irag — CLI Reference#
Project resolution is directory-wise: every command operates on the nearest ancestor directory (including the current one) that contains .irag. An enclosing git repository is never adopted as the project — a versioned home/Desktop directory can't silently become one. Projects nest and multiply; whichever .irag is nearest to where you run the command is the one you operate on. All commands except init require prior initialization and print a friendly error otherwise. Exit code is 0 on success; check uses 1 to signal a failed gate. irag --version prints the installed version.
irag init#
Initialize the directory you run it in as a project: create .irag/memory.db and .irag/config.toml (defaults, only if absent), and ingest what's there. When the directory is a git repo's top level, git hooks are installed (never clobbering a foreign hook) and history is ingested. When it sits inside a larger git repository, init prints a scoping note and runs in snapshot mode — the enclosing repo is not touched and gets no hooks; git init the project itself any time to upgrade it to commit-based ingestion.
irag sync#
Catch up on changes. In git mode: all commits since the last synced hash (idempotent; survives rebases via full re-scan). In snapshot mode (no git at the project root, or [ingest].mode = "snapshot"): diffs content fingerprints of the working tree — adds, edits, and deletions each become events, no commit required. auto (default) picks git only when the project root is a git repository's top level; a project scoped to a subdirectory of a larger repo always snapshots (git's paths are toplevel-relative and would not match the project's subjects).
sync only detects changes (queues events) — it never writes a new page version. If it queued anything, it prints a reminder to run irag update, which is the composite command that actually synthesizes.
irag ingest-commit REF#
Ingest a single commit (what the git hook runs with HEAD). One queued event per touched module; staleness bumped per config. Idempotent on (commit, module).
irag synthesize [--dry-run] [--limit N] [--subject S]#
Update pending pages via the configured LLM.
--dry-run— print the exact prompt(s) instead of calling the LLM--limit N— process at most N pages (highest staleness first)--subject S— force one subject (e.g.src/auth), pending or not
Synthesis is hierarchical and two-phase: pending FILE pages first (each file summarized from its own capped content + structural facts), then FOLDER pages bottom-up (each folder summarized from its direct children's summaries), ending at the root. A page is pending when not pinned and (never synthesized with queued events, or staleness ≥ threshold); file changes bump their file page fully and every ancestor folder at half weight, so summaries cascade upward. Before sweeping, previously failed events (e.g. from a misconfigured LLM command) and events stuck in 'processing' for over 10 minutes (interrupted runs) are automatically requeued — fixing the config and re-running synthesize always recovers. When nothing is pending, the message explains why (no pages, empty queue, or below-threshold staleness with the current score shown).
irag context [--open FILE ...] [--query Q]#
Serve tiered, budget-gated context markdown: warnings, FULL bodies, DIGEST summaries, INDEX lines. When the working tree has uncommitted changes (excluding irag's own artifacts) a note is prepended, since pages and map reflect the last commit. --json emits the machine dict. --open is repeatable and boosts the matching module (+50), its relatives (+25), and its dependency neighbors from the structural map (+20). Each FULL page carries a compact map block (files, symbols, imports/importers). --budget N overrides the token budget (used by the Claude Code hook).
irag search QUERY#
Full-text search (FTS5) over all revision bodies; current revisions surface first, with snippets.
irag lint [--subject S] [--llm]#
Static checks of current page bodies against ground truth: backticked paths must exist on disk (missing_path, high), version claims must match package.json / requirements.txt (version_mismatch, medium), backticked identifiers() must be defined in the module directory (missing_symbol, low, heuristic). Identical open claims are deduped, and static contradictions that no longer reproduce (page revised, file restored, version corrected) are auto-resolved with a note — so irag check goes green again without manual cleanup. --llm additionally runs the LLM audit tier (llm_flagged); LLM-flagged rows are never auto-resolved.
irag contradictions [--resolved]#
List open (default) or resolved contradictions with id, subject, type, severity, claim, and truth.
irag contradiction-report [ID] [--output FILE]#
Write a self-contained HTML repair packet for one contradiction or, with no ID, one master packet containing every open contradiction. It includes the memory claim, observed truth, detector, severity, current page, verified structural context, a completion gate, and a ready-to-copy prompt for any coding agent. The dashboard exposes the same report beside every row and as a master button.
irag resolve ID [--notes TEXT] [--undo] [--id KEY]#
Dismiss a contradiction as a false positive. This marks the check wrong — it does not edit the page. A summary that really does say something untrue keeps saying it; that is fixed by irag update, which rewrites the page from current code and clears the flag on its own.
Dismissal is permanent for that exact claim on that page: re-synthesis will not raise it again, which is what stops a false positive returning under a new id forever. Because it is permanent, dismissing a genuine error silences it for good with the wrong text still in place — so --undo reopens one dismissed by mistake.
Auto-resolved contradictions (the claim simply stopped failing) are never suppressed: if such a claim starts failing again that is a real regression, and it is raised.
irag forget PATH [--purge]#
Drop a page from live memory — it stops being served by search, context and folder rollups, while its history stays queryable by asof and why. --purge deletes the page and every revision permanently.
A file that is deleted from disk is withdrawn automatically: the next sync marks its page, and re-adding the path restores it. Since a rename is a delete plus an add, this is what stops every rename leaving behind a page for a file that no longer exists. Use forget for the cases irag cannot infer — a path that moved out of the project, a folder that will not return.
Do not reach for irag resolve here. That dismisses the contradiction permanently while leaving the page live and served, which is worse than doing nothing.
irag stale#
Show every page's staleness score, pinned flag, and whether it is due for synthesis.
irag why CLAIM#
Trace a claim: best-matching revision (page, version, date, model) and the event chain that produced it (commit hash, message, files) — or "human/rollback".
irag asof DATE [--show SUBJECT]#
Print the wiki state as of an ISO date (each page's latest revision at that time); a bare YYYY-MM-DD is inclusive of that entire day. --show prints one subject's full body as of that date.
irag rollback SUBJECT VERSION#
Non-destructive rollback: inserts the old body as a new revision (change_summary = "rollback to vN") via a rollback event. No history is rewritten.
irag pin SUBJECT / irag unpin SUBJECT#
Pinned pages are skipped by synthesis (hand-curated content stays put).
irag export#
(Re)install CLAUDE.md and AGENTS.md — irag's static operator manual (bundled with the package), identical content, at the repo root. irag init already installs them; run this to restore them if deleted. The latter is the cross-tool convention read by Codex, Antigravity, and other non-Claude agents. A CLAUDE.md you wrote yourself is never clobbered — irag only overwrites files it installed. These files carry instructions, not memory: irag update never rewrites them.
irag obsidian [--out DIR] [--no-versions]#
Project the database into an Obsidian vault (default <repo>/irag_vault). The vault is a disposable build artifact: wiped and rebuilt every run (guarded by a .irag-vault marker — irag refuses to delete a folder it did not create; close the vault in Obsidian before regenerating).
Contents: Modules/ — one note per page with YAML frontmatter (version, staleness, confidence, tags), open contradictions as [!warning] callouts, parent/child + explicit wikilinks, and history links; _versions/ — one note per revision, tagged #version, chained prev/next, carrying trigger provenance (commit hash/message, rollback, decision); _meta/ — stats.md, contradictions.md, graph_settings.md (color groups + the -tag:#version toggle trick); README.md index. --no-versions omits the history nodes.
irag update [--limit N] [--dry-run] [--id KEY]#
The one-shot pipeline and the standard agent trigger: sync (detect changes) → scan (rebuild the structural map) → synthesize (new page versions for everything affected, file pages then folder rollups) → lint (fact-check). It does not export the agent guide. Updates the memory database only; the CLAUDE.md/AGENTS.md agent guide (installed by irag init) instructs agents to run this after finishing edits, so page versions advance with every change automatically.
--dry-run reports how many pages would be synthesized and roughly what it would cost, without calling the model or writing anything — use it to state the size before spending.
Exits 1 when a page holds a queued change it can never act on (a "stuck" page). That state is self-contradictory and cannot self-heal, so it is reported loudly rather than folded into a successful-looking run.
An edit that changes only comments or whitespace skips the model entirely. Naming a page with synthesize --subject is an explicit force and always rewrites it.
irag ask QUESTION [--open FILE] [--budget N]#
AI search. Retrieval assembles ranked, budgeted context for the question (same engine as irag context), then the configured LLM answers using ONLY that context — citing page paths, flagging contradicted pages as unreliable, and saying what's missing (with the right irag command to find it) instead of guessing. Complement of irag search, which is the SQL side: instant FTS5 full-text lookup, zero tokens.
irag scan#
Force-rebuild the structural map (symbols + dependency edges). Automatic refreshes parse only content-changed files when the set of code paths is unchanged; adds, deletes, and renames trigger a full pass so newly resolvable imports cannot be missed. It runs on init, sync, context, map, and impact whenever the working-tree fingerprint has changed, so uncommitted edits are included and you rarely need it by hand. Pure parsing — Python via ast; JS/TS, Go, Rust, Java, C#, Ruby, PHP, and C/C++ via regex; zero LLM tokens; capped at 300KB per file / 4000 files. Import edges resolve for languages with file-relative imports (JS/TS, Python, Ruby require_relative, C/C++ #include "...", relative PHP includes); Java and C# contribute symbols but not edges (their imports are package paths, which need source roots irag doesn't track).
irag map [SUBJECT]#
Without a subject: the repo overview — every module with its symbol count, plus all import edges. With a subject: that module's files, every symbol with kind and file:line, what it imports, and what imports it. This is the pre-computed map the agent reads instead of grepping.
irag impact SUBJECT#
Transitive reverse dependencies with hop distance: everything that could break if the module changes. "Nothing imports X — change is contained" when it's a leaf.
irag learn TEXT [--module M] [--id KEY]#
Log a lesson/gotcha discovered while working (deterministic, no LLM). Lands on the lessons page, which — like decisions — is boosted so it appears in every context serve. This is how session knowledge survives: the agent (or you) records it explicitly, and it is never lost to a compaction.
irag claude-setup#
Wire irag into Claude Code for this repo (merge-safe, idempotent) with two hooks in .claude/settings.json: SessionStart runs irag context --budget 3000 — stdout is injected as session context, so every session starts already knowing the project — and Stop runs irag update --limit 50 (10-min timeout) when Claude finishes a turn, so changed files are synthesized into new page versions mechanically, with zero reliance on the agent remembering to do it; it is a no-op when nothing changed. Also (re)installs the CLAUDE.md/AGENTS.md agent guide if missing — the operator manual that teaches agents to use irag map/impact/ search/why instead of exploring, and to log with irag learn/ irag record-decision.
irag session-begin [--task LABEL] / irag session-end [--no-narrate] [--transcript FILE]#
The conversation logger (called automatically by the Claude Code hooks; usable by any agent or human). session-begin opens a diary entry and records ID high-water marks plus the optional task label, branch, worktree, and starting commit; a still-open previous session (crashed terminal) is closed as interrupted first. session-end closes the entry and logs exactly what that conversation did — files changed, page versions written, decisions and lessons recorded, commit messages — plus an LLM-written 2-5 sentence narrative (deterministic digest if the LLM is unavailable or --no-narrate). It also records, redundantly with revisions (cheap to duplicate, expensive to join every time), the exact per-file change_summary for every page version written that session — this is changes_detail in --json output.
When [sessions].capture_transcript = true (off by default — transcripts can contain secrets), session-end also stores the verbatim conversation. Claude Code pipes the transcript path in on stdin automatically; other agents pass --transcript <file.jsonl>. Read it back with irag transcript.
irag transcript SESSION_ID [--json]#
Print the stored verbatim messages (your prompts + the agent's replies, tool calls noted as [tool: Name]) for a logged session. Empty unless [sessions].capture_transcript was on when the session closed. Internal reasoning and raw tool output are never stored.
irag sessions [-n N] [--json]#
The project diary: every conversation with when it ran, its status (closed/interrupted), change counts, and its summary. --json includes changes_detail — the full list of {subject_id, version_number, change_summary} for that session, so you can see exactly what changed without joining revisions yourself.
irag recap [-n N]#
"Previously on this project" — the last sessions' summaries as markdown. This is the fresh-start command: close every terminal, come back next week, open a brand-new chat, and the agent already knows what happened — it is also injected automatically at the top of irag context and the SessionStart hook, so a new conversation costs ~zero tokens to resume instead of thousands to re-explore.
irag dashboard [--port N] [--no-open]#
Local web dashboard on 127.0.0.1 (stdlib server, zero deps). Tabs: Overview — live cards (token burn, page versions, contradictions, queue) refreshing every 3s, a cumulative token-burn chart, a live activity feed of revisions/events, a "Run irag update" button with streaming progress, and validated controls for changing the summary model and web-search provider without editing TOML. Main Summary — the complete body of every current memory page together with currentness, project status, contradictions, recent session evidence, and latest audit state; structural truth refreshes automatically, with an explained Memory Trust score. Code Audit — the same deterministic report as irag audit, filterable by severity/category, with source coverage, API inventory, OSV state, dependency cycles, recommendations, and a live checker restricted to discovered, current loopback read routes. Findings retain review status, required rationale, optional acceptance expiry, and can export as SARIF 2.1.0. App Proof — one evidence-first application test surface for static frontend/backend contract matching, loopback page crawling, links, controls, forms, safe API execution, optional Playwright, configured project suites, and explicitly confirmed bounded read-only stress. Profiles and results persist; each behavior stays proven, failed, blocked, untested, or excluded and complete runs open as self-contained coding-agent repair briefs. Thinking Studio — a persistent code-review/product/business/ marketing/creative conversation beside a durable recommendation board and experiment ledger; optional live research and explicitly refreshed watchlists display source URLs, provider, retrieval time, and what changed. Chat — chat with the knowledge base; each message is auto-routed like the original DBS project: keyword/path/symbol lookups → instant SQL search (green badge), natural-language questions → AI answer with citations (purple badge); a keyword miss falls through to AI, and a selector can force either mode; a typing indicator shows while a request is in flight. Pages — the memory browser: filter every file and folder page, read its rendered summary, walk its full version history and diff any version against the previous one, see its blast radius, pin or unpin it, and roll back to an older version (with an inline confirmation — the rollback is non-destructive, as always). The same tab logs knowledge (irag learn / irag record-decision) and traces a claim back to the revision and commit that created it (irag why). Health — open contradictions with one-click resolve, staleness table, click any page to read its current body. Visualize — the codebase as a 3D force-directed graph built from the same symbol and dependency tables map queries: nodes are files (sized by symbol count, coloured by top-level folder), edges are real imports. Drag to orbit, scroll to zoom, click a file to inspect what it defines, what it imports, what depends on it, and everything irag has written about it; the map is re-read every few seconds so new files appear without a refresh. Delivery — turns a validated Git diff (or snapshot-mode drift) into changed paths, transitive blast radius, contract removals, risk, related tests, repository-native verification gates, release readiness, and a copyable agent brief. It can export/import bounded reviewable team memory without copying source, transcripts, prompts, or executable facts. Below that, What your agent sees renders the exact irag context briefing with its token count and tier breakdown; Time travel runs asof for any date; Operations runs sync, scan, lint, check, export, obsidian, claude-setup, backup, and doctor (a strict server-side allowlist of Python callables — the dashboard never builds a shell command from a request). Map — an interactive, Obsidian-style dependency graph (drag to pan, scroll to zoom, drag nodes, hover to trace imports) above the files/symbols and import-edge tables. Sessions — the conversation log: click a session to see its full summary, the exact per-file changes it made (changes_detail), and the verbatim transcript when [sessions].capture_transcript is on. Docs — the full documentation rendered in-app (Quickstart, Setup, Architecture, CLI reference, Comparison).
The main memory, audit, web-search, contradiction, provider, and update paths are also available through CLI or MCP. Dashboard-only composition (the Studio conversation and idea board) still persists in the same SQLite database rather than browser storage.
Updates receive durable job IDs. Progress and ordered logs are stored in SQLite and streamed to the browser with Server-Sent Events, so refreshes and reconnects resume the same operation instead of resetting a process-local spinner.
irag mcp [--root PATH]#
Start the vendor-neutral Model Context Protocol server over stdio. It negotiates stable MCP versions, publishes JSON Schema tools, returns text plus structured results, and never writes logs to protocol stdout. --root should be absolute when launched by a coding client. See MCP.md.
irag audit [--offline] [--json]#
Run the deterministic defensive audit over the current repository. It scans bounded text/code files for security-sensitive patterns, Python syntax and quality risks, very large files, dependency cycles, and discovered API routes. Exact versions found in supported lock/manifests can be queried against OSV; --offline skips that network lookup. --json returns the complete report.
Every finding includes rule, severity, category, file, line, redacted evidence, remediation, and confidence. Heuristics are review leads, not proof of an exploitable vulnerability. The command deliberately exits 0 when it found review items; irag check remains the strict memory-integrity gate.
irag proof [--mode quick|full|stress] [OPTIONS]#
Run App Proof against a local full-stack application. The runner refreshes the repository and a local, offline Code Audit first, then combines static contract evidence with actual loopback HTTP behavior.
--base-url URL— localhost or a loopback IP only; public/staging/production targets are rejected--health-path PATH— readiness endpoint, default/; only HTTP 2xx is ready--start-command CMD— start the app before probing; parsed into an argument vector and executed without a shell--test-command CMD— project-owned verification command; repeat up to ten times. Full/Stress only, no shell, 300-second limit each--auth-env NAME— environment variable holding the exactAuthorizationheader. The value is used in memory and never stored--request-timeout SECONDS,--start-timeout SECONDS— per-request timeout (1–30 seconds) and readiness wait (1–120 seconds)--no-browser,--interact,--external-links— control optional browser evidence, explicitly enabled safe control interaction, and public link checks--max-pages,--max-controls— bound discovery; excess coverage becomes a visible blocked check--stress-requests,--stress-concurrency,--confirm-stress— bounded GET load settings. Stress mode refuses to start without the confirmation flag--report FILE— write the escaped, self-contained HTML evidence/repair packet;--jsonprints the complete machine result--strict— exit 1 when any behavior remains blocked or untested. Without it, deterministic failures exit 1 and incomplete-but-failure-free coverage exits 0
Quick runs contracts, pages, links, forms/controls inventory, and safe read routes; browser and project journeys stay explicitly untested. Full adds Playwright and configured test commands. The runner uses project-local Node Playwright or the Python Playwright package available to iRAG's interpreter. Stress adds at most 1,000 GET requests across at most ten loopback routes with at most 32 workers. HTTP probes never follow redirects; browser navigation stays on the configured origin. Form submissions, mutating API methods, parameterized routes, and destructive-looking controls require a project-owned test instead of an automatic click.
A click with no observed text or navigation change remains untested. A visible change without errors proves that interaction occurred; only your assertions establish whether its result is correct. Unknown route methods, dynamic URLs, missing query fixtures, and unsupported static routing remain blocked. Coverage is the fraction of discovered checks executed, not a claim that every possible application state or business rule has been tested.
irag web-search QUERY [--json]#
Search the live web without asking an LLM. Results include title, URL, snippet, domain, any provider-supplied publication date, provider name, and retrieval time. The provider comes from [web]: auto, Brave, Tavily, SearXNG, or the keyless DuckDuckGo fallback. Brave and Tavily credentials are read only from BRAVE_SEARCH_API_KEY and TAVILY_API_KEY. --json emits the complete source records used by the Thinking Studio and irag_web_search MCP tool.
irag provider [--json]#
Show the selected summary-provider adapter, effective model, timeout/retry policy, and whether its executable is available. This check makes no model call; use doctor --probe-llm when an actual output probe is wanted.
irag status [--json]#
One-screen dashboard: pages/revisions, symbols/dep edges, queue depth and failures, open contradictions, pages due, estimated LLM tokens spent, uncommitted changes, db size, sync/scan heads. --json for tooling and benchmarks.
It also reports the live change-detection mode (hybrid, git or snapshot) and, separately from pages due, any files whose mtime is newer than the page written for them. pages due is computed from the database, so edits made since the last sync are not counted in it — treat either signal as "run update". In snapshot mode "uncommitted changes" reads n/a, because git status there would describe an enclosing repo rather than the project.
irag diff SUBJECT [V1] [V2]#
Unified diff between two revisions of a page (default: previous vs current) — review exactly what a synthesis pass changed before trusting it.
irag backup [PATH]#
Online, lock-safe snapshot of the database via SQLite's backup API (default .irag/backups/memory-<timestamp>.db).
irag doctor [--probe-llm]#
Full install diagnosis with PASS/WARN/FAIL per check: git presence, database and FTS integrity, config keys and types, LLM command on PATH (--probe-llm invokes it once), all three git hooks, scan freshness, stuck/failed queue events, Claude Code hook wiring. Exit 1 on any FAIL — suitable for CI.
irag check [--skip-facts]#
The CI gate. Prints open contradictions, pages over max_staleness, and never-synthesized pages. Exits 1 if open contradictions exist (when fail_on_contradictions = true) or any page exceeds max_staleness.
It can also re-run executable facts (see irag verify), but only when you opt in with [check].fail_on_facts = true. That default is false on purpose: facts are shell commands stored in .irag/memory.db, and that database is meant to be committed — so running them automatically would mean git clone && irag check executes whatever commands the repo carries. When enabled, every command is printed before it runs.
Of the three fact outcomes, only one gates the build:
| outcome | meaning | gates? |
|---|---|---|
pass | the command ran and the expectation held | no |
fail | it ran and the expectation did not hold | yes |
error | it could not run here (tool missing, timeout) | no — reported only |
error is deliberately not a failure: a machine without nmap says nothing about whether a claim about nmap is true.
irag record-decision TEXT [--module M] [--id KEY]#
Log a decision deterministically (no LLM): inserts a decision event and appends a line to the decisions page as a new revision. Like lessons, decisions are boosted into every context serve.
irag tried APPROACH --because WHY [--module M] [--id KEY]#
Record a dead end — an approach that was attempted and did not work, with the mechanism that defeated it. What you ruled out is worth as much as what worked, and without somewhere to put it the next session pays full price to rediscover the same failure. Surfaced by irag brief as "already ruled out" so it arrives before someone tries it again.
irag tried "position:sticky for the toolbar" \
--because "it only catches after you scroll past it" --module ui/bar.cssirag verify [CLAIM --cmd CMD] [--expect TEXT] [--expect-exit N] [--module M] [--timeout S] [--id KEY]#
Executable memory: a claim that carries its own proof. Every other layer describes what the code says; this records what it does — the facts you can only learn by running something, together with the command that demonstrates them.
irag verify "scan aborts entirely without root, it does not degrade" \
--cmd "python3 -m scanner --probe" --expect "QUITTING" --module scanner.pyWith a claim and --cmd, the fact is recorded and run immediately. With no arguments, every recorded fact is re-run. Exits non-zero if any fact fails.
--expect TEXT— this substring must appear in stdout+stderr.--expect-exit N— the command must exit with this code.- Give both and both must hold. Give neither and the command must exit 0.
- A command containing shell operators (
|,&&,>, globs …) is run through a shell, so pipelines work as written. Operators inside quotes are data, not syntax.
Facts are re-run by irag check only when [check].fail_on_facts = true — see that command for why it is opt-in.
irag facts#
List every recorded fact with its last verification status, without running anything.
irag topic [NAME] [--files A,B,C] [--replace] [--list] [--id KEY]#
A page for a concept rather than a file. Knowledge is often feature-shaped while storage is file-shaped: "how does root privilege affect scanning?" spans a scanner, a helper and a template that share no folder, so no folder page can answer it. Members are curated by hand — the one page type irag will not infer.
irag topic "root privilege" --files src/scanner.py,src/net.py,ui/index.html
irag update # writes the page
irag topic "root privilege" # read it back
irag topic --listirag brief PATH [--limit N] [--quiet]#
Everything known about one file, in a few lines: disputed claims, verified behaviour, dead ends, gotchas lifted from the page itself, and who imports it. Small enough to inject on every edit.
Session-start context is just-in-case; by turn 40 it has scrolled away. claude-setup wires this to PreToolUse so it arrives at the moment a file is about to be edited. Pass - as the path to read the file from a hook payload on stdin.
irag suggest [--limit N]#
What needs doing right now, each with the command that does it — drifted files, stuck pages, contradictions, broken behavioural claims, unsynthesized pages. A flat command index is not discovery; this surfaces the right command at the moment it applies.
irag capture [--command C] [--exit-code N] [--output T] [--module M] [--quiet] [--id KEY]#
Draft a candidate lesson from a command that failed. Anything relying on an agent volunteering knowledge gets skipped under load, so the draft is written from the strongest available signal that something surprising happened. claude-setup wires this to PostToolUse on Bash; it reads the tool call from stdin and does nothing when the command succeeded.
irag candidates [--limit N] [--discard ID] [--clear]#
List unconfirmed drafts, promote the useful ones with irag learn, and throw the rest away with --discard ID or --clear.