chant search
Synopsis
Section titled “Synopsis”chant search "<query>" [--live | --at <ref>] [--env <name>] [flags]Description
Section titled “Description”chant search answers a question about your estate with a compact result
instead of the whole graph. Each match prints as one line — logical id, kind,
physical id when known, and any attributes you asked for. Tens of tokens, not
thousands.
That compactness is the point. An agent asking “which instances sit in public
subnets” should not ingest a multi-thousand-token IR dump and join
instance -> subnet -> route table by hand — it should run one query and read a few
rows. chant search is the query surface the
agent integration leans on, and it is what
kept chant’s token footprint the lowest of any tooling configuration on
aws-bench, an infrastructure-agent
benchmark.
By default the query runs over the declared graph (source only, offline).
With --live --env <name> chant observes the environment, overlays live
identity and attributes onto the declared graph, and answers from that — same
canvas as chant graph --overlay.
Query grammar
Section titled “Query grammar”Space-separated terms. All terms must match (AND). Quote phrases to keep them together.
| Term | Matches |
|---|---|
word | case-insensitive substring over id, kind, and attribute values |
kind:<substr> | node kind contains <substr> (e.g. kind:EC2::Instance) |
attr:<name> | attribute <name> is present |
attr:<name>=<val> | attribute <name> equals/contains <val> |
tag:<key>=<val> | a Tags entry with Key=<key> and Value containing <val> |
->kind:X, ->attr:…, ->tag:… | node has an edge to a node matching the right side |
<-kind:X, <-attr:…, <-tag:… | node has an edge from a node matching the right side |
The edge operators make the search edge-aware: a traversal becomes one term instead of a hand-join across results.
# instances that reference a public subnetchant search "kind:Instance ->attr:MapPublicIpOnLaunch=true"Derived attributes
Section titled “Derived attributes”Before matching, chant folds derived reachability facts onto instance nodes (effective-topology enrichment), so multi-hop and launch-template joins become one node predicate:
internetFacing— the instance’s subnet routes to an internet gateway (resolved across the account default VPC in live mode)effectiveIngress— normalized ingress rules from all reachable security groups, attached directly or via the instance’s launch template
chant search "kind:EC2::Instance attr:internetFacing=true" --live --env devchant search "kind:EC2::Instance attr:internetFacing=true attr:effectiveIngress=tcp:22:0.0.0.0/0" --live --env dev --explain --show InstanceId| Flag | Type | Default | Description |
|---|---|---|---|
--live | boolean | false | Query live state overlaid on the declared graph (requires --env) |
--at | string | — | Answer from a recorded snapshot instead of reading the estate now (latest; requires --env; mutually exclusive with --live) |
--env | string | — | Environment to observe (must be in chant.config environments when declared) |
--src | string | config sourceDir or . | Source directory to discover/build |
--show | string | — | Comma-separated attribute names to append to each result row |
--explain | boolean | false | Print the match-universe footer and near-miss exclusions |
--ambient | boolean | false | Also report resources of a managed kind that exist without being declared or referenced |
--check-live | boolean | false | With --at: additionally read the estate live and diff the matched rows against the snapshot the answer came from |
--check-snapshot | boolean | false | With --live: additionally diff the matched rows against the most recently recorded snapshot |
--fail-on-drift | boolean | false | With --check-live/--check-snapshot: exit non-zero when the scoped check finds drift |
--explain
Section titled “--explain”The footer gives a small model a reason to trust the result instead of re-deriving it with a lossy CLI sweep:
- the universe count —
4 of 6 EC2::Instance matched, a denominator the typed graph knows and a live sweep does not - inclusion evidence for derived facts — e.g.
✓ web1 internet-facing via subnet route - up to 8 near-misses with the query term each one fails
— 2 of 6 EC2::Instance matched (query: kind:EC2::Instance attr:internetFacing=true) ✓ BastionUsEast1 internet-facing via default-vpc · excluded AppUsWest2 — fails attr:internetFacing=trueEverything in the footer is a property of the query over the graph, not of any expected answer.
Live mode
Section titled “Live mode”--live builds the project first (a failing build stops the search), observes
owned resources in the environment, and overlays live identity onto the
declared graph — the declared side carries the topology so ->/<- resolve,
the live side supplies physical ids and live-only attributes.
Multi-stack projects are observed per stack, and results display the bare logical id without the stack qualifier.
Every answer ends with a provenance line saying what backed it: declared only,
observed live · bound N/M, or observed from snapshot. A live read that fails
(unreachable endpoint, denied credentials) is reported as a failure rather than
an empty estate. Each row the read could not cover prints (unobserved: read-failed) where its physical id would go, stderr names the lexicon and the
underlying error, the footer reads live read failed (<lexicon>) · N/M rows unobserved, and the command exits 1. Derived attributes that fold over live
topology are not advertised in that case, since nothing was read to compute
them. The rows printed are what the source declares, labelled as such; answer
from a recorded snapshot with --at latest or drop --live for a declared-only
query.
Query-scoped drift
Section titled “Query-scoped drift”--check-live and --check-snapshot compare the matched rows — and only the
matched rows — against the observation the primary answer did not use. Where
lifecycle diff --live asks “has anything changed anywhere”, this asks “is
what I was just told still true”, about the resources in front of you, in the
same command that produced them.
$ chant search "kind:EC2::Instance" --env prod --at latest --check-livewebServer AWS::EC2::Instance i-e392157f576caf855launchTemplateServer AWS::EC2::Instance i-ee2744528df10ea0d⚠ webServer attributes.SubnetId: subnet-2faec80b → subnet-9f01ab3c — drifted— checked against a live read · 1 of 2 matched driftedThe reverse framing answers live and checks the record for staleness:
chant search "kind:EC2::Instance" --env prod --live --check-snapshotBoth reuse diffLive — the exact function lifecycle diff --live calls —
scoped to the matched entity ids, so the categories and what counts as drift
are identical: missing/orphan/disappeared/drifted are drift,
newlyObserved and runtime children are reported but are not, and
unobserved (a read that could not look) stays distinct from both. A resource
the query scoped out is a fourth thing again — never reported as missing or
unobserved, because it was never asked about.
--check-live requires --at; --check-snapshot requires --live — each
checks the answer against the source it did not already use. --fail-on-drift
exits non-zero when the check finds drift, so it is usable as a CI gate; a
missing snapshot for --check-snapshot is a note on stderr, not a failure —
the live answer already stands. A snapshot recorded with chant lifecycle snapshot <env> --deep compares here at identity depth regardless, and the
footer says so, rather than reporting every property the identity-depth side
never recorded as drift.
# offline, over the declared graphchant search "kind:Bucket"chant search "tag:Environment=prod"
# live estate questionschant search "kind:EC2::Instance attr:internetFacing=true" --live --env devchant search "kind:Instance ->attr:MapPublicIpOnLaunch=true" --live --env dev --explain
# query-scoped driftchant search "kind:EC2::Instance" --env prod --at latest --check-livechant search "kind:EC2::Instance" --env prod --live --check-snapshot --fail-on-driftExit Codes
Section titled “Exit Codes”| Code | Meaning |
|---|---|
| 0 | Query ran (including zero matches — prints (no matches)), including a scoped check that found drift without --fail-on-drift |
| 1 | Missing query, missing/unknown --env, build failure in --live mode, a --live/--check-live read that failed for at least one lexicon (rows are printed, marked unobserved), --check-live/--check-snapshot used without its required flag, --fail-on-drift used without either, or --fail-on-drift with drift found |