Reading the graph
The colours
Section titled “The colours”| colour | means | reads as |
|---|---|---|
| green | managed | chant declared it and the estate confirms it |
| amber | foreign | it is there, chant did not put it there |
| blue | pending | declared, not yet observed as deployed |
| grey | neutral | nothing deployed for this component yet |
A node behold could not read is unobserved, reported as a hole and never painted as absent. “I did not look” and “it is gone” are different claims, and conflating them is how a viewer talks someone into deleting something.
Health and rotation
Section titled “Health and rotation”Drift says whether the account matches the source. Health says whether a declared thing is serving, and behold draws it apart from the colours above. With an environment picked and chant 0.124.33 or newer, behold reads chant lifecycle health <env> for each chant project (each member of a workspace) and marks every card that has a health read: a Route 53 health check, an ECS service, a Container App and a Cloud Run service.
| mark under the card | means |
|---|---|
| green healthy | the provider says it is serving |
| red unhealthy, with a solid red ring | the provider says it is not |
| grey health unknown | the read worked and the answer decides neither way, such as a service scaled to zero or a rollout in progress |
| health not read: <reason>, with a dashed grey ring | chant could not read it (read-failed, no-credentials, no-binding, unsupported-kind) |
| grey not deployed | the provider says it is not there |
A health check chant could not read is a hole, the same as an unobserved card, and is never drawn as unhealthy. The card’s fill stays the drift colour, so a health check can be managed and unhealthy at once.
Rotation is derived from the graph. A Route 53 record whose HealthCheckId names a declared health check is out of rotation while that check is unhealthy: the record and its edges are dimmed and its line reads out of rotation: azureCheck unhealthy. A healthy check puts the record in rotation. When the check is unknown, not read or not deployed, the record’s line says its rotation is unknown and nothing is dimmed, since behold does not guess. Routing beyond that, such as failover pairs or alias targets, is not modelled.
The Model tab counts each state under the drift legend and lists the records out of rotation. Clicking a card shows the provider’s detail line, when it was checked and when chant read it, and for a health check, the records it guards. The health is read once per environment and kept for 30 seconds; “Re-check live” reads it again. Agents read the same answer from GET /api/health?env=<env>.
The zoom dial
Section titled “The zoom dial”From widest to narrowest:
- Components. The deploy units and the waves they go out in.
- Logical. An architecture diagram in the shape the substrate actually has. AWS nests
region → VPC → subnet; Azure nests under the resource group; GCP isproject → location, with no network containment, because the emulated GCP surface has no VPC to draw. - Composites. The higher-level constructs your source declares.
- Resources. Individual resources at their real provider names.
- Attributes. The properties on one resource.
On Kubernetes there is one tier further down, below anything you declared:
Runtime. The Pods, ReplicaSets and EndpointSlices the cluster created and maintains through ownerReferences. They are runtime children rather than drift: nothing declared them and nothing should. This tier is why a healthy-looking Deployment in front of a dead Service is visible rather than green.
Field ownership, on Kubernetes
Section titled “Field ownership, on Kubernetes”The API server records, per field, which manager last wrote it. chant compiled the manifest, so it knows which fields it authored. Put together, the inspect pane can say these fields are chant’s, spec.replicas is the HPA’s, and someone edited the image by hand.
Foreign-owned is shown as a distinct state from drifted. A field the HPA legitimately owns is not a problem, and colouring it like drift would recreate the noise that per-field ownership exists to remove.
Cross-substrate edges
Section titled “Cross-substrate edges”An estate that spans providers keeps its edges: a managed cluster declared in your cloud lexicon and the workload running on it render connected, in the live view and not only in the source graph.
Pipeline boxes
Section titled “Pipeline boxes”A project that declares CI (the github, forgejo or gitlab lexicon, chant 0.124.20 or later) draws each workflow or pipeline as a box holding the workflow and its jobs. The box takes the workflow’s name: when it has one (CI Pipeline), and the entity’s key otherwise. A reusable-workflow call runs between two boxes.
Pipeline boxes appear on a project’s resources view, alone or in an estate. In an estate (behold serve a b, or a declared workspace) each member’s box holds its pipeline boxes, one level down, titled the same way without the member name the box around them already shows (release, not api/release). A pipeline goes in the member box that holds most of its cards. When the member boxes are packed into rows, or a wide member’s cards are laid out again, each pipeline box is drawn again around where its cards ended up, so it stays inside its member box and clear of the others.
The composites level has no pipeline boxes, because chant leaves pipeline membership off at detail 1 (chant#3921). When a graph carries deploy waves as well, the wave boxes are drawn instead.
CI edges
Section titled “CI edges”A GitHub Actions, Forgejo or GitLab project draws its edges by the kind chant gives them (chant 0.124.20 or newer). A needs edge is a heavier solid line, calls and triggers have their own colours, and includes and extends are dotted. An edge that leaves its own workflow or pipeline, such as a call to a reusable workflow or a workflow_run trigger, is dashed. The chip on the edge says the kind, with the attribute when that adds something (needs (stage), calls (uses)), as chant’s Mermaid output does, and hovering the edge says what the kind means. The Model tab lists the kinds the graph holds, with a count for each.
Two nodes can be joined by more than one kind, such as a GitLab job that both needs and extends another. Each kind is its own edge, drawn as its own line a little apart from the other, with its own chip, tooltip and highlight.
What was deployed, from where
Section titled “What was deployed, from where”Three cards carry provenance beside their status, so “is this what we meant to deploy” has an answer on the card rather than in a CI log.
- A component that the release ledger recorded shows
<sha> via <forge>, the commit and the id space of the run that deployed it. The inspect pane’s release section carries the run id, commit, digest, actor and approver. The run is a link only when the record itself carries an address (chant ≥ 0.54); a bare id from an older chant is stated as unlinked rather than guessed at. - A Helm chart whose observed release records its render identity (chant ≥ 0.54) gets a deployed from row in the render-diff section: the release was deployed from this project’s render byte for byte, from the same inputs, or from something else. A mismatch repaints the card the drift colour, since a release running someone else’s render is bad news whatever its status. A release no ledger record names reads as unrecorded rather than as a mismatch.
- A chant entity carved out of Terraform carries
carved: <address>and acarved → chantmark on the entity graph and the overlay: the carve manifest names the file it emitted,chant graphnames the file that declared the entity, and the join is a byte comparison. The inspect pane’s carved from section gives the Terraform address, stage and estate.
Ops that touch the estate
Section titled “Ops that touch the estate”On the ops lens, a step whose contract declares which of its arguments identify an estate entity (httpCheck and its url, chant ≥ 0.54) links to the card it touches: the card is drawn beside the track in an estate box with a dashed edge from the step, and the pane lists the value on both ends. The join is exact: a node id, or a declared attribute value equal to the step’s. A value nothing carries stays on the step as unresolved rather than guessed.