Skip to content
RunConcepts

Runtime concepts

The model behind everything in this tab: how a System’s declared shape becomes Kubernetes workloads, and why the topology never decides what a Port resolves to. Read this page before the Deploy section; every page there assumes it.

The build side ends with a System host: the .NET project that declares which Components exist, which Resources join them, and which Ports and Services sit at the System’s edges (The system host). The host’s graph verb prints that declaration as interchange JSON of kind SystemTopology (topology.intropy.io/v1). This document is the contract between the two halves of Intropy: the deployment tooling consumes it, and nothing else from the source tree.

{
"apiVersion": "topology.intropy.io/v1",
"kind": "SystemTopology",
"system": "order-flow",
"pubsubs": [{ "name": "order-flow-pubsub", "role": "bus" }],
"components": [
{
"name": "order-extractor",
"kind": "extractor",
"publishes": [{ "pubsub": "order-flow-pubsub", "topic": "orders", "message": "order-placed" }],
"ports": [{ "port": "order-extractor-source", "direction": "in" }],
"uses": ["idempotency-service", "business-incident-service"]
}
]
}

intropy manifests inspect derives the deployment model from that topology plus the scaffold records each component carries in .intropy/scaffold.json. Every component maps to a workload kind: extractors run as CronJobs (wake, pull, publish, exit), while loaders and other Components run as long-lived Deployments. Each workload gets a Dapr sidecar through pod annotations, and the System’s Topic and Port Resources materialize as Dapr components:

components
order-extractor extractor cronjob
order-loader loader deployment
ports
order-extractor-source external system not declared
order-loader-destination external system not declared

Note what the port rows do not say. The topology names a port; it never decides what the name resolves to. The adapter’s binding type, address, and credentials are environment-owned deployment configuration, which is why the same System runs against drop folders on a laptop and SFTP endpoints in production without a rebuild. See intropy manifests for the command surface.

The runtime is built on Dapr. Every workload runs with a Dapr sidecar, and Component code talks only to its own sidecar — never to a broker, endpoint, or credential directly. Three Dapr building blocks carry the model’s names:

Model term Dapr building block What the environment decides
Topic Pub/sub Which broker the name resolves to (Redis locally, your broker in production).
Port Binding The adapter type, address, and credentials for the external system.
Service Service invocation Where the platform service runs and how calls reach it.

This is the build/connect/deploy split at runtime: the Component knows names, the sidecar configuration — rendered per environment — knows what they resolve to. What Dapr is and how its building blocks work in general is documented at dapr.io; this section covers only what the runtime uses. Why the binding is deferred at all is explained on Dapr in the build tab.