Contributing a Lifecycle
chant’s product is the synthesis core: pure, deterministic, lint-gated TypeScript-to-spec compilation. Everything past synthesis — state, apply, drift, reconcile, retire — is the lifecycle, and it is a bolt-on, not the core. The shape of the project is:
Pluggable lexicons in. Pluggable lifecycles out. Pure synthesis in the middle.
Lexicons are the established pluggable axis. This page is about the other one: how you bring your own lifecycle. There are two doors.
Door 1 — Write a lifecycle as Ops
Section titled “Door 1 — Write a lifecycle as Ops”The first door ships today. A lifecycle is just orchestration over chant’s primitives, and you declare orchestration as Ops in *.op.ts files — named, phased workflows that run on the local executor or, when you need durability, on Temporal.
The built-in lifecycle composites are themselves nothing more than Ops you could have written:
WatchOp— observe: snapshot + live diff on a schedule.ReconcileOp—cloud → code: open PRs when live drifts from source.ApplyOp—code → cloud: apply via the target’s native mechanism, with owned-only deletes.
To contribute a lifecycle this way, compose the primitives your workflow needs:
chant lifecycle plan <env>— the typed change set against live (CLI).chant import --from <env>— regenerate TypeScript from live state (Live Import).- The pre-built Op activities (
lifecycleSnapshot,lifecycleDiff,reconcilePr,nativeApply,compensateApply) plus your own. - Gate steps and
onFailurecompensation when the workflow must survive a crash or hold a human approval.
Package a reusable one as a composite that returns an Op (and optionally a TemporalSchedule), exactly as the built-ins do — see lexicons/temporal/src/composites/ for reference. That is a complete, shippable lifecycle.
Door 2 — Plug an existing lifecycle in
Section titled “Door 2 — Plug an existing lifecycle in”The second door is the direction, not a finished feature. The architecture is pluggable: the seams a foreign lifecycle would attach to already exist —
- Per-lexicon live access —
describeResources()(scrubbed observation) andexportResources()(full-fidelity export) give a lifecycle a typed view of live infrastructure without a hosted state file. - Ownership markers — provider-native tags/labels (ownership marking) let any lifecycle answer “is this mine?” from the resource itself.
- A runtime boundary — the Op executor’s local-vs-Temporal split is a clean interface between declaring a workflow and running it durably.
The intended end state is that a vendor’s whole product becomes one plugin under chant’s pure synthesis — you don’t rip out Terraform, you plug it in as a lifecycle backend, and chant owns the socket.
Why two doors, not one
Section titled “Why two doors, not one”The two doors close the gap BYOL could otherwise open. “Bring your own lifecycle” must never read as “you’re on your own”: Door 1 gives you durable rails to build on today (chant makes it durable), and Door 2 means an existing investment isn’t thrown away — it’s plugged in. Own the socket, outlast the lifecycle war.
See also
Section titled “See also”lifecycle-reconcile-awsexample — a Door 1 lifecycle (ReconcileOp + ApplyOp) wired to a real stack- Lifecycle Models — the three axes and the observe → reconcile → authoritative dial
- Ops — declaring orchestration in
*.op.ts - Durable Workflows — when a lifecycle wants Temporal
- Lexicon Authoring — the other pluggable axis