Skip to content

Philosophy

Infrastructure tools give you syntax — YAML schemas, HCL blocks, SDK constructors. What they don’t give you is semantics: whether what you declared actually makes sense in context. That’s the gap chant closes.

A deterministic core as the foundation, the lifecycle you choose built on it, and the agents and operators that act on it A deterministic core as the foundation, the lifecycle you choose built on it, and the agents and operators that act on it
The deterministic core and the lifecycle built on it

Lexicons are collections of types and semantic lint rules for an operational area. A lexicon knows what resources exist in its domain and can validate whether your declarations are coherent — not just structurally correct, but semantically meaningful.

Synthesis takes typed TypeScript declarations in and produces validated artifacts out. You write TypeScript objects, chant resolves dependencies, and serializes to the target format.

chant is a compiler at its core. TypeScript in, spec-native output out. This isn’t a new idea — it’s an approach that was always available. Nobody built it because the industry was racing to weld one lifecycle to the compiler: state management, deployment, drift detection, rollback, owned end to end. chant keeps the compiler deterministic and lets the lifecycle be yours — built on top of that core, not fused into it.

Most IaC tools that use general-purpose languages — CDK, Pulumi, Terraform’s CDK — work by executing your code. Your program runs, makes API calls, and the tool captures the result.

The build runs only synthesis. It imports your .ts files, reads the resource objects they export, and emits output. It never calls a cloud API, reads or writes state, or deploys. Your TypeScript declares intent. The build turns that intent into an artifact — deterministically, with no side effects. Deploying that artifact is the lifecycle’s job, one layer up.

Synthesis does run your code. It runs only a constrained slice of it. The evaluability lint rules (EVL) reject anything that would make a resource depend on more than literals, constants, and cross-resource references. No function calls in props. No control flow around resources. With those rules satisfied, running the file is equivalent to reading static data. That constraint is the point. Because synthesis is side-effect-free and deterministic for conforming source:

  • Evaluation is deterministic for code that passes the evaluability rules. Same source, same output. No API calls during synthesis.
  • Analysis is a single pass over the imported modules. Type-checking and linting are separate commands.
  • Output is auditable — every value traces to a literal, a const binding, or a cross-resource reference.
  • IDEs work fully — types drive the API surface, so autocompletion, inline errors, and go-to-definition come for free.

The static evaluation constraint also makes chant a natural complement to agentic workflows. Agents handle the dynamic, operational layer — deploying, monitoring, remediating. chant handles the part that should be deterministic and auditable. The two layers don’t compete; they compose.

Each lexicon is faithful to its target spec. The AWS lexicon generates from the CloudFormation resource specification. The GitLab lexicon maps to .gitlab-ci.yml schema. Chant doesn’t invent an abstraction layer across specs — it gives you the real API surface, typed and linted.

This means walk-away cost is zero. The output is standard CloudFormation, standard GitLab CI, standard whatever-the-lexicon-targets. If you stop using chant, the artifacts keep working. There’s nothing chant-specific in the output.

chant build produces artifacts — it doesn’t deploy them, call cloud APIs, or manage state. Synthesis is pure and deterministic: same source in, same output out, zero side effects. That boundary is deliberate. Deployment, drift, and reconciliation live one layer up, in the lifecycle you choose (Lifecycle Models) — kept separate so the build path stays a small, side-effect-free thing to audit, with no provider SDKs, state backend, or network at build time; see Owning less.

The lifecycle above the build runs either way you want it: as chant’s own durable Ops, or handed off to agents, CI pipelines, and platform tooling. The core’s job is to make synthesis typed, linted, and deterministic — then carry that trust up into deploy, observe, and reconcile, or hand a native artifact to any mechanism that consumes it.

Anything with a schema is a potential lexicon target. chant doesn’t replace your cloud tooling. It’s a semantic layer on top of it. You can import existing templates, give them types, and lint them alongside everything else.

chant’s architecture is layered: a deterministic synthesis core as the foundation, with the lifecycle you choose built on top of it. The core never changes — chant build is deterministic and side-effect-free — and each lifecycle layer adds operational reach without touching the build pipeline.

The lifecycle spans declarative deployment workflows (Op — phased Temporal workflows declared in *.op.ts files, run via chant run), continuous observation (WatchOp — periodic snapshot+diff scheduled via Temporal), the observational lifecycle model (chant lifecycle — non-authoritative snapshots; see Drift Detection), a release model (Components — releasable units composed from a bounded capability set and run by a generated Op), and agentic skills for import and drift detection. They share a principle: the deterministic core provides context and structure that the durable layers, agents, and operators act on with the same auditability underneath.

The lifecycle is opt-in per environment. Use none of it and chant is a deterministic compiler you hand off from; use all of it and chant deploys, observes, and reconciles — the same core underneath either way.