Skip to content

chant query

llms.txt lists every page for an agent
chant query "<sql>" [dir] [--member <name>] [--json]

chant query loads the local chant/lifecycle branch into an in-memory SQLite database and runs one statement over it (#4297). The inventory comes from the snapshots each lexicon’s describeResources wrote, so it works for every lexicon.

$ chant query "SELECT env, lexicon, count(*) AS n FROM resources GROUP BY env, lexicon"
env lexicon n
---- ------- --
prod aws 14
prod k8s 6
(2 rows)

Only a statement that begins with SELECT, WITH or VALUES runs, and the database takes PRAGMA query_only, so nothing is written (packages/core/src/lifecycle/query.ts:270 and :285). It reads the local branch and never fetches. Run git fetch origin chant/lifecycle:chant/lifecycle first to query what CI recorded.

Inside a workspace the command reads every member’s ledger and each row names its member, as packages/core/src/cli/handlers/query.ts:44 sets it. Outside a workspace it reads the project’s own ledger and leaves member NULL. The engine is the SQLite built into Node from version 22.13, node:sqlite.

Every table starts with member. A column marked JSON holds JSON text for json_extract, and a column is TEXT unless it is marked INTEGER.

TableOne row perColumns
resourcesresource in an environment’s snapshotenv, stack, lexicon, name, type, physical_id, status, last_updated, ownership, attributes (JSON), git_sha, observed_at
snapshotssnapshot file, <env>/<lexicon>.json or <env>/<stack>__<lexicon>.jsonenv, stack, lexicon, git_sha, observed_at, depth, resources (INTEGER), unobserved (INTEGER)
runsOp run record, <env>/runs__<op>.jsonlid, op, env, started, ended, status, git_sha, forge, run_url, failure_code, failure_reason, failed_phase, gate, steward, labels (JSON), outcomes (JSON)
gatesgate ledger line, _gates/<op>.jsonlop, gate, kind (pending or resolution), timestamp, resolved_by, relayed_by, approver_kind, plan_digest, environment, release_digest, git_sha, run_id, url, note, expires_at, origin, empty (INTEGER), signed (INTEGER)
deploysdeploy record, <env>/releases.jsonlenv, component, digest, git_sha, run_id, forge, run_url, timestamp, actor, approver, release_digest, digest_kind, promoted_from (JSON), restores (JSON), redeploys (JSON)
releasesrelease file, _releases/<digest>.jsonrelease_digest, release_member, git_sha, envs (comma list), artifacts (JSON)
cutsline of _releases/cuts.jsonlrelease_digest, label, actor, timestamp, run_id, forge, channel, signed (INTEGER), composed_base
chant_schemacolumn of every table aboveversion (INTEGER), table_name, column_name, type, position (INTEGER)

The columns are listed in QUERY_TABLES (packages/core/src/lifecycle/query.ts:49).

The tables are a contract at version 1 (QUERY_SCHEMA_VERSION, packages/core/src/lifecycle/query.ts:39). A column can be added within a version. Renaming or removing one, or changing what it holds, makes a new version. chant_schema carries the version on every row, and --json prints it as schemaVersion, so a saved query can check what it runs against:

chant query "SELECT DISTINCT version FROM chant_schema"

Each ledger is parsed by the reader its own commands use, and a line or file that is not its kind is left out and counted. The text output warns with the counts on stderr, and --json prints them under malformed. A release file whose content does not hash to its digest counts as malformed, as readAllReleases counts it (packages/core/src/lifecycle/query.ts:223). Other JSON files beside the snapshots, such as the observation baseline, are skipped (packages/core/src/lifecycle/query.ts:175).

OptionMeaning
"<sql>"The statement, quoted as one argument.
dirWhere to read from. The default is the current directory.
--member <name>Only this member. Repeat it, or give a comma list, for several.
--jsonPrint { schemaVersion, columns, rows, tables, malformed }. tables counts each table’s rows.
CodeMeaning
0The statement ran.
1No statement, a statement that writes or does not parse, a --member that names no member, or a Node with no node:sqlite.

chant