chant graph
Synopsis
Section titled “Synopsis”chant graph [path] [--stacks] [--json]chant graph [path] [--components] [--json]chant graph [path] --format ir|mermaid|dot|layout [--detail 0..3] [--lens <kind>:<target>] [--up] [--down]chant graph [path] --format layout [--node-sizes <json|-|@file>] [--layout-engine dagre|graphviz]chant graph --format ir --live --env <name>chant graph --format ir --live --env <name> --overlayDescription
Section titled “Description”chant graph has four modes:
- default — the Op dependency graph (edges from each Op’s
dependsfield). --stacks— the cross-stack apply-ordering graph.--components— the component dependency graph, from each discovered component’sdependsOn.--format ir|mermaid|dot|layout— the infrastructure graph chant resolves during synthesis, emitted for diagrams. This is the graph of your declared resources and the references between them.
The infra-graph formats are a pure function of lint-clean source — every node traces to a source file, every edge is a real cross-resource reference. They are lint-gated: chant refuses to emit a graph for source that does not pass chant lint, because the graph represents valid infrastructure.
--live — the provisioned graph
Section titled “--live — the provisioned graph”--format ir --live --env <name> emits the graph of what’s actually deployed in that environment, not what source declares. It queries each lexicon’s live observation (describeResources) for the chant-managed resources and projects them into the same IR. Nodes carry their observed physicalId and ownership marker.
chant graph --format ir --live --env prod # the provisioned resources as IREdges are reconstructed from the live references: observed resources point at each other by physical id (a subnet’s VpcId, an ALB listener’s TargetGroupArn), and each lexicon ships a reference catalog that turns those into graph edges (peer references) and containment (subnet ∈ VPC). A reference whose target isn’t in the observed set is reported as dangling, never a wrong edge.
Scope today is managed-only — resources carrying chant’s ownership marker; it isn’t a full-account scan. Unlike the source graph, --live is not lint-gated (it reads the cloud, not source).
Edge reconstruction is only as rich as the observed node attributes. AWS’s plain describe-stack-resources metadata is too thin, so the AWS lexicon enriches from the deployed CloudFormation template (its {Ref}/{Fn::GetAtt} references, resolved to node ids) before reconstruction — so a managed AWS stack produces its topology. A lexicon without that enrichment yields nodes with fewer edges.
--overlay — declared vs provisioned
Section titled “--overlay — declared vs provisioned”--live --overlay also reads your declared source and classifies every resource, tagging each node so a renderer colours the drift:
- managed — declared and provisioned
- foreign — provisioned but not declared (in the cloud, not in your source)
- pending — declared but not yet provisioned (appended to the graph)
chant graph --format ir --live --env prod --overlay--overlay-anchor <source|live> — which graph is the canvas
Section titled “--overlay-anchor <source|live> — which graph is the canvas”The overlay merges two graphs; the anchor decides which one’s edges survive.
source(default) — the declared graph is the canvas, so its edges are kept. This matters because cross-substrate edges (an ECS service wired to a k8s workload) are a source-graph property: live edges are reconstructed per-substrate by identifier match and never cross providers, so the mixed topology exists only in the declared graph. Each declared node is taggedmanagedorpendingand carries the observedphysicalId/ownership; foreign resources are appended with any live edges that touch them.live— the provisioned graph is the canvas, keeping its reconstructed live edges (the original behaviour). Use it when the provisioned graph itself is the subject and per-substrate islands are acceptable.
chant graph --format ir --live --env prod --overlay # source-anchored (keeps cross-substrate edges)chant graph --format ir --live --env prod --overlay --overlay-anchor live # provisioned graph's own edgesInfra graph: --format
Section titled “Infra graph: --format”chant graph ./infra --format mermaid # paste-able Mermaid flowchart (renders in GitHub)chant graph ./infra --format ir # the graph IR as JSON (the contract for tools)chant graph ./infra --format dot # Graphviz DOT (render with `dot -Tsvg`)chant graph ./infra --format layout # node positions (dagre by default — no native dep)| Format | Output | Needs |
|---|---|---|
mermaid | A Mermaid flowchart with one subgraph per lexicon. The zero-install default — renders in GitHub, docs, and browsers. | nothing |
ir | The graph IR as JSON: nodes (id, kind, lexicon, attrs, sourceLoc, composite info), edges (real references, labelled with the consumer property), and groups. The stable contract downstream diagram tools consume. | nothing |
dot | Graphviz DOT text, with lexicon clusters and labelled edges. Render directly with dot -Tsvg, or feed to a layout engine. | nothing to produce; dot to render |
layout | Node positions for a custom painter that does its own drawing: { width, height, nodes: [{id, x, y, w, h}] } (y-up, origin bottom-left). | nothing (dagre); dot only with --layout-engine graphviz |
--format layout: size-aware positions
Section titled “--format layout: size-aware positions”The layout step exists for custom painters (the pinhole diagrammer is one): chant computes positions, the painter draws. By default it uses dagre — a pure-JS engine, so --format layout needs no native dependency.
A painter draws nodes at a real size (cards, icons, labels), so it can pass those footprints in and get spacing that fits them — no node overlap:
# {id: {w, h}} in layout units (≈ px). Inline, or '-' for stdin, or '@file.json'.chant graph ./infra --format layout --node-sizes '{"vpc":{"w":180,"h":68}, ...}'echo "$SIZES" | chant graph ./infra --format layout --node-sizes -Without --node-sizes, nodes fall back to a default box (the layout still works, but a painter with larger nodes may need to space them itself).
To use Graphviz for layout instead of dagre (e.g. to match dot’s routing), pass --layout-engine graphviz — this is the only path that needs dot (brew install graphviz), and it honours lexicon clusters.
Detail tiers: --detail 0..3
Section titled “Detail tiers: --detail 0..3”The detail dial controls how much of the graph each format shows. It is a transform over the same IR, so it works with every --format.
| Level | Name | Shows |
|---|---|---|
0 | stacks | one node per lexicon; edges are cross-lexicon dependencies |
1 | composites | each composite instance collapsed to a single node |
2 | declarables | every resource (the default) |
3 | attributes | declarables, plus the referenced attribute on each edge |
chant graph ./infra --format mermaid --detail 0 # high-level: lexicons onlychant graph ./infra --format mermaid --detail 1 # composites as single nodeschant graph ./infra --format ir --detail 3 # every resource + attribute-level edgesA handful of composites at --detail 2 expands to every resource they declare — you describe a few, the graph shows the whole set. Turn the dial down to 0/1 for an overview.
Lenses: --lens <kind>:<target>
Section titled “Lenses: --lens <kind>:<target>”Lenses focus the graph on a slice. They compose with --detail (the lens is applied first, then the detail tier).
| Lens | Keeps |
|---|---|
lexicon:<name> | only that lexicon’s nodes |
stack:<name> | only one stack’s nodes (stacks map to lexicon partitions today) |
blast:<node> | the transitive neighbourhood of a node |
For blast:, choose a direction (default is both):
--up— what the node depends on (its producers)--down— what depends on the node (its dependents)
chant graph ./infra --format mermaid --lens lexicon:gcpchant graph ./infra --format mermaid --lens blast:vpc --down # everything that depends on the VPCA lens drops edges that would dangle and rebuilds group metadata, so the result is always a self-consistent graph. An unknown or no-match target exits non-zero with a clear message.
--stacks — cross-stack apply order
Section titled “--stacks — cross-stack apply order”chant graph --stacks [path] renders the cross-stack apply-ordering graph instead. chant resolves cross-lexicon references during build and already knows the order — a stack that exports a value must apply before the stack that imports it. --stacks surfaces that as tool-agnostic data for your orchestrator. chant exposes the order; it does not drive the apply.
chant graph --stacks ./infrachant graph --stacks ./infra --jsonThe output is the stacks, their dependency edges (consumer → producer), a topological apply order, and waves — levels whose stacks have no inter-dependency and may apply concurrently. --json emits the full graph (nodes, edges, order, waves, cycles). A dependency cycle is reported and exits non-zero.
Apply order (waves apply top-to-bottom; a wave's stacks are parallel-safe): 1. aws 2. k8s
Dependencies (consumer → producer): k8s → aws--components — component dependency order
Section titled “--components — component dependency order”chant graph --components [path] renders the component dependency graph: every *.component.ts declaration under path, ordered by dependsOn. Unlike --stacks (which infers edges from cross-lexicon attribute references), a component’s dependency is always an explicit name in its own dependsOn list, so no reference inference is needed — the same dependsOn the interpret driver uses to order a real run.
chant graph --components ./infrachant graph --components ./infra --jsonThe output is the same shape as --stacks: a topological order, waves (components with no inter-dependency, safe to run concurrently), and dependency edges (consumer → producer). --json emits the full result. A dependency cycle, or a dependsOn naming an undiscovered component, is reported and exits non-zero.
Deploy order (waves apply top-to-bottom; a wave's components are parallel-safe): 1. shared-alb, orders-table 2. search-service
Dependencies (consumer → producer): search-service → shared-albOp graph (default)
Section titled “Op graph (default)”With no format flag, chant graph discovers all *.op.ts files under the given path and prints the dependency edges declared via each Op’s depends field.
chant graph # Ops in the current directorychant graph ./infra # Ops in a specific directoryEach dependency prints as one edge per line, <dependency> → <dependent> — the left Op must complete before the right Op can run. If no Ops declare dependencies the output is No Op dependencies; if no *.op.ts files are found, No Ops found.
Exit Codes
Section titled “Exit Codes”| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Discovery errors; lint errors (infra-graph formats); a dependency cycle (--stacks, --components) or unknown dependency (--components); an invalid --detail/--lens; malformed --node-sizes; or a layout-engine failure (e.g. missing dot with --layout-engine graphviz) |
See Also
Section titled “See Also”- Ops guide — define Op dependencies with
depends chant lint— the gate the infra-graph formats run firstchant build— synthesize the artifacts the graph describes