atif-sql · CLI
Section titled “atif-sql · CLI”The atif-sql console script (packages/atif-cli/pyproject.toml:42) is the repo’s public contract: one cyclopts router (packages/atif-cli/src/atif_cli/app.py:52) dispatches the ten subcommands below, and a root-level --version resolves the installed atif-sql distribution (:60).
Three conventions hold across every subcommand. --format takes auto, table, json, or csv from the OutputFormat StrEnum at packages/atif-cli/src/atif_cli/output.py:58, and auto resolves to table when stdout is a TTY and json otherwise (packages/atif-cli/src/atif_cli/output.py:74). Exit codes come from one table, EXIT_CODES at packages/atif-cli/src/atif_cli/errors.py:28: 0 ok, 2 empty-session / no-embeddings, 64 invalid input or SQL parse error, 65 catalog error / validation error / embedding mismatch, 70 runtime error, 78 terminal state or suspicious scan, 127 harbor missing. A number in that table is a wire contract: keys may be added, never renumbered. And stderr carries WARNING and above only, so a piped read emits data on stdout and nothing on stderr unless something is wrong; ATIF_SQL_LOG_LEVEL widens it (INFO, DEBUG) and is the only way to reach the INFO surface, because the entry point replaces loguru’s default handler and with it the LOGURU_LEVEL that would have parameterized it (packages/atif-cli/src/atif_cli/app.py:1141-1148).
analyze, embed, and search call Amazon Bedrock and spend money; the other seven are offline.
convert
Section titled “convert”atif-sql convert [OPTIONS] SESSION-JSONLConvert one Claude Code session JSONL to ATIF plus a loss report and edges.
packages/atif-cli/src/atif_cli/app.py:226
Flags:
SESSION-JSONL/--session-jsonl— required path to the session transcript,~/.claude/projects/<proj>/<session>.jsonl.:226--include-subagents/--no-subagents— stage<session>/subagents/**.jsonlside-files alongside the main chain; defaultTrue, with the negative form named explicitly.:228--trajectory-out— write the trajectory JSON here andedges.jsonlbeside it, instead of stdout.:229
Exit codes: 0 ok, 2 empty session, 64 invalid input, 65 validation, 70 conversion, 127 the pinned private harbor method is gone. :250
materialize
Section titled “materialize”atif-sql materialize [OPTIONS]Sync the materialized corpus with the raw transcript corpus in one scan-plan-convert-write pass.
packages/atif-cli/src/atif_cli/app.py:352
Flags:
--force/--no-force— re-materialize every quiescent session regardless of the watermark; defaultFalse.:341--quiesce-seconds— source-silence threshold; defaults from settings (contract: 300).:342--source-root— override the raw transcript root, otherwiseATIF_SQL_SOURCE_ROOTor<CLAUDE_CONFIG_DIR>/projects.:343--corpus-root— override the materialized corpus root, otherwise env or~/.atif-sql/corpus/<slug>.:344--sessions— comma-separated session-id filter; only these sessions are planned this pass.:345--format— report format.:346
Exit codes: 0 ok, 78 suspicious scan — the source scan found zero sessions while the corpus holds materialized ones, so ghost removal was refused and nothing was deleted. Check --source-root; a retry over the same root cannot succeed. packages/atif-cli/src/atif_cli/app.py:429-443
status
Section titled “status”atif-sql status [OPTIONS]Report corpus freshness: watermark age, counts, bytes, staleness.
packages/atif-cli/src/atif_cli/app.py:444
Flags:
--source-root— override the raw transcript root.:414--corpus-root— override the materialized corpus root.:415--quiesce-seconds— source-silence threshold used to replaymaterialize’s planning decision.:416--format— report format.:417
Both roots resolve through _corpus_settings (:433), so a --source-root given without --corpus-root re-derives the corpus root from the overridden source’s slug unless ATIF_SQL_CORPUS_ROOT is set (:206).
atif-sql query [OPTIONS] [ARGS]Run one SQL statement against the atif-duck catalog and emit results.
packages/atif-cli/src/atif_cli/app.py:529
Flags:
SQL— positional-only statement; omitting it without--examplesis a parse error.:498--examples— short-circuit to theexampleslisting, honoring--categoryand--requires, without opening DuckDB.:501--category— forwarded to theexampleslisting.:502--requires— forwarded to theexampleslisting.:503--corpus-root— override the materialized corpus root.:504--format—tableon a TTY, a JSON array of row objects on a pipe.:505
The statement runs against a hardened connection: reads reach the registered views and nothing else, and the only writable path is the query engine’s own spill directory <corpus_root>/.duckdb_tmp. :601
Exit codes: 64 parse error, 65 catalog error, 65 embedding mismatch, 70 runtime error. :550
analyze
Section titled “analyze”atif-sql analyze [OPTIONS]Run the analytics pipelines — cluster, terms, community, plus the LLM classify, trajectory, conflicts, friction, and perceived stages.
packages/atif-cli/src/atif_cli/app.py:659
Flags:
--since-days— restrict LLM stages to sessions whose last step is within N days; default30, and structural stages always run over the full store.:629--limit— cap the number of sessions, newest-first, per LLM stage.:630--max-sessions— hard per-run session ceiling per LLM pipeline; overridesATIF_SQL_LLM_MAX_SESSIONS_PER_RUN, default 50.:631--max-cost-usd— hard per-run dollar ceiling across all LLM pipelines, checked against running actual usage; overridesATIF_SQL_LLM_MAX_COST_USD_PER_RUN, default 25.0.:632--no-dry-run— execute the LLM stages for real, which costs money; the default is a dry run emitting plan dicts and cost estimates.:633--structural-only— run only cluster, terms, and community, the hourly cron lane that fires at minute 17.:634--llm-only— run only classify, trajectory, conflicts, friction, and perceived, the nightly lane.:635--skip-cluster— opt out of the cluster stage.:636--skip-terms— opt out of the terms stage.:637--skip-community— opt out of the community stage.:638--skip-classify— opt out of the classify stage.:639--skip-trajectory— opt out of the trajectory stage.:640--skip-conflicts— opt out of the conflicts stage.:641--skip-friction— opt out of the friction stage.:642--skip-perceived— opt out of the perceived stage.:643--force-cluster— recompute clustering even when the mtime sidecar says the input is unchanged.:644--force-community— recompute community detection even when the mtime sidecar says the input is unchanged.:645--corpus-root— override the materialized corpus root.:646--format— summary format.:647
atif-sql embed [OPTIONS]Embed unembedded corpus steps with Cohere Embed v4 and append them to LanceDB.
packages/atif-cli/src/atif_cli/app.py:766
Flags:
--limit— cap the number of steps embedded this run.:736--all— explicitly embed every unembedded step, a full backfill.:737--dry-run— preview only; emit the plan JSON with keyspipeline, candidates, batches, batch_size, concurrency, model, limit, dry_runand make no embedding calls.:738--corpus-root— override the materialized corpus root.:739--format— output format.:740
A real run requires an explicit scope: a bare atif-sql embed exits 64 with a hint rather than starting an unbounded backfill. :778
Exit codes: 0 success, 64 missing --limit or --all, 70 runtime (Bedrock, DuckDB, or Lance failure — transient, safe to retry), 78 terminal state, where the store or its config needs operator action and unattended lanes suppress retries. :767
search
Section titled “search”atif-sql search [OPTIONS] QUERY_TEXTSemantic top-k nearest-neighbor search over step embeddings.
packages/atif-cli/src/atif_cli/app.py:860
Flags:
QUERY_TEXT— required positional-only text, embedded with Cohere Embed v4 insearch_querymode.:829-k/--k— top-k; default10. This is the CLI’s only short flag.:832--session-id— confine the kNN to one session.:833--corpus-root— override the materialized corpus root.:834--format— output format.:835
Output columns are uuid, session_id, snippet, and sim (:927), ranked by cosine distance ascending so the highest similarity comes first (:935).
Exit codes: 0 success, 2 no embeddings yet, 65 embedding mismatch when the store was written by another provider, 70 runtime. :864
examples
Section titled “examples”atif-sql examples [OPTIONS]List tested example queries for every view and macro, derived from the static atif-duck catalog.
packages/atif-cli/src/atif_cli/app.py:995
Flags:
--category— filter to one ofview,table-macro,scalar-macro, validated againstCATEGORY_VALUES.:965--requires— filter to one ofcore,analytics,vss, validated againstREQUIRES_VALUES.:966--format— a TTY table grouped byrequires, or a JSON object carryingnoteandexamples.:967
Both value sets are Literal aliases in the producer package: Requires at packages/atif-duck/src/atif_duck/domain/examples.py:48 and Category at :53, exported as tuples at :55 and :56.
Exit codes: 0 ok, 64 unknown --category or --requires value. packages/atif-cli/src/atif_cli/app.py:1020
schema
Section titled “schema”atif-sql schema [OPTIONS]List every registered view with its columns and every macro signature.
packages/atif-cli/src/atif_cli/app.py:1087
Flags:
--format— a TTY listing, or a JSON object carryingviews,macros, andexamples_hint.:1057
The answer comes from the static VIEW_SCHEMA and MACRO_SIGNATURES dicts with no DuckDB import and no view registration. :1067
atif-sql cron COMMANDInspect and manually install the atif-sql refresh cron lanes.
packages/atif-cli/src/atif_cli/cron.py:38
The group is attached to the root router by app.command(cron_app) at packages/atif-cli/src/atif_cli/app.py:66, and its three lanes — materialize on */10 * * * *, structural on 17 * * * *, llm on 20 10 * * * — are declared once in LANES at packages/atif-cli/src/atif_cli/cron.py:47.
cron install
Section titled “cron install”atif-sql cron install [OPTIONS]Print the crontab block for the three refresh lanes and never write it.
packages/atif-cli/src/atif_cli/cron.py:180
Flags:
--script— path toatif-sql-refresh.sh.packages/atif-cli/src/atif_cli/cron.py:180
Without the flag the script is located by walking up from this module (:147); a tree where scripts/atif-sql-refresh.sh is unreachable exits 64 demanding --script (:175).
cron status
Section titled “cron status”atif-sql cron status [OPTIONS]Report each lane’s lock holder plus the last run and skip parsed from the refresh log.
packages/atif-cli/src/atif_cli/cron.py:199
Flags:
--script— path toatif-sql-refresh.sh, whose.run/sibling holds the locks and the log.packages/atif-cli/src/atif_cli/cron.py:201--tail— how many trailing log lines to include;0disables, default10.:202--format— human lines on a TTY, JSON on a pipe.:203
The lock probe acquires and releases nonblocking, so the command perturbs no running lane. :127
See also
Section titled “See also”- processes — 7 shared source citations
- module map — 6 shared source citations
- debugging guide — 6 shared source citations
- dead code — 5 shared source citations
- impact analysis — 5 shared source citations