state-resolver
Turns an intent into the desired-state graph: it defines the intent data, derives the needs, fills each from a catalog of concrete tools, and emits every resource node the deployment requires.
flowchart LR
sdk["sdk<br/>i.have · i.want"] -- "IntentSet" --> needs["intent/<br/>resolveNeeds"]
needs --> state(["state-resolver<br/>resolveState"])
catalog["catalogFor<br/>Forgejo · GitHub · GitLab stack"] --> state
state -- "emit → ResolvedNode[]" --> compile["graph<br/>compile"]
compile --> artifact["DesiredStateGraph"]
src/intentis the intent the SDK records, as plain data: one*Intenttype per declaration kind and the author's*Inputshapes. Handles become resource-id strings, so anIntentSetserializes and carries no SDK types.resolveNeedsmaps the intent to abstract needs before any tool is chosen. ANeedis one capability at one scope:source-control,docker-registryandinfra-controlon the control-plane host (the first declared host with apps,controlPlaneHostId),deployment-targeton every host that runs something, anddomainon the Cloudflare account. It validates the intent as a whole: apps without Cloudflare, targets on undeclared hosts and workspace tools naming undeclared services all throw there.- The catalog follows the intent:
i.have.githubselects the GitHub stack,i.have.gitlabthe GitLab stack, otherwise self-hosted Forgejo. In all three, Komodo deploys and a Cloudflare tunnel exposes the apps. - Each need must map to exactly one catalog option. Zero or several options throw; the resolver makes no choices.
src/resolversholds one resolver per concern: the control plane, apps, routes, backings with per-app bindings, catalog services, agent workspaces, users and teams, and scheduled backups.- Every derived id and platform domain comes from
src/lib/ids.ts. The SDK imports the same functions, so a handle's ids match the graph's. - It is pure. The Cloudflare
zonearrives as an argument; the CLI discovers it before calling.
Key files
- src/state.ts —
resolveState: needs, catalog assignment, emit, compile. - src/intent/needs.ts —
resolveNeeds,Capability,Planeand the control-plane host rule. - src/emit/emit.ts — builds the nodes for one assignment, host by host.
- src/lib/catalog.ts — the three stacks and which capabilities each option provides.
- src/lib/ids.ts — every derived resource id and platform domain.
- src/resolvers/app.ts — what one app becomes: repo, CI per environment, deployment, route.
Commands
pnpm --filter @intentic/state-resolver test