--- name: chi description: Archis's method for answering questions about this repository from its pre-built semantic index instead of reading files. Use when exploring an unfamiliar codebase, locating a symbol, finding who calls what, judging the blast radius of a change, checking whether exact text appears anywhere, or planning an edit — and whenever the next step would otherwise be Read, Grep or Glob to find out what a repository contains. Covers the batching rules that make Archis cheap, Archis's session memory, and the `chi` CLI fallback when the MCP server is not connected. metadata: version: "0.36.3" source: "https://archis.dev/skill.md" published_from: "chi 0.36.3" --- # Archis — ask the repository, do not read it Archis keeps a pre-built semantic index of this repository: every symbol, its kind, its signature, its line span, its imports, and who calls whom. Asking it a question costs a fraction of what finding the same answer by reading files costs, and it is already built — the server indexes on its first call and refreshes itself as files change. This skill is the method. The tool descriptions say what each call *is*; what follows is the order to make them in, and what to do when the answer is not where you first looked. ## First, is Archis here? Run `chi status`. If there is no `chi` on this machine, install it — one line, no root, no package manager: ``` curl -fsSL https://archis.dev/install.sh | sh ``` Then, once: ``` chi auth login # activates this machine — Archis Free, no card chi agents on # claude, cursor, … `chi agents` lists what it found here chi init # index this repository, and write the briefing and this skill ``` `chi agents` prints every harness on this machine and whether Archis reached it, and `chi agents check ` verifies one end to end. If Archis's tools are still not in your tool list after that, say so rather than working around it: the tools are the product, and `chi context ""` is this same first pass from the shell while they are missing. The rest of what is here, for the questions that are not about code: `chi dashboard` opens the local dashboard (loopback only, never published), `chi measure` says what a file costs against its projection, `chi tools` shrinks what other commands print, `chi session report` says what a session read and saved, and `chi telemetry preview` prints the exact analytics payload — `chi telemetry off` stops it. Every command, flag and default: https://archis.dev/docs/cli, or https://archis.dev/docs/cli.md and https://archis.dev/docs/commands.json for the same reference as markdown and JSON. ## The one rule everything else follows from **A turn is the unit of cost, not a token.** Every tool call ends a turn, and every turn re-sends the entire conversation *and* buys a fresh reasoning block. Ten calls in ten messages cost ten times what ten calls in one message cost, for identical information. So: **independent calls go in the same message**, and **never loop a singular form when a plural exists**. `get_files(paths=[a, b, c])` is one turn; three `get_file` calls are three. This is the difference the whole product is built around, and it is the one thing a model reliably gets wrong unprompted. ## Start here: one call, not four ``` chi_context(task="", intent="understand") ``` This is the first call for anything you do not already have coordinates for. It runs, inside the server, the passes you would otherwise spend a turn each on: rank the repository against your task, outline the files it lands in, project the symbols that matter, and scan for any literal your task quoted. One package, one turn. Measured on five real questions about this repository, the hand-made version of that sequence costs three to five turns and 24,000–43,000 input tokens; the single call costs 10,000–11,000 and answers the same questions. The saving is not that the package is smaller — it is that the announce and the growing conversation are not re-sent three more times. **Name the intent.** It is an allocation, not a hint, and it changes what the package is made of: | `intent` | What you get | |---|---| | `understand` | outlines and projections, breadth, no bytes | | `debug` | the same, plus a scan of the whole index for every literal your task quoted | | `edit` | narrow, and exact: the target's source, its `content_hash`, its callers, the signatures it must keep honouring, its tests | | `test` | what covers this, and where a new test would go | | `review` | breadth, and who calls what | **Quote what you saw.** For `debug`, put the error text, the log line or the config key in quotes inside `task`. Quoted strings are scanned across every indexed file — and if one is *not* there, you are told that too, which means it is assembled from a format string and no whole-string search will ever find it. **Read `confidence`.** High means the ranking found one clear answer and the package was deliberately narrowed to it. Low means the field was flat: `files` is then the part to trust, and the response names the call that recovers. **A second call on the same area does not repeat itself.** Projections this session has already been given are left out and the room goes to ones it has not, so the follow-up call is all new information rather than 60% restatement. ## Which call answers which question After `chi_context`, for what it did not settle: | What you want to know | Call | |---|---| | What is this repository, how big, what languages | `project_overview()` | | What is in these files | `get_files(paths=[…], view="outline")` | | What does this named thing look like | `get_symbols(ids=[…], detail="behavior")` | | Does this exact text appear anywhere | `contains(tokens=[…], paths=[…])` | | Where is something called X | `search(queries=[…])` | | Who calls this, what does it call, what breaks if I change it | `get_relations(ids=[…])` | | The literal bytes, because nothing else will do | `get_files(paths=[…], view="full")` or `get_symbols(ids=[…], detail="source")` | The row most often skipped is the expensive one to skip: **`contains` is the only tool that sees inside bodies.** Outlines carry symbols, kinds, spans and imports — not comments, not string literals, not statement bodies. If the question is "is this string here", an outline will not answer it and a `view="full"` read is a thousand times the tokens for the same yes/no. Exact source is capped per session. When a call comes back trimmed, the response says so and says what remains: that is the budget speaking. Do not route around it by asking for the same bytes through a different tool. ## Recipes **Unfamiliar repository, open-ended question.** `project_overview()` and `chi_context(task="")` in one message. The overview tells you the shape; the package tells you where to stand. **A bug report or a stack trace.** `chi_context(task="", intent="debug")` — one call. Paste it *whole*, quotes and all: every term seeds the ranking, and the quoted error text is scanned across the index in the same pass. Do not summarise it first; a fuller task is a better answer, not a costlier one. **"Where is X handled?"** If X is a name you already have, `search(queries=["X", "handleX", "x_handler"])` — the plural form, several spellings, one call. If it is a behaviour rather than a name, that is `chi_context`. **Before changing a function.** `chi_context(task="", intent="edit", symbols=[""])`. That returns the current source, the hash to patch against, the blast radius and the tests, in one turn — the four calls it used to take. **"Does this repository use Y anywhere?"** `contains(tokens=["Y"])` — not a `search`, and certainly not a Grep sweep. Hit counts and paths, no file bodies. **Reviewing a change across several files.** One `get_files(paths=[all of them], view="outline")` first. Outlines plus line spans are usually enough to reason about structure; pull `view="full"` only for the files where the change is subtle. ## Session memory Archis remembers across turns so your context does not have to. Where the server offers `session_report`, the accounting it returns — tokens per level, per tool, per turn, escalation rates — is how you check that a long session is still cheap. If a session is escalating to L3 repeatedly, passes 1–3 are being skipped. The fuller session tools (`session_create`, `task_set`, `decision_add`, `checkpoint_create`, `session_rehydrate`) exist on the full toolset. On a long task, recording a decision costs one call and saves re-deriving it after a compaction. ## Editing If `apply_patch` is in the tool list, the server was started with writes on and edits go through it: `apply_patch(patches=[{file, base_hash, operations}, …])`. The outline already gave you every symbol's line span and every file's `content_hash`, so an edit needs no further read. Emit only what the region becomes — do not quote the old text back to locate it, and never re-emit a whole file to change part of it. Every file and every hunk goes in one call: nothing is written unless all of them verify. If `apply_patch` is *not* in the tool list, writes are off by design. Use the harness's own editor — but locate the edit with Archis first, so the editor is handed coordinates instead of being used to search. ## When Archis's tools are not in this session The MCP server may not be registered. Do not silently fall back to reading the whole repository — say so, and use the CLI, which answers the same questions from the same index: ```bash chi overview # project_overview chi search "" --limit 20 # search chi symbol --detail behavior # get_symbols (signature|behavior|source) chi context "" # chi_context; --intent edit for a patch chi callers # get_relations, callers chi callees # get_relations, callees chi impact --depth 3 # transitive callers — the blast radius chi source # exact source, L3 ``` The CLI pays process start on every invocation and holds no session, so batch what you can and prefer the server when it is available. Registering it is one command and takes effect on the harness's next start: ```bash chi mcp on claude # or: chi mcp status, to see what is connected ``` If `chi` itself is missing from the PATH, Archis is not installed on this machine and none of the above applies — fall back to the harness's own tools and say that is what you are doing. ## Anti-patterns - Reading files one at a time to discover what is in them. That is pass 1, and it is one call. - Looping `get_symbols` per symbol, or `get_files` per path. The plural is the point. - Reaching for Grep to answer "does this text exist" — `contains` answers it without reading the files. - Re-requesting content already returned this session. It is still in your context; asking again returns a pointer, not the bytes, and costs a turn. A file that changed since comes back as bytes, so a pointer is never stale. - Escalating to `view="full"` because an outline "might" be missing something. Check with `contains` first — that is what it is for. - Using `search` on a described symptom. `search` matches names; a symptom has none. That is `chi_context`. - Assembling `chi_context`'s package by hand out of `compact_select`, `get_files` and `get_symbols`. Those calls all still work and each one costs a turn; the whole point of the package is that it costs one. - Shortening the `task` to keywords. Every term in it seeds the ranking, and quoted text is searched for literally. Prose is the input format.