token-goat 2.9.1 → 2.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/docs/cli.md ADDED
@@ -0,0 +1,339 @@
1
+ ---
2
+ title: "CLI reference"
3
+ description: "Every command: surgical reads, semantic search, repo maps, cached output recall, and PDF, Word, PowerPoint, Excel, SQLite and image inspection."
4
+ image: /token-goat/assets/goat-social.png
5
+ ---
6
+
7
+ [← Back to the token-goat README](../README.md)
8
+
9
+ # CLI
10
+
11
+ Every command accepts a global `--cwd <path>`, which runs it as if invoked from that directory. It exists so a caller can name a project root without making that root its own working directory — a launcher should never resolve a binary name against a directory the workspace controls. It is applied before anything resolves the project root or loads config, so `--cwd` selects which `.token-goat.toml` applies.
12
+
13
+ ### Archive/document comparison workflow
14
+
15
+ These are agent-selected primitives, not a manual checklist. Give the agent the file and the question. The installed routing guide and read hook select the matching format flow; the commands below show the steps it can take without loading whole files:
16
+
17
+ ```bash
18
+ token-goat sqlite-schema catalog.db
19
+ token-goat sqlite-query catalog.db "SELECT file_path, name FROM files WHERE name LIKE '%owner%' LIMIT 20" --json
20
+ token-goat xlsx-sheets link-map.xlsx
21
+ token-goat xlsx-query link-map.xlsx --sheet Links --columns publication,source,target --head 50
22
+ token-goat pdf-meta manual.pdf
23
+ token-goat pdf-outline manual.pdf
24
+ token-goat pdf-locate manual.pdf "torque spec" --ignore-case
25
+ token-goat pdf-extract manual.pdf --pages 12-15 --layout --head 120
26
+ ```
27
+
28
+ `token-goat` intentionally does not render PDF pages or infer XML publication lineage: those operations produce binary/visual output or require schema-specific interpretation. Keep those steps in the document/PDF tooling, then pass only the bounded paths, rows, and page text needed for comparison.
29
+
30
+ | Command | What it does |
31
+ |---------|-------------|
32
+ | `token-goat symbol [name]` | Jump to a symbol definition. `-p, --project [path]` scopes the search to one project root instead of the default global (cross-project) index — pass no value to use the current directory's project root, or a path to scope to a different one. `--json`'s `filePath` renders root-relative when a project root resolves, absolute when none does — matching human output and the outline/skeleton/refs `--json` convention. `--grep <pattern>` searches project-wide by NAME PATTERN instead of an exact name (regex, falling back to a literal substring match when the pattern is not valid regex) — the positional name is omitted in that mode, and the two are mutually exclusive since regex-filtering an already-exact name can only match everything or nothing. This is the only project-wide symbol-name pattern search: `skeleton`/`outline`/`exports --grep` are per-file, `types --grep` covers only type-like kinds, and `dead --grep` only zero-reference symbols. The filter is applied before the `--limit` slice, so `--limit N --grep P` returns up to N *matching* rows; when it matches nothing among symbols that are in scope, the output names the active filter instead of reading as an empty project. `--exclude-tests` hides symbols DEFINED in a test file (opt-in — omitted, output is unchanged), the same definition-site sense `dead --exclude-tests` uses rather than the call-site sense of `refs`/`callers`. The high-value case is a common helper name that is mostly defined in tests: against this repo's own index `symbol run` returns 18 rows of which 14 are test-file definitions, and `symbol capture` returns 9 of 9. Composable with `--grep` (a symbol must satisfy both) and applied before the `--limit` slice, so the flag selects from the whole match set rather than an already-capped page — without that ordering a `--limit N` window filled by test-file rows would report nothing for a symbol that is plainly indexed in src. When it hides every match there was, the output names how many were hidden and exits 0, instead of the exit-1 `No matches` a genuinely unindexed name returns. `--stats` adds a per-result reference count and doc-coverage flag, computed live from the index — the same flag `read`/`skeleton`/`outline` already carry, useful here for picking which of several same-named candidates is the real one. Note its known limitation: the count is keyed by symbol NAME project-wide, not by definition site, so under `--grep` several same-named symbols in different files all show the identical count. |
33
+ | `token-goat read "file::symbol"` | Pull one function or class, not the whole file. Supports qualified lookups (`read "file.py::Class.method"`) and line ranges: `read "file.py@10-40"` for lines 10 to 40 inclusive, or `read "file.py@42"` for one line. Line ranges read straight from disk, so they work on any file, including paths outside an indexed project. A trailing `@LINE` on the symbol itself (`read "file.py::run@42"`, or combined with a qualifier as `read "file.py::Class.method@42"`) anchors an ambiguous spec to the one candidate starting on that exact line — for a top-level definition with no enclosing `Class.method` qualifier, this is the only way to pick it out when its bare name also matches something else in the same file; every ambiguity error's retry suggestions already use this form where a plain qualifier wouldn't be unique. Pass a comma-separated spec (`file::a,b`) to merge several symbols' bodies from one file into a single call, each headed by its symbol name. Segments may also carry their own file (`a.ts::x,b.ts::y`) to merge symbols across several files in one call; a bare segment inherits the file to its left (`a.ts::x,b.ts::y,z` reads `z` from `b.ts`), and once more than one file is involved each block is headed by the full `file::symbol` so two files contributing the same symbol name stay distinct. `--force-refresh` reparses the file from disk and updates the index before querying — for files touched by git operations, external tools, or direct filesystem writes that bypass the normal post-edit indexing hook. `--stats` adds a per-symbol reference count and doc-coverage flag, computed live from the index. |
34
+ | `token-goat replace <file>` | Replace one string in a file using `--old-from`/`--new-from` or `--old-b64`/`--new-b64`; `--all` replaces every match. If the exact match fails but a unique match exists once CRLF/LF differences are ignored, it heals automatically, writing the replacement back in the file's line-ending convention at that location. `--normalize-newlines` converts the old/new text's CRLF/LF to match the target file's dominant line ending before matching, for forcing normalization proactively. |
35
+ | `token-goat insert-section <file> --after <heading>` | Insert content immediately after a matched section (`--content-from <source>` or `--content-b64 <payload>`), resolved the same way `section` resolves headings (exact, normalized, or an unambiguous prefix) — avoids the stale byte-exact anchor `replace` would otherwise need for an append-to-a-running-log edit. |
36
+ | `token-goat note-add <file> [--symbol NAME]` | Attach a free-text architecture/rationale note (Markdown, `--content-from <source>` or `--content-b64 <payload>`) to a file, or to one specific indexed symbol within it. Captures a fingerprint of what the note describes (the symbol's current body, or a digest of the file's current top-level symbol manifest) so staleness can be detected later — re-running `note-add` for the same file/symbol overwrites rather than duplicates. |
37
+ | `token-goat note-get <file> [--symbol NAME]` | Read back the note attached to a file or one indexed symbol within it. Flags whether the note has gone stale (the underlying code changed since it was written) via a `stale` field under `--json`. |
38
+ | `token-goat note-list [--stale-only]` | List every recorded architecture note. `--stale-only` shows just the notes whose fingerprint no longer matches the current index — i.e. the file/symbol they describe changed since the note was written. Staleness is purely advisory: nothing here auto-rewrites or deletes a note. |
39
+ | `token-goat write-file <dest>` | Write exact bytes to a file, sidestepping shell-escaping trouble with backticks, quotes, `$vars`, and CRLF. `--from <source>` copies bytes from a source file; `--b64 <payload>` decodes a base64 payload; with neither, reads from stdin. |
40
+ | `token-goat section "doc.md::Heading"` | Pull one Markdown section by heading. A miss that is an unambiguous prefix of exactly one heading, or a distinctive suffix/word-subset of exactly one heading (e.g. `Setup` → "Installation and Setup", `Config Options` → "Configuration Options"), auto-redirects with a `(redirected from: …)` marker (and a `redirectedFrom` field under `--json`); a query matching 2+ headings is never guessed and reports a miss instead. A genuine miss lists only headings similar to the query as "Did you mean" suggestions, not every heading in the file. Disambiguate duplicates with `"doc.md::Heading#2"`. Comma-separated `"doc.md::A,B"` fetches several sections from one file in a single call, mirroring `read`'s `file::a,b` multi-symbol grammar. Cross-file `"a.md::Heading1,b.md::Heading2"` fetches sections from several files in one call, mirroring `read`'s `a.ts::x,b.ts::y` cross-file grammar — a bare heading after a `file::Heading` segment inherits the previous file, and each section is keyed by its full `file::Heading` pair so two files sharing a heading name cannot overwrite each other. `token-goat section doc.md --list` lists every heading in the file instead of reading one; `--grep <pattern>` narrows that list to headings matching a regex (falls back to a literal substring match if the pattern doesn't compile), same convention as `outline`/`types`/`exports`'s own `--grep`. |
41
+ | `token-goat skill-section "<name>::<heading>"` | Extract a named section from an installed skill without reading the full skill file. |
42
+ | `token-goat skeleton "file"` | Show all signatures in a file without bodies — typically 70–90% fewer tokens than a full read. `--force-refresh` reparses from disk first, bypassing a stale index. `--stats` adds a per-symbol reference count and doc-coverage flag, computed live from the index. `--grep <pattern>` narrows to symbols whose name matches a regex (a literal substring when the pattern is not valid regex), which is how you skim one area of a large file without dumping its whole symbol list; `--min-lines <n>` drops symbols shorter than N lines. Both compose, and if a filter removes everything the output says so and names the filter, rather than looking like a file with no symbols. Accepts a comma-separated file list (`"a,b,c"`) to cover several files in one call, one clearly-headed block per file; extra space-separated file arguments are reported in a note naming that comma form instead of being silently dropped. With `--json`, a comma-separated list returns one merged document (rows carry their own `filePath`), not one document per file. |
43
+ | `token-goat outline "file"` | List top-level symbols with line ranges and docstring hints — one-glance file map. Doc hints are clipped to about a sentence with a visible ellipsis; the full doc comment is one `read "file::symbol"` away (`--json` carries it whole). `--force-refresh` reparses from disk first, bypassing a stale index. `--stats` adds a per-symbol reference count and doc-coverage flag, computed live from the index. `--grep <pattern>` narrows to symbols whose name matches a regex (a literal substring when the pattern is not valid regex), which is how you skim one area of a large file without dumping its whole symbol list; `--min-lines <n>` drops symbols shorter than N lines. Both compose, and if a filter removes everything the output says so and names the filter, rather than looking like a file with no symbols. Accepts a comma-separated file list (`"a,b,c"`) to cover several files in one call, one clearly-headed block per file; extra space-separated file arguments are reported in a note naming that comma form instead of being silently dropped. With `--json`, a comma-separated list returns one merged document (rows carry their own `filePath`), not one document per file. |
44
+ | `token-goat yaml-outline <file>` | Structural summary of a YAML document (array shape / object key types) instead of a raw Read. Multi-document streams (`---`-separated) outline as an array of documents. |
45
+ | `token-goat yaml-query <file> <path>` | Extract one value or a projected/filtered subset from a YAML document by dot-path instead of a raw Read (same grammar as `json-query`: `[n]` index, `[*]` wildcard, `[field=value]` filter — e.g. `items[status=active].name`). `--head <n>` caps a projected/filtered result. |
46
+ | `token-goat xml-outline <file>` | Structural summary of an XML document (element tag hierarchy, attribute keys, child counts) instead of a raw Read. |
47
+ | `token-goat xml-query <file> <path>` | Extract one value, element text/XML, or a projected/filtered subset from an XML document by XPath-like dot-path instead of a raw Read (same grammar as `json-query`/`yaml-query`: element tags, `@attr`, `[n]` index, `[*]` wildcard, `[attr=value]` filter, `--head <n>`). |
48
+ | `token-goat json-outline <file>` | Structural summary of a JSON document (array shape / object key types) instead of a raw Read. |
49
+ | `token-goat json-query <file> <path>` | Extract one value or a projected/filtered subset from a JSON document by dot-path instead of a raw Read: dot-separated keys with optional bracket segments — `[n]` index, `[*]` wildcard (projects every element/value), `[field=value]` filter. Examples: `data.items[3].name`, `items[*].id`, `items[status=active]`. |
50
+ | `token-goat brief "file::symbol"` | Bundle a symbol's body, resolved callers (grouped by enclosing function), and its containing doc section into one round-trip instead of three separate `read`/`callers`/`section` calls. `--limit <n>` caps the callers shown per symbol (default 20; the true caller count is reported even when truncated). Comma-separated `"file::a,b"` fetches several symbols' bundles from one file in a single call, mirroring `read`'s `file::a,b` multi-symbol grammar. Cross-file `"a.ts::x,b.ts::y"` bundles symbols from several files in one call, mirroring `read`'s cross-file grammar — a bare segment inherits the file to its left, and once more than one file is involved each bundle is keyed by the full `file::symbol` so two files contributing the same symbol name stay distinct. Also accepts `read`'s `symbol@LINE` anchor to pick out an otherwise-ambiguous candidate. `-C, --context <n>` adds N lines of real call-site source around each entry of the caller block. `--json`'s `symbol.filePath` and `callers[].file` render root-relative when a project root resolves, absolute when none does — matching the plain-text block above. `--exclude-tests` hides callers whose call site is in a test file, matching `refs`/`callers`; the caller count and the elided tail both count the filtered set, so they never disagree with the rows shown, and when the filter empties the block it says so instead of reporting a bare zero that would read as "nothing calls this". `--json` adds `hiddenByExcludeTests` only when the filter actually hid something. `--grep <pattern>` narrows the caller block to callers whose enclosing symbol name matches this regex (literal substring if it is not valid regex), the same filter `refs --grep`/`call-chain --grep` apply to their own results — useful for a high-fanout symbol whose default 20-caller window is otherwise mostly noise; composes with `--exclude-tests`, and reports `hiddenByGrep` under `--json` only when it hid something. |
51
+ | `token-goat scope "file:line"` | Show symbols in scope at a given line — avoids reading the whole file to understand locals. |
52
+ | `token-goat exports "file"` | List public (exported) symbols with types, docstring hints, and line ranges (`(lineStart-lineEnd)` in text mode, `lineStart`/`lineEnd` fields under `--json`). Names caught only by the source-text scan (no corresponding index row — e.g. certain re-export forms) report no location: omitted from text mode, `null` under `--json`. Accepts a comma-separated file list (`"a,b,c"`) to cover several files in one call, one clearly-headed block per file; extra space-separated file arguments are reported in a note naming that comma form instead of being silently dropped. `--grep <pattern>` only shows exported symbols whose NAME matches this regex (literal substring if it is not valid regex), applied before output is built; when it matches nothing among real exports, the output names the active filter instead of reading like the file has no exports at all. |
53
+ | `token-goat refs "<name>"` | Show all files and line numbers where a symbol is referenced. Pass a comma-separated spec (`a,b,c` or `file::a,b`) to merge several symbols' references into one call, each group headed by its symbol name. Segments may also carry their own file (`a.ts::x,b.ts::y`) to merge references across several files in one call, mirroring `read`'s cross-file grammar — a bare segment inherits the file to its left, and once more than one file is involved each block is headed by the full `file::symbol` so two files contributing the same symbol name stay distinct. `--top <n>` groups references by file (count only) and shows just the top N by reference count with an elision note, instead of a per-line dump — for high-fanout symbols referenced in hundreds of places. `-C, --context <n>` shows N lines of real call-site source either side of each hit, rendered exactly like `grep -C`; omit it (or pass 0) and output is unchanged. Under `--json` each item gains a `contextLines` array alongside the existing `context` field (which names the enclosing symbol, not source text). `--exclude-tests` hides references whose call site is a test file (opt-in — omitted, output is unchanged); the summary line reports the filtered count plus how many were hidden. `--grep <pattern>` only shows references whose call-site FILE PATH matches this regex (literal substring if it is not valid regex) — rows render as `file:line: symbol`, so this is the field each row is keyed on. The pattern is tested against the path exactly as the row renders it, so an anchored `--grep "^src/"` matches what you see, identically in the single, multi-symbol and cross-file forms. Every form renders a call-site path the same way -- root-relative when a project root resolves, absolute when none does, never cwd-dependent -- and `--json` carries that same spelling in `filePath` (and in `--top`'s `fileCounts[].file`), so a payload is reproducible rather than tied to one machine's drive-letter casing. The high-value case is narrowing a wide-fanout symbol to drop test/vendored hits. Applied before `--top`'s grouping and before any `--limit` slice, so it selects from the whole reference set, not an already-capped page; when it matches nothing among references that do exist, the output names the active filter instead of reading like the symbol is unreferenced. A bare name that isn't indexed at all reports `Symbol not found: <name>` (with a `Did you mean:` suggestion when a near-name candidate is indexed) instead of the misleading "no references found", which is reserved for a real, indexed symbol that genuinely has zero references. |
54
+ | `token-goat callers <symbol>` | Show which functions call a given symbol, grouped by caller with file, caller name, and every invoking line. Complements `refs`, which shows raw reference sites without grouping by enclosing function. Accepts `file::symbol` to disambiguate WHICH same-named definition is meant when several files define a symbol with that name — the file only narrows which definition, callers can still be found in any file. `-C, --context <n>` shows N lines of real call-site source either side of each hit, rendered exactly like `grep -C`; omit it (or pass 0) and output is unchanged. Under `--json` each item gains a `contextLines` array alongside the existing `context` field (which names the enclosing symbol, not source text). `--exclude-tests` hides callers whose call site is a test file (opt-in — omitted, output is unchanged); prints a note naming how many were hidden. `--grep <pattern>` only shows callers whose enclosing symbol NAME matches this regex (literal substring if it is not valid regex) — rows render as `symbol<TAB>file:line`, so this is the field each row is keyed on. Applied before the `--limit` slice, so it selects from the whole caller set, not an already-capped page; when it matches nothing among callers that do exist, the output names the active filter instead of reading like the symbol has no callers. A bare name that isn't indexed at all reports `Symbol not found: <name>` (with a `Did you mean:` suggestion when a near-name candidate is indexed) instead of the misleading "no references found", which is reserved for a real, indexed symbol that genuinely has zero callers. `--json` emits each item's path under both `file` and `filePath` with the identical value; `file` is kept for this release only and will be removed in a future one, so `filePath` is the spelling to migrate to (matching `symbol`/`types --json`). `--json` emits the shared `{items, truncated, totalCount}` envelope — the same shape `symbol`/`refs`/`skeleton`/`outline --json` return, present whether or not truncation occurred, so a script never has to branch on shape. |
55
+ | `token-goat call-chain <symbol>` | Trace every caller layer from a symbol back to the entry points — one step deeper than `callers`. Use when you need to know what reaches a function across the whole call graph, not only who invokes it directly. Pairs with `impact` for the downstream direction. Accepts `file::symbol` to disambiguate WHICH same-named definition the chain starts from — the file only narrows which definition, callers can still be found in any file. `--exclude-tests` prunes callers whose call site is a test file BEFORE they're admitted to the traversal, so nothing walks through a test node either (opt-in — omitted, output is unchanged); when every caller was a test, the "no callers" line names how many were hidden instead of reading as genuinely unreferenced. `Symbol not found: <symbol>` for an unindexed name (bare or `file::symbol`) now carries a `Did you mean:` suggestion when a near-name candidate is indexed. `--grep <pattern>` keeps only completed chains containing a symbol name matching this regex (literal substring if it is not valid regex) — the BFS still walks the full graph, this only narrows which finished chains are reported, so a chain passing through a matching symbol on its way to an unrelated root still surfaces; when it matches none of the chains that do exist, the output names how many were filtered out rather than reading as genuinely caller-less. A chain the walk abandoned because it ran out of `--depth` ends in a `(depth-limit)` marker, so a truncated chain is never mistaken for one that reached a real entry point. |
56
+ | `token-goat impact <symbol>` | Walk the call-reference graph forward (breadth-first) and list every function that depends on a symbol, with hop depth; module-scope callers are surfaced as `(module scope) <file>` entries. Run before a refactor to size up the blast radius without starting a build. Accepts `file::symbol` to disambiguate WHICH same-named definition the walk starts from — the file only narrows which definition, callers can still be found in any file. `--exclude-tests` prunes callers (including module-scope entries) whose call site is a test file BEFORE they're enqueued for further traversal, so nothing walks through a test node either (opt-in — omitted, output is unchanged); when every caller was a test, the "no callers found" error names how many were hidden instead of reading as genuinely unreferenced. A bare name that isn't indexed at all reports `Symbol not found: <name>` (with a `Did you mean:` suggestion when a near-name candidate is indexed) instead of the misleading "no callers found", which is reserved for a real, indexed symbol that genuinely has zero impact. `--grep <pattern>` only shows impacted entries whose symbol name (or `(module scope) <file>` key) matches this regex (literal substring if it is not valid regex), the same filter `call-chain --grep`/`dead --grep` apply to their own results — applied BEFORE the `--top` slice, so it selects from the whole impacted set rather than an already-capped page; when it matches none of the impacted entries that do exist, the output names how many were filtered out instead of reading as genuinely impact-free. |
57
+ | `token-goat context-for <task>` | Takes a natural-language task description, runs semantic search across the indexed codebase, and emits a prioritized list of `token-goat read` commands trimmed to a token budget. Fetches only the relevant slices instead of loading entire files. `--budget N` sets the token ceiling; `--top N` limits the file count; `--json` for structured output. Every emitted command carries the `file::symbol@LINE` anchor, so a suggestion still runs when the same symbol name has more than one definition in its file; `--json` entries carry the matching `line` field. |
58
+ | `token-goat ask "<question>"` *(experimental)* | Retrieves relevant slices via full-text (BM25) search over the symbol index — not semantic/embedding search — and lists them as pointer-citations plus `token-goat read` commands. Set `TOKEN_GOAT_ASK_BACKEND=claude` or `TOKEN_GOAT_ASK_BACKEND=codex` to synthesize a short answer via that CLI (whatever model it defaults to; token-goat does not force Haiku or any particular tier); with the env var unset, or the named CLI missing from PATH, `ask` degrades to printing the retrieved pointers with no network call. `--top N` caps the number of FTS hits (default 8); `--json` for structured output. Answers are not cached — each call re-retrieves and re-synthesizes from scratch. Every emitted command carries the `file::symbol@LINE` anchor, so a suggestion still runs when the same symbol name has more than one definition in its file; `--json` entries carry the matching `line` field. |
59
+ | `token-goat changed [<ref>]` | List files (or `--symbol` for symbols) changed since a git ref, without reading the full diff. `<ref>` and `--since <ref>` are equivalent (default `HEAD~5`); `--since` wins if both are given. `--json` for structured output. `--grep <pattern>` only lists changed files whose path matches this regex (literal substring if it is not valid regex) — applied to the file list even in `--symbol` mode, before any downstream slicing; when it matches none of the files that did change, the output names the active filter instead of reading like nothing changed. `--exclude-tests` hides changed files that live in a test file (opt-in — omitted, output is unchanged), completing the flag family already on `refs`/`callers`/`dead`/`call-chain`/`impact`/`semantic`/`symbol`. `--grep` can only ever *select* a path, so there was no reliable way to ask for the non-test half of a diff: the negative-lookahead regex that expresses "not a test" silently degrades to a literal substring match whenever the regex-compile fallback fires. Test files are a large share of a typical diff — measured against this repo, 35–54% of changed files across the last 5, 10 and 20 commits. Like `--grep` it filters the file path, so it applies in `--symbol` mode too, and it prunes before the per-file index lookup rather than after, so a test file is never queried at all. Composable with `--grep` (a file must satisfy both; when both are active and `--grep` is what emptied the list, the `--grep` notice takes priority, and when `--grep` left only test files so that `--exclude-tests` emptied it, the message names both filters rather than claiming no non-test file changed). When it hides every changed file there was, the output names how many were hidden and exits 0, rather than a bare "No files changed." that would read as a clean diff. Every zero-row path emits the shared `{items, truncated, totalCount}` envelope under `--json`. |
60
+ | `token-goat diff "file::symbol" [range]` | Show only the git diff hunk(s) that fall within one symbol's line range, e.g. `token-goat diff "file.ts::myFn" HEAD~3..HEAD`, instead of the whole file's diff. Also accepts `read`'s `symbol@LINE` anchor to pick out an otherwise-ambiguous candidate. |
61
+ | `token-goat blame "file::symbol"` | Git blame narrowed to a specific symbol's lines — no whole-file blame needed. Also accepts `read`'s `symbol@LINE` anchor to pick out an otherwise-ambiguous candidate. |
62
+ | `token-goat log "file::symbol" [ref]` | Git commit history scoped to one symbol's line range via git's own `-L` line-range history, instead of a raw `git log -- file` dump of every commit that touched the whole file. `--max-count <n>` caps commits shown (default 20); `--json` for structured output. Also accepts `read`'s `symbol@LINE` anchor to pick out an otherwise-ambiguous candidate. |
63
+ | `token-goat types ["file"]` | List type definitions (TypedDict, Protocol, dataclass, Pydantic models) in a file or across the project. `--grep <pattern>` only shows type declarations whose NAME matches this regex (literal substring if it is not valid regex), applied before output is built; when it matches nothing among declarations that do exist, the output names the active filter instead of reading like there are none. `--exclude-tests` hides type declarations DEFINED in a test file (opt-in — omitted, output is unchanged), the same definition-site sense `dead --exclude-tests` uses. Applied before the per-kind `--limit` slice, so the flag selects from the whole matching set rather than an already-capped page; when it hides every declaration there was, the output names how many were hidden and exits 0, instead of the exit-1 `No type declarations found` a genuinely empty scope returns. `--json`'s `filePath` renders root-relative when a project root resolves, absolute when none does, matching plain-text output. `--json` emits the shared `{items, truncated, totalCount}` envelope — the same shape `symbol`/`refs`/`skeleton`/`outline --json` return, present whether or not truncation occurred, so a script never has to branch on shape. |
64
+ | `token-goat openapi-outline <spec>` | Per-operation listing (method, path, operationId, summary, tags) of an OpenAPI 3.x / Swagger 2.0 spec (JSON or YAML) instead of a raw Read. |
65
+ | `token-goat openapi-op <spec> <operation>` | Full detail (parameters, request body schema, response schemas, description) for exactly one OpenAPI operation instead of a raw Read. `operation` may be an operationId (exact match) or a `"METHOD path"` spec, e.g. `"GET /users/{id}"`. |
66
+ | `token-goat sqlite-schema <db>` | Tables/views, columns, indexes, foreign keys, and row counts of a SQLite database instead of a raw Read. |
67
+ | `token-goat sqlite-query <db> "<SELECT ...>"` | Run a read-only `SELECT` against a SQLite database instead of a raw Read or shelling out to `sqlite3` — rejects any non-`SELECT` statement. |
68
+ | `token-goat imports "file"` | Show the import graph for a file one level deep. Accepts a comma-separated file list (`"a,b,c"`) to cover several files in one call, one clearly-headed block per file; extra space-separated file arguments are reported in a note naming that comma form instead of being silently dropped. `--grep <pattern>` only shows imports whose MODULE SPECIFIER matches this regex (literal substring if it is not valid regex), applied before `--json`'s truncation; when it matches nothing among real imports, the output names the active filter instead of reading like the file has no imports at all. |
69
+ | `token-goat dep-docs <package>` | Extract one installed npm package's README, `package.json` metadata, and (if resolvable) a compact `.d.ts` signature outline, instead of grepping `node_modules`. |
70
+ | `token-goat find "<query>"` | Find the FILES defining a symbol whose name matches a pattern: a case-insensitive substring scan over indexed symbol names, emitting the distinct file paths. When no name contains the pattern, falls back to an edit-distance match so a mistyped name still lands (`getUserr` → `getUser`) — the same ranking `Did you mean:` uses. The fallback runs only when the substring pass found nothing, so an exact match is never reordered or displaced, and a query near nothing still reports a clean miss instead of unrelated names. A recovered match names what it actually matched on stderr rather than silently answering for a name you didn't type; `--json` marks it with `fuzzy: true` and `matchedNames`, both absent on an exact hit. `--limit <n>` caps the file count. Matches on NAMES only — for meaning-based search over file content use `token-goat semantic`. |
71
+ | `token-goat similar "file::symbol"` | Find the top-k symbols most similar to a given symbol, via full-text search over symbol names and bodies. Also accepts `read`'s `symbol@LINE` anchor to pick out an otherwise-ambiguous candidate. |
72
+ | `token-goat test-for "file"` | Find test file(s) for an implementation file and list their test functions. `--json`'s `testFile` renders root-relative when a project root resolves, absolute when none does, matching plain-text output. `--json` emits the shared `{items, truncated, totalCount}` envelope — the same shape `symbol`/`refs`/`skeleton`/`outline --json` return, present whether or not truncation occurred, so a script never has to branch on shape. |
73
+ | `token-goat dead` | Surface functions, methods, and classes with no recorded callers in the project index. Private names and common entry points (`main`, `app`, etc.) are excluded by default. `--include-private` lifts the underscore filter; `--kind` narrows to specific symbol types, comma-separated for a union (`--kind function,method`) — an unrecognized kind errors instead of silently reading as a clean codebase; `--top N` caps output; `--json` for structured output. `--exclude-tests` hides dead symbols DEFINED in a test file (opt-in — omitted, output is unchanged); prints a note naming how many were hidden. `--grep <pattern>` only shows dead symbols whose NAME matches this regex (literal substring if it is not valid regex), applied before `--top`'s slice; when it matches nothing among dead symbols that do exist, the output names the active filter instead of reading like a genuinely clean codebase. Results are a heuristic lead — dynamic dispatch and external callers are invisible to static indexing. `--json` emits both `file` and `filePath` with the identical value, root-relative when a project root resolves, absolute when none does, matching plain-text output; `file` is retained for this release only and will be removed in a future release, `filePath` is the spelling to migrate to (matching `symbol`/`types --json`). `--json` emits the shared `{items, truncated, totalCount}` envelope — the same shape `symbol`/`refs`/`skeleton`/`outline --json` return, present whether or not truncation occurred, so a script never has to branch on shape. |
74
+ | `token-goat coverage-gaps` | Find callables in non-test source files that never appear in a test file's reference records. Useful for spotting untested surface area before a refactor or release. `--top N` caps output; `--json` for structured output. |
75
+ | `token-goat recent [N]` | Show the N most recently edited/accessed files with their symbols. |
76
+ | `token-goat grep "<pattern>" [paths...]` | Built-in fallback regex search over files (no `rg` shell-out, no caching) — session-aware dedup for raw `rg`/`grep` Bash calls is a separate hook, not this command. Accepts zero or more paths: omit to walk cwd, or pass several to search them together with hits merged in argument order under one `--max-lines` cap. `-C, --context <n>` shows `n` lines before and after each match. `--symbol` annotates each hit with its enclosing indexed symbol — ` [name (kind)]` appended in text mode, a `symbol: {name, kind, lineStart, lineEnd} | null` field per item under `--json` — `null`/no tag when the hit falls outside any indexed symbol (e.g. module-level code). |
77
+ | `token-goat semantic "<query>"` | Find code by meaning, not by filename: embedding-vector similarity search over indexed file chunks and full-text search (BM25) over symbol names/bodies both run on every query and are fused by Reciprocal Rank Fusion (`score = sum of 1/(60 + rank)` per list), so an exact keyword match can outrank a weak vector hit instead of being shadowed by the vector branch. Covers extracted text from PDF/DOCX/PPTX/XLSX files alongside source code, so a query can surface a spec PDF, design doc, deck, or spreadsheet, not just code. Results are re-ranked with a path-priority multiplier so live source wins ties/near-ties against stale or archival prose (`archive/`, `archived/`, `old/`, `deprecated/`, `plans/`, `drafts/`, `CHANGELOG*`, `*.bak`, `*.orig`) and, more mildly, general docs (`docs/**`, `*.md`) — a nudge, not a hard filter, so a genuinely much better archival match still surfaces. Configure with `token-goat config set semantic.archive_weight <0-1>` / `token-goat config set semantic.docs_weight <0-1>` (both default `<1`; set to `1` to disable that penalty entirely, e.g. for a project with a genuinely live `plans/` directory). `--limit <n>` caps result count; `--json` for structured output: `{source, items, truncated, totalCount}`, where `source` is `"hybrid"` when both the embedding and BM25 branches contributed at least one raw hit, `"embeddings"` when only the embedding branch did (e.g. no vector index exists yet: optional embedding deps unavailable, or `indexing.embeddings_enabled` is off), or `"fts"` when only BM25 did, and every item carries the same keys (`filePath`, `name`, `kind`, `startLine`, `endLine`, `distance`, `preview`), with `null` for whichever of `name`/`kind`/`distance` don't apply to that item's source, and `filePath` rendered root-relative when a project root resolves, absolute when none does, matching plain-text output. On an embeddings hit, `name`/`kind` are resolved to the innermost indexed symbol whose line range contains the hit's start line (`null`/`null` when the hit falls outside any symbol, e.g. a top-of-file imports chunk); text output appends the same as a `— inside <name> (<kind>)` suffix. `--grep <pattern>` only shows hits whose FILE PATH matches this regex (literal substring if it is not valid regex), tested against the path exactly as rendered (so an anchored `--grep "^src/"` matches what you see, not the stored absolute path) — the high-value case is dropping test/vendored noise from a project-wide semantic hit list. Applied before the `--limit` slice in both the embeddings and full-text-fallback branches, so it selects from the whole hit set, not an already-capped page; when it matches nothing among hits that do exist, the output names the active filter (and `--json` sets `grepFilteredToEmpty: true`) instead of reading like the search found nothing. `--exclude-tests` hides hits whose file is a test file (opt-in — omitted, output is unchanged), covering the case `--grep` structurally cannot: `--grep` can only ever *select* a path, and the negative-lookahead pattern that would express "not a test" silently degrades to a literal substring match whenever the regex-compile fallback fires. Applied before the `--limit` slice in both branches and composable with `--grep` (a hit must satisfy both); when it hides every hit there was, the output names how many were hidden (and `--json` sets `excludeTestsFilteredToEmpty: true`) and exits 0, instead of the exit-1 "no matches" a genuinely empty search returns. With both filters set and both emptying the view, the `--grep` notice takes priority. |
78
+ | `token-goat map` | Get a compact orientation of the repo. Add `--compact` to fit a fixed 2000-token budget. `--json` emits the project map as JSON instead of text. |
79
+ | `token-goat deps "file"` | One-level import listing for a single file: resolves relative imports to project files (`internal`, root-relative paths) and groups everything else as `external`. `--json` for structured output. `--grep <pattern>` only shows dependencies whose MODULE SPECIFIER (the resolved internal path or the external package name) matches this regex (literal substring if it is not valid regex), applied before output is built; when it matches nothing among real dependencies, the output names the active filter instead of reading like the file has no imports at all. Complemented by `token-goat arch` for the project-wide graph. |
80
+ | `token-goat arch` | Project-wide import graph summary: hub modules (most imported), entry points (nothing imports them), and circular chains. `--modules` adds a grouping of the files that mostly import each other, naming each group by its most connected file, saying whether the group is one directory or spread across several, and listing which groups reach into which. That section also prints the grouping's modularity and calls it out when it is too weak to mean anything, since the algorithm returns groups for any graph, including one with no real structure. `--json` carries each group's full member list. Complements `token-goat deps <file>` for per-file depth. |
81
+ | `token-goat affected [files...]` | Which test files transitively import the given changed files, for narrowing a CI run: `git diff --name-only \| token-goat affected --stdin --quiet` prints bare paths ready to pipe into a test runner. Walks the same import graph `arch` builds, backwards. Distinct from `test-for`, which asks which tests reference a file's SYMBOLS by name in one hop; a test reaching the change through a helper is invisible to that one and visible here, and neither subsumes the other. `--depth <n>` bounds the walk (default 5); `--filter <regex>` overrides what counts as a test and an invalid pattern is refused rather than silently matched as a literal, since a typo would quietly select a different set of tests. Every way it can return less than everything is disclosed: an untracked path is named rather than dropped, and a depth bound that actually cut the walk short is reported with how many files were left unexplored. Both disclosures go to stderr so `--quiet` stdout stays pipeable. `--json` for structured output. |
82
+ | `token-goat reconcile` | Sweep this project for files that changed while no token-goat hook was running -- a pull in another terminal, an editor save, a code generator -- and queue them for reindexing. The same sweep runs automatically at session start; this is the manual form. Costs one filesystem stat per tracked file in the ordinary case and only reads a file whose timestamp moved, and a moved timestamp is confirmed against content rather than trusted, so a branch switch does not queue the whole repository. `--dry-run` reports the drift without queueing it; `--budget-ms <ms>` changes the time budget; `--json` for structured output. A sweep cut short by its budget says so and reports no deletions at all, because a file it never reached is indistinguishable from one that was deleted. |
83
+ | `token-goat index [path]` | Parse all git-tracked files and (re)build the symbol index from scratch. Runs automatically on install and incrementally via the background worker after edits — use this to force a full rebuild (e.g. after a config change that narrows what gets indexed). Each file records which version of token-goat's extraction logic produced its symbols, so an upgrade that changes what gets extracted reparses every already-indexed file once, on the next run, instead of leaving unchanged files on their old symbols until something edits them. That first run after such an upgrade takes noticeably longer than usual; later runs skip unchanged files as before. `--walk` indexes a bounded directory walk instead when `path` isn't a git repo. `--force-walk` does the same non-git walk and raises its 20,000-file refusal to 500,000 for a folder you know is genuinely that large (slow, and produces a large index — check `token-goat doctor` afterwards); it never lifts the separate refusal to walk a filesystem root or your home directory. On a real terminal (not a pipe/CI), prints a live progress line to stderr (files done/total, current phase, elapsed time) so a large repo doesn't look hung; stdout is unaffected either way. |
84
+ | `token-goat ignores` | List active skip patterns for the current project — built-in skip dirs and suffixes, blocked roots, and which command each one applies to. It also reports `.tokengoatignore`, which applies to `token-goat pack` only: it excludes nothing from the symbol index. To keep a path out of the index, use `token-goat project exclude <path>`. |
85
+ | `token-goat gdrive-sections <file-id>` | List the heading outline of a Google Doc without fetching the body. |
86
+ | `token-goat stats` | See locally estimated savings: total events / bytes saved / tokens saved. Add `--full` for the per-source, per-command, and per-day breakdown, or `--methodology` to explain estimates and their limits. These values are not GitHub Copilot usage or billing data. |
87
+ | `token-goat cost [--session]` | Estimated tokens saved, session or all-time, broken down by savings source. |
88
+ | `token-goat context-stats [--project <path>]` | Report estimated token overhead from `CLAUDE.md` files and `MEMORY.md` in a project. `--json` for structured output; `--fix` prunes dead-link and duplicate entries from `MEMORY.md` and writes the file (destructive — inspect the report first). |
89
+ | `token-goat bootstrap-audit [--project <path>] [--json]` | Audit Claude Code startup-context contributors without outputting prompt bodies: global/project `CLAUDE.md` totals plus agent/skill frontmatter metadata, largest entries, diagnostics, and CI warning/failure budgets (`--warn-tokens`, `--fail-tokens`, `--warn-bytes`, `--fail-bytes`). |
90
+ | `token-goat memory [--project <path>] [--analyze\|--fix] [--yes]` | Find duplicate/overlapping content across the `CLAUDE.md` files loaded for a project, plus near-duplicate sibling auto-memory files. `--analyze` (default) is report-only. `--fix` removes exact-duplicate lines within a file (the only mechanical, judgment-free fix); duplicate headings and cross-file overlaps are reported as advisory only and never auto-applied. See [Memory analysis and cleanup](#memory-analysis-and-cleanup) below. |
91
+ | `token-goat waste [--project <path>] [--transcript <path>] [--top <n>] [--json] [--copilot]` | Session spend-ledger: parses the current project's Claude Code session transcript and reports token cost by tool, by file, the top N most expensive individual tool calls, files read once and never referenced again, Bash commands run repeatedly without hitting token-goat's own bash-output cache, and the assistant's own text-output cost (generated tokens plus a cache-unaware re-send upper bound). See [Session waste ledger](#session-waste-ledger) below. |
92
+ | `token-goat mcp-audit [--project <path>] [--json]` | MCP server schema cost report: scans .mcp.json for installed MCP servers, estimates per-server token costs from cached tool calls, correlates schema complexity against real call frequency. Outputs as markdown table or JSON. |
93
+ | `token-goat recall ["<query>"] [--type bash\|web\|mcp] [--limit <n>] [--json]` | Full-text search across every cached bash-output, web-output, and mcp-output entry at once — one command instead of remembering which cache type holds a prior result. Ranked by relevance (BM25 via SQLite FTS5). With **no query**, lists every cached entry newest-first instead of searching, so you can browse when the ids have scrolled out of context and you have no term to search for. `--type` narrows to one cache type; `--limit` caps results (default 10). Each hit shows its cache type, id, the exact recall command (`bash-output <id>` / `web-output <id>` / `mcp-output <id>`), and a content snippet. See [Cross-cache recall](#cross-cache-recall) below. |
94
+ | `token-goat hint-stats [--json] [--reset] [--mark-effective <cat>] [--mark-ineffective <cat>]` | Per-category efficacy report for token-goat's discretionary hint hooks: how often each hint category was emitted, how often the agent actually followed its specific suggestion within the next few tool calls, whether the category is currently auto-suppressed, and the bytes each category spent (injected into context) plus an all-time saved/spent/net summary line. `--reset` clears all tracked data; `--mark-effective`/`--mark-ineffective <category>` record a manual vote as a supplement to the automatic signal. See [Hint efficacy tracking](#hint-efficacy-tracking) below. |
95
+ | `token-goat history` | Show current session access history: bash commands and URLs fetched. |
96
+ | `token-goat session-outline` | Turn-by-turn structure (role, preview, tool calls, approx size) of a Claude Code session JSONL transcript, instead of a raw Read; defaults to the current project's most recent session. |
97
+ | `token-goat session-slice <turns>` | Full content of one turn range from a Claude Code session JSONL transcript (see `session-outline` for turn numbers), instead of a raw Read. |
98
+ | `token-goat session-audit [--dir <path>] [--json]` | Corpus-wide token attribution across every local Claude Code session transcript, including nested subagent transcripts (default corpus: `~/.claude/projects`): measured billed usage from each API response's own usage record, estimated content size by source and by tool, a per-attachment-kind census ranked by modeled billed cost (cache write plus compaction-capped cache re-reads over the model-visible fields only), a hook-output census split by origin, a subagent-lane rollup (spawn-prefix size and its modeled billed carriage, plus a per-agent-type breakdown from each lane's meta file), a Read-interception census (diverted reads versus full serves, with each large full serve split into first read versus repeat and repeats classified as deliberate paging or divert-miss candidates), a Bash filter fire-rate census (results carrying a token-goat marker versus the untouched remainder, bucketed by bare command head: the binary name only), and billed cost by session position. Output is aggregate counts only, never transcript content or command lines. |
99
+ | `token-goat bash-output <id>` | Retrieve a cached Bash output by ID instead of re-running the command. Large outputs return a head(30)+tail(80) view by default; pass `--full` for the entire stored entry with no elision, `--head N`/`--tail N` for a specific slice, or narrow with `--grep PATTERN` (cap `--grep` to the first N hits with `--max-matches N`). Read a file directly with `--file <path>` (e.g. a background task's `tasks/<id>.output`); add `--transcript` to parse that file as a subagent JSONL transcript, keeping only assistant text blocks in order before the slicers apply. |
100
+ | `token-goat bash-history` | List cached Bash outputs (newest first) with their IDs, byte sizes, and exit codes. |
101
+ | `token-goat compress --cmd '<command>'` | Preview what the Bash compression hook would do to any command — runs it, applies the matching filter, and prints the compressed view. |
102
+ | `token-goat web-output <id>` | Retrieve a cached WebFetch response body by ID — same head+tail default and `--full`/`--head`/`--tail`/`--grep`/`--max-matches` slicers as `bash-output`. `--raw` returns the body as actually fetched, before `webfetch.compress_bodies`'s HTML-cleaning pass, for recovering a selector/script tag/embedded JSON that the default cleaned text drops; falls back to the (already-raw) cleaned body when no separate raw copy was stored. |
103
+ | `token-goat web-history` | List cached WebFetch responses (newest first) with their IDs, byte sizes, status codes, and URL previews. |
104
+ | `token-goat mcp-output <id>` | Retrieve a cached MCP tool result by ID (the id an MCP `post_tool_use` hook cached, or a `[token-goat: compressed, full via mcp-output <id>]` label points here). Same slicers as `bash-output`; `--full` returns the stored entry verbatim, which is what an elision marker's `mcp-output <id> --full` pointer relies on. |
105
+ | `token-goat mcp-history` | List cached MCP tool result entries (newest first) with their IDs and byte sizes — same role as `bash-history`/`web-history` for the `mcp-output` cache. |
106
+ | `token-goat skill-body <name>` | Retrieve a cached Skill body by name without re-invoking the skill (which would replay side effects). Prints the full body; `-c`/`--compact` prints the compact slice instead. No head/tail/grep slicers. |
107
+ | `token-goat skill-history` | List cached Skill bodies (newest first) with their IDs, byte sizes, truncation status, and skill names. |
108
+ | `token-goat skill-compact [name]` | Cache the compact slice for a skill so later `skill-body --compact` calls are instant, and print a confirmation. Resolves an installed skill by name (falling back to `~/.claude/skills/<name>/SKILL.md` when it was never loaded this session), or pass `--path <file>` to compact a skill straight from a file without name resolution. |
109
+ | `token-goat skill-compact --all` | Batch-regenerate stale or missing compacts for every skill cached in the current session. Skips skills whose compact is already fresh (source SHA matches). The summary also counts skills that have no `COMPACT_END` marker (with a pointer to `token-goat skill-size` for per-skill recommendations) and skills whose source file no longer resolves, so the pass reports every skill it visited. Run after updating any skill file on disk. |
110
+ | `token-goat skill-list [--session-id <id>]` | List all skills cached in the current (or specified) session with body token count, compact availability, compact_stale status, hit count, and age. |
111
+ | `token-goat skill-list --json` | Machine-readable version; each skill row includes `compact_stale` (true/false/null) — true means the compact's embedded source SHA no longer matches the body's current SHA and a `skill-compact <name>` regeneration is recommended. |
112
+ | `token-goat skill-size` | Show per-session token overhead for all cached skills, with restructure recommendations. |
113
+ | `token-goat skill-diff "<name>"` | Unified diff between the two most recent cached versions of a skill — tracks skill updates across sessions. |
114
+ | `token-goat compact-hint --session-id <id>` | Inspect the compaction manifest for a session. Add `--trigger auto` to preview the pressure-aware budget the live PreCompact hook would use. |
115
+ | `token-goat resume <session_id>` | Emit a single post-compact recovery packet — top skills, last two Bash outputs, top edited-file diffs, and `git diff --stat`, capped at ~2000 tokens. Replaces 5-10 round-trips. |
116
+ | `token-goat config list / get / set / validate` | Inspect or edit `config.toml` from the CLI. `validate` reports unknown keys with did-you-mean suggestions, plus any project-file or environment value that validation rejected or clamped. A project-root `.token-goat.toml` layers on top of the global config, overriding hint thresholds, indexing settings, etc. for that project only. It may not set the security sections `injection`, `webfetch`, `gdrive`, or `mcp`, nor `indexing.cross_project_symbols`: that file arrives with the repository, so a cloned project could otherwise switch off prompt-injection fencing or empty the fetch allow list for anyone who opened it. Those settings come from the global config or the environment only, and a project file that tries to set one is ignored with a message naming what was dropped. `config get`/`list`/`set` report which layer a value actually resolved from — the project file, an environment variable, or the global config — and where that layer's value was clamped or rejected they say so, naming what was asked for and what is in effect instead. |
117
+ | `token-goat config-get <file> <key>` | Look up one key from a config-shaped file (TOML/INI `key = value`, or YAML) without reading the whole thing. On a `.md` file, a leading `---`-fenced YAML frontmatter block (Jekyll/Hugo/SKILL.md style) is checked first and takes precedence over the TOML/INI fallback; a `.md` file with no frontmatter, or an unclosed fence, falls through to the normal lookup unchanged. |
118
+ | `token-goat pdf-extract <file>` | Extract plain text from a PDF instead of a raw Read. `--pages <spec>` narrows to a page range (e.g. `1-5` or `3`); `--head`/`--tail`/`--grep`/`--max-matches`/`--section` slice the extracted text the same way `bash-output`/`web-output` do. `--layout` heuristically reconstructs column-aware reading order from text-item coordinates instead of raw content-stream order (imperfect on rotated/overlapping text). |
119
+ | `token-goat pdf-locate <file> <pattern>` | Find which pages of a PDF match a regex, with a snippet per match, so you can `pdf-extract --pages` only those pages instead of pulling the whole document. `-i`/`--ignore-case` for case-insensitive matching; `--max-matches <n>` caps how many page matches to collect (default 50); `--context <n>` sets the snippet length around each match (default 80); `--pages <spec>` narrows the scan to a page range; `-j`/`--json` emits `{ file, pattern, matchCount, pages, matches }`. |
120
+ | `token-goat pdf-outline <file>` | List a PDF's bookmark/outline tree with page numbers instead of a raw Read. |
121
+ | `token-goat pdf-meta <file> [--json]` | Page count, title/author, and whether a PDF has an extractable text layer (so you know before extracting whether it's scanned/image-only). `--json` emits `{ pageCount, title, author, hasTextLayer }` — `hasTextLayer` as a real boolean rather than a prose sentence, and an absent title/author as `null` rather than the literal `(none)`. |
122
+ | `token-goat image-meta <file> [--json]` | Dimensions, format, byte size, and what a `shrinkImage` pass would cost — a cheap "should I even look at this" probe that reads `sharp` metadata only and never runs OCR. Requires `sharp`; degrades with a clear message when it's missing. |
123
+ | `token-goat image-text <file> [--json]` | OCR text for an image instead of a raw Read. Reports confidence and character count either way; below the usefulness threshold it says so plainly instead of printing low-confidence noise as content. Requires `tesseract.js`; degrades with a clear message when it's missing. |
124
+ | `token-goat csv-query <file>` | Project columns and/or filter rows from a CSV instead of a raw Read. `--columns <cols>` selects a comma-separated subset; `--where <spec>` is repeatable and ANDed, supporting `col=value`, `col!=value`, `col>value`, `col<value`, and `col~=regex`; `--head <n>` caps rows; `--json` emits rows as a JSON array of objects instead of a formatted table; `--delimiter <char>` and `--no-header` handle non-comma or headerless files. |
125
+ | `token-goat csv-profile <file>` | Per-column type inference (number/date/string), null/distinct counts, and min/max or top values for low-cardinality columns, instead of a raw Read. Same `--delimiter`/`--no-header` flags as `csv-query`. |
126
+ | `token-goat sharepoint-resolve <shareUrl>` | Best-effort resolve a SharePoint/OneDrive sharing URL to a local synced file path, purely from the local filesystem and `OneDrive`/`OneDriveCommercial` env vars -- no network call, no Graph API, no credentials. Prints the resolved path (feed it to `xlsx-sheets`/`pptx-outline`/etc.) or an honest "could not resolve" with the paths it tried. |
127
+ | `token-goat video-chapters <file>` | Lists a video's embedded chapter markers (timestamps + titles) and subtitle/caption streams via `ffprobe`, instead of downloading/transcoding the file to inspect it. Requires ffmpeg on PATH; degrades with a clear message when it's missing. |
128
+ | `token-goat xlsx-sheets <file> [--json]` | List sheet names, used range, and dimensions in an Excel workbook instead of a raw Read. `--json` emits `{ name, ref, rows, cols }[]`, so a sheet name can be fed straight into the `--sheet` of `xlsx-head`/`xlsx-range`/`xlsx-query` instead of being parsed back out of the text line. |
129
+ | `token-goat xlsx-head <file> --sheet <name>` | Preview the header + first N rows of one sheet (`--rows`, default 20) instead of a raw Read. |
130
+ | `token-goat xlsx-range <file> --sheet <name> --range <a1>` | Extract one cell range (e.g. `A1:D50`) from a sheet; `--formulas` shows formulas instead of computed values. |
131
+ | `token-goat xlsx-query <file> --sheet <name>` | Project columns / filter rows from one sheet instead of a raw Read (same `--columns`/`--where`/`--head` shape as `csv-query`, via the sheet's CSV projection). |
132
+ | `token-goat pptx-outline <file>` | Per-slide title, body size, and speaker-notes flag instead of a raw Read. |
133
+ | `token-goat pptx-slide <file> --slide <n>` | Full text of one slide; `--notes` appends that slide's speaker notes. |
134
+ | `token-goat pptx-notes <file>` | Speaker notes for one slide (`--slide <n>`) or all slides, instead of a raw Read. |
135
+ | `token-goat pptx-text <file> --grep <pattern>` | Find slides whose text matches a pattern instead of a raw Read. |
136
+ | `token-goat docx-outline <file>` | Heading tree of a Word document instead of a raw Read. |
137
+ | `token-goat docx-text <file>` | Full body text of a Word document instead of a raw Read; `--head`/`--tail`/`--grep`/`--section`/`--max-matches` slice it the same way `pdf-extract` does. |
138
+ | `token-goat transcript-outline <file>` | Speaker list, duration, and time-bucketed markers for a WebVTT/SRT transcript instead of a raw Read. |
139
+ | `token-goat transcript <file>` | Slice a WebVTT/SRT transcript by `--speaker <name>`, `--from`/`--to <hh:mm:ss>`, and/or `--grep <pattern>` instead of a raw Read. |
140
+ | `token-goat screenshot <url> <destPath>` | Capture a local headless-browser screenshot, shrunk the same way local image reads are (image-shrink pipeline). `--executable-path` overrides the Chrome/Chromium binary; `--width`/`--height` set the viewport (default 1280x800); `--full-page` captures the full scrollable page. Only `http:`/`https:` targets are allowed, and loopback/link-local/private/cloud-metadata addresses are refused by default (`screenshot.block_private_targets`, env `TOKEN_GOAT_SCREENSHOT_BLOCK_PRIVATE_TARGETS`) — see [Security, privacy, and uninstall](security.md) for what that check does and does not cover. |
141
+ | `token-goat clean-cache` | Prune on-disk caches to their configured floor without waiting for the worker. |
142
+ | `token-goat reclaim-index` | Shrink an oversized symbol index (`VACUUM` + WAL checkpoint). `--rebuild` also drops every derived row — files/symbols/refs/chunks — so the next `token-goat index` re-derives them under current parser rules, which is what actually reclaims space held by rows a since-fixed extractor wrote too large. Refuses to run while the worker daemon is writing to the index unless `--force`. `token-goat doctor` points here when `global.db` grows past 1 GB, and separately when it finds a stored symbol body above the parser's own size cap — a leftover from a since-fixed extractor bug, which only `--rebuild` can clear (a plain `VACUUM` reclaims freed pages but never deletes row content). |
143
+ | `token-goat prune-cache` | Manually trigger LRU eviction across all cache directories (images, bash, web, skills). |
144
+ | `token-goat session-summary` | Compact one-liner about current session state — designed for orchestrators and multi-agent loops. |
145
+ | `token-goat cache-audit` | Audit your Claude Code config for patterns that bust the prompt cache. |
146
+ | `token-goat pack <patterns>` | Collect files matching glob patterns into a single LLM-ready output — Markdown (default), XML, or plain text — with a manifest table of per-file line and token counts. `--line-numbers` prefixes each line; `--instruction-file` appends a task prompt; `--output` writes to a file; `--no-ignore` bypasses `.tokengoatignore`. `--strip-comments` removes language-appropriate comments before packing (shebangs preserved; `#` inside string literals is a known limitation). `--scan-secrets` checks for credentials and exits 2 with per-file warnings if any are found. `--budget N` exits 3 when the estimated token count exceeds N — lets a shell script treat an oversized context as a hard error. Reads file paths from stdin when no patterns are given. |
147
+ | `token-goat budget <patterns>` | Estimate the token cost of a file set without reading them into context. Prints results sorted by cost descending; `--context <N>` shows each file as a share of an N-thousand-token window. `--json` for machine-readable output. Run before `pack` to decide what to include. |
148
+ | `token-goat tokens [patterns]` | Per-file token footprint table, sorted largest-first. `--tree` groups by directory with subtotals and percentage of total. `--top N` limits to the N biggest files. `--asc` reverses order. `--json` for structured output. Omit patterns to scan the whole project. Useful for deciding what to exclude before running `pack`. |
149
+ | `token-goat todo` | Scan indexed project files for `TODO`, `FIXME`, `HACK`, `XXX`, and `NOTE` comment markers. Groups by file by default; `--group kind` to group by marker type; `--kinds` to filter to a subset; `--json` for machine output. Markers in string literals are excluded. |
150
+ | `token-goat failures [src]` | Extract failing test blocks from test runner output (pytest, Jest, Go, Cargo). Passes and preamble are dropped; each failure comes back as a labeled block. Reads stdin by default; pass a file path for saved output. `--json` for structured output. |
151
+ | `token-goat trace [src]` | Condense a stack trace/traceback/panic to project-owned frames. Auto-detects and parses Python tracebacks, Node.js/V8 stack traces, Rust panics (including `RUST_BACKTRACE=1` backtraces), and JVM (Java/Kotlin/Scala) and .NET exceptions -- even mixed together in one input (e.g. a CI log with both a Python and a Node error). Strips library, stdlib/runtime-internal (`node:...`), and dependency (site-packages, rustc-internal, Cargo registry) frames; chained exceptions (Python's chained tracebacks, JVM's `Caused by:`) preserve cause notes as separate blocks; bare exceptions without a message are handled. `--keep N` (default 5) caps the frame count. `--bodies` resolves each surviving frame to its enclosing symbol and prints the actual code body (same lookup `scope`/`read`/`symbol` use), so a traceback is directly readable without a separate lookup per frame; recursive frames show the body once with `(same as above)` on repeats. `--json` for structured output. |
152
+ | `token-goat conflicts [path]` | Unresolved git merge-conflict markers (`<<<<<<<` / `\|\|\|\|\|\|\|` / `=======` / `>>>>>>>`, two-way or diff3 three-way) instead of a raw Read or grep. `path` may be a file, a directory (scanned recursively), or omitted entirely (scans the whole project); only files with at least one conflict region or malformed-marker warning are reported. `--summary` narrows each region to its line range and side labels, omitting the full ours/base/theirs content. `--json` for structured output. |
153
+ | `token-goat coverage-report-gaps <file>` | Extract uncovered lines/branches/functions from an LCOV or Istanbul coverage report instead of scanning the raw file. Auto-detects format; collapses consecutive uncovered lines into ranges; drops fully-covered files. `--file <path>` filters to one file; `--json` for structured output. |
154
+ | `token-goat zip-list <archive>` | Entry paths and sizes inside a zip-format archive (`.zip`/`.jar`/`.whl`/`.vsix`/`.nupkg` are all zip containers under the hood) instead of a raw Read or an `unzip -l` shell-out. Reads the central directory only — no member is decompressed just to list it. `--json` for structured output. |
155
+ | `token-goat zip-read <archive> <entry>` | Extract and print exactly one entry's text content from a zip-format archive by its in-archive path, instead of extracting the whole archive to disk. A binary member prints a `[binary content elided by token-goat]` marker instead of raw bytes. |
156
+ | `token-goat pr-slice <pr>` | Surgical GitHub PR reads via `gh` — one file's diff, a single review-comment thread, the description, or CI check statuses, instead of pulling the whole PR payload into context. |
157
+ | `token-goat bridges-status` | Parity matrix of which hooks/commands are wired for each supported harness (Claude Code, Codex, opencode, openclaw, Grok, etc.), side by side. A `verified` column says how each row was established — `dogfooded` (driven against the real harness binary), `sourced` (read out of the harness's own source or declarations), or `documented` (from its docs only) — so a claim built from reading alone is never presented as one that was tested. |
158
+ | `token-goat commands` | Machine-readable manifest of every registered command, its description, options, and arguments (including subcommands like `worker start`). `--json` emits it as structured JSON for external tooling (shell completion, doc generators, scripts) instead of the default text listing. `--grep PATTERN` narrows the manifest to commands whose name, description, or aliases match; a parent command that matches keeps all its subcommands, a parent that only has a matching child keeps just that child; no matches prints `no matches` and exits 0. |
159
+ | `token-goat mcp-serve` | Run token-goat as an MCP stdio server exposing all 18 tools: read/symbol/section/outline/skeleton/semantic/index_status/refs/brief/map/changed/grep/imports/exports/compress_text/retrieve_text/handoff_create/handoff_resolve. |
160
+ | `token-goat version` | Print the token-goat version. |
161
+ | `token-goat statusline` | Claude Code statusline command surfacing session stats (bytes saved, hint efficacy, cache hit rate) inline in the terminal. |
162
+ | `token-goat lockdeps [path]` | Summarize lock file dependencies as a compact table. Reads poetry.lock, uv.lock, requirements.txt, Pipfile.lock, package-lock.json, Cargo.lock, and yarn.lock. Direct dependencies only — optional and transitive entries excluded. `--json` for structured output. |
163
+ | `token-goat logfold [src]` | Collapse consecutive duplicate log lines. Runs of identical or structurally equivalent lines fold to `[Nx] line`. Normalizes timestamps, UUIDs, IPs, hex IDs, and bare integers (counters, PIDs, ports, byte counts) before comparing so the same event with different values folds correctly. `--tail N` keeps last N lines; `--no-normalize` disables normalization; `--fold-repeats` also folds non-consecutive duplicates anywhere in the input, attributing the total count to the first occurrence (capped at 20,000 distinct keys, past which it falls back to consecutive-only); `--json` for structured output. |
164
+ | `token-goat hot [--limit N]` | Cross-session file frequency table: read and edit counts tallied from all stored sessions, ranked by total activity. Shows which files dominate your token spend across your entire history. `--project <dir>` filters to one project; `--json` for structured output. |
165
+ | `token-goat note set/get/unset/list/clear` | Persistent per-project notes stored as key-value pairs. Token-goat injects them at session start and after compaction so they survive conversation rollover. Use to pin decisions, constraints, or reminders that would otherwise vanish after compaction. `note list --json` for machine-readable output; `note clear` removes everything at once. |
166
+ | `token-goat project list` | Show all project roots indexed by token-goat with their file counts. Roots on the blocklist appear tagged `[excluded]`. `--json` for structured output. |
167
+ | `token-goat project exclude <path>` | Add a project root to the blocklist so the worker never indexes it. Writes the resolved absolute path to `[worker] blocked_roots` in `config.toml`; idempotent. It also removes anything already indexed under that path and says how many files went, so excluding a directory means its contents stop being readable through `symbol` rather than merely stopping future indexing. Remove the entry from the config to re-enable indexing, then run `token-goat index` to bring the contents back. |
168
+ | `token-goat project prune [--dry-run]` | Remove blocked/excluded roots that no longer exist on disk. `--dry-run` previews removals without touching the config file. Useful after deleting or moving projects. |
169
+ | `token-goat install` | Wire up hooks (and, with the harness flags below, other AI tool integrations). No `--dry-run` or `--verify` flag — run `token-goat doctor` after install to audit the result. |
170
+ | `token-goat doctor` | Confirm everything is wired correctly. Surfaces install state, cold-import timing, cache hit rates, compaction-budget telemetry, opt-in flag status, and canonical-root sanity. A **Tool names** check reports any tool name a harness sent that reached no handler wanting it, and calls out the ones that differ from a handled name only by capitalisation or punctuation — the signature of a bridge that forgot to rename something, which is otherwise invisible. A **Security** section reports the posture in one place: whether offline mode is on, whether injection scanning is on, whether the Google Drive integration is enabled, whether fetching runs against an allow list or a deny list, whether MCP reads are confined to the project root, and whether the data directory is readable by other local users. It only warns when a protection that ships on has been switched off, so a default install stays quiet. It read-only audits `~/.copilot/mcp-config.json` for globally configured Chrome DevTools or Playwright `npx` launchers, recommending project scope or removal when inactive; it never prints server configuration or secrets. On Windows, it also reports duplicate Chrome DevTools/Playwright MCP launchers and orphaned Node processes without terminating anything. Pass `--context` to show the **Context footprint** section: a fill bar with severity (ok / warn / high / URGENT), per-component breakdown (skills catalog, loaded skill bodies, CLAUDE.md+MEMORY.md, conversation estimate), session-to-session growth trend with sessions-to-URGENT projection, and tiered compaction recommendations (Tier 0–4) naming the exact commands to run. Auto-shown when fill > 40 % or any loaded skill > 2 K tokens lacks a compact. `--json` emits the check results (one entry per check, with `ok`/`warn`/`fail` status) as JSON instead of text. |
171
+ | `token-goat capabilities` | List every capability that can send data off this machine or leave data on it, with whether it is currently on, the config key that decides that, and the exact `file::symbol` where the decision is made — so a reviewer can open the code rather than take the list's word for it. `--json` emits the same thing for a pipeline to assert on, which is the point: the answer comes from the binary installed on your machine, not from documentation that may describe a different build. A test in the suite fails the build when a module that can open a network connection is missing from this list, and equally when the list names one that no longer connects anywhere. |
172
+ | `token-goat baseline` | Emit a project map: file count, per-language file counts, the top indexed symbols (by name/kind/location), and the most recently modified files. `--subagent` emits a terser variant (fewer symbols, fewer recent files) for context handed to a freshly spawned subagent; `--json` for the machine-readable form. |
173
+ | `token-goat compact-doc <path>` | Build an extractive compact sidecar for a large reference doc (`.md`/`.markdown`). The compact is stored in the token-goat data dir as a SHA-keyed sidecar; `pre_read` serves it in place of the full file when it exists and is fresh, saving 80–95% of context tokens. Use `--force` to rebuild, `--sentences N` to control lines per section (default 2), `--show` to print the result. The sidecar is automatically marked stale when you edit the source file. Config: `[hints] stable_doc_compacts = true` (default on). |
174
+
175
+ Missed lookups recover surgically: `read` and `section` print a "Did you mean…?" list on a miss, and `section` auto-redirects on an unambiguous heading-prefix match — a typo costs at most one extra glance, not a re-read.
176
+
177
+ ### Skill efficiency — the `<!-- COMPACT_END -->` marker
178
+
179
+ When Claude Code invokes a skill, it re-injects the full skill body on every subsequent turn. A large skill file (e.g. a 10k-token `/improve` or `/ralph`) can cost 40–65k tokens per session across 6 active skills. The `<!-- COMPACT_END -->` marker solves this: place it in any skill file to split it into a compact form (above the marker, ~400 tokens) and a reference section (below). Token-goat detects the marker the first time the skill fires, caches only the compact slice, and injects that from then on — labeled `--- compact form (N tokens) ---` so the model knows to request the full body only when it needs the detail.
180
+
181
+ To add the marker to a skill, open the file and insert `<!-- COMPACT_END -->` on its own line where the "quick reference ends and the detail begins" — typically after the quick-start table and before step-by-step instructions. The full reference section is still reachable via `token-goat skill-section "<name>::<heading>"` or `token-goat skill-body <name>` when needed.
182
+
183
+ **Re-load and direct-read protection.** Even without the marker, token-goat protects against the two other ways large skills burn context in a long session:
184
+
185
+ - If the model tries to `Read` a skill file directly (`~/.claude/skills/improve/SKILL.md`), the pre-read hook intercepts it and emits a `token-goat skill-body improve` hint instead — the full 10k–65k tokens never enter context.
186
+ - If the same skill is invoked a second time in the session (e.g. `/improve` called again after a `/compact`), re-load detection fires: instead of re-caching the full body, token-goat emits the cached token count and `skill-body`/`skill-section` recall hints. The model can retrieve any section it actually needs rather than absorbing the whole skill again.
187
+
188
+ To check overhead for your current skills: `token-goat skill-size`. To inspect compact freshness, run `token-goat skill-list` — the `compact_stale` column shows `[stale]` when a skill's compact was generated from an older version of the file. Run `token-goat skill-compact --all` to refresh every stale compact in the current session in one pass.
189
+
190
+ `token-goat install` now pre-generates compacts for all installed skills as its final step, so compacts are ready from the first session. If you install new skills after the initial install, run `token-goat skill-compact --all` manually — or check `token-goat doctor --context` which reports how many skills were added since the last pre-gen pass and shows the exact command to run.
191
+
192
+ ### Memory analysis and cleanup
193
+
194
+ `token-goat memory` audits the `CLAUDE.md` files Claude Code loads for a project for wasted tokens: exact-duplicate lines within one file, duplicate headings, content that overlaps verbatim across files, and near-duplicate sibling auto-memory files (`~/.claude/projects/<slug>/memory/*.md`). Default mode is `--analyze` (read-only):
195
+
196
+ ```
197
+ $ token-goat memory
198
+
199
+ # token-goat memory
200
+ Project: C:\Projects\example
201
+
202
+ ## CLAUDE.md files (1)
203
+
204
+ C:\Projects\example\CLAUDE.md (842 tok)
205
+ exact-duplicate lines: 1
206
+ line 40 duplicates line 12: "Always run the full test suite before committing."
207
+ duplicate headings: none
208
+ cross-file overlaps: none
209
+
210
+ ## Duplicate-content clusters (sibling auto-memory files)
211
+ none
212
+ ```
213
+
214
+ `--fix` builds on `--analyze`. The only change it can apply automatically is removing exact-duplicate lines (keeping the first occurrence) — a pure structural dedup with no judgment call. Duplicate headings and cross-file overlaps are printed as advisory findings only; they often mean content should move into a path-scoped `.claude/rules/` file or a subdirectory `CLAUDE.md`, but token-goat never picks where for you, so no diff is proposed for those.
215
+
216
+ Every proposed exact-duplicate-line fix is shown as a diff before anything is written, gated by the same confirm-before-write flow: pass `--yes` to apply non-interactively (scripts, CI), or run it from a terminal without `--yes` to be prompted per file. Running `--fix` without `--yes` from a non-interactive shell (no TTY) prints the diffs as a dry run and writes nothing.
217
+
218
+ ### Session waste ledger
219
+
220
+ `token-goat waste` parses the current project's Claude Code session transcript — the JSONL file Claude Code writes under `~/.claude/projects/<slug>/*.jsonl` — and attributes token cost to every tool call in it, then flags a few concrete waste signals: files that were `Read` once and never referenced again, and Bash commands run repeatedly without ever hitting token-goat's own bash-output cache. By default it auto-discovers the most-recently-modified transcript for the current project; pass `--transcript <path>` to point at a specific one instead (useful when several sessions are open, or for CI/testing):
221
+
222
+ ```
223
+ $ token-goat waste
224
+
225
+ # token-goat waste
226
+ Transcript: C:\Users\you\.claude\projects\C--Projects-example\a1b2c3d4-....jsonl
227
+ Total tokens: 18420
228
+
229
+ ## Tokens by tool
230
+ Read: 9120 tok
231
+ Bash: 6210 tok
232
+ Grep: 2140 tok
233
+ Edit: 950 tok
234
+
235
+ ## Top expensive tool calls
236
+ [3400 tok] Read: src/big_module.ts
237
+ [1800 tok] Bash: npm test
238
+
239
+ ## Read once, never touched again
240
+ src/unrelated_helper.ts: 640 tok, never referenced again
241
+
242
+ ## Repeated Bash commands not hitting the token-goat cache
243
+ "git status": ran 4 times, 210 tok each, 840 tok total, uncompressed
244
+
245
+ ## Assistant output (re-send CEILING, not real spend)
246
+ 42 turns, 21300 tok generated
247
+ Re-send upper bound: 187400 tok if every turn were resent at full price on every later request
248
+ Real cost is substantially lower: prompt caching bills resent conversation history at cache-read rates, not full input price.
249
+ ```
250
+
251
+ `--top <n>` controls how many entries appear under "Top expensive tool calls" (default 10). `--json` prints the same report as machine-readable JSON instead.
252
+
253
+ `--copilot` reads a GitHub Copilot CLI session instead, from `<copilot-home>/session-state/<id>/events.jsonl`. It is a different report rather than the same one with different inputs, because Copilot writes down its own token accounting at shutdown and token-goat reports those numbers rather than estimating them:
254
+
255
+ ```
256
+ $ token-goat waste --copilot
257
+
258
+ ## Per-request fixed overhead (Copilot's own token counts)
259
+ System prompt: 8,981 tok
260
+ Tool definitions: 11,548 tok
261
+ Conversation: 722 tok
262
+
263
+ ## Tool definitions by MCP server (estimated)
264
+ github-mcp-server: 6 tools, 6 KB, ~2,135 tok
265
+ ~2,135 tok estimated across 1 server, re-sent every request.
266
+ Copilot counted 11,548 tok of tool definitions in total, so this is roughly 18.5% of it.
267
+ ```
268
+
269
+ The fixed overhead is the largest number in a Copilot session and no hook can reach it: Copilot assembles the system prompt and the tool definitions natively, with nothing between assembly and send. Only configuration moves it. The per-server breakdown exists to make that configuration decision possible, since one aggregate says the tool definitions are expensive without saying which tools. It is read from Copilot's own MCP tool cache, counts only the fields a model is actually sent, and is labeled an estimate throughout: it comes from byte length rather than Copilot's tokeniser, and it deliberately does not add up to Copilot's total, because Copilot's own built-in tools are not cached there.
270
+
271
+ The "Assistant output" section is separate from the tool-call ledger above it: `generatedTokens` is what was actually paid, once, to produce the assistant's own text turns. `resendCeilingTokens` is a cache-unaware upper bound on how much re-sending those turns as conversation history on every later request could cost — not real spend, since Claude Code's prompt caching bills a repeated conversation prefix at cache-read rates, a fraction of full input price. Treat it as a ceiling on how bad unbounded verbosity could get, not as a dollar figure.
272
+
273
+ ### Cross-cache recall
274
+
275
+ `token-goat recall "<query>"` searches every cached bash-output, web-output, and mcp-output entry at once, so you don't need to remember which cache type holds the result you want — a single full-text query ranks hits across all three:
276
+
277
+ ```
278
+ $ token-goat recall "eslint warnings"
279
+
280
+ [bash] a1b2c3d4e5f6a7b8 (token-goat bash-output a1b2c3d4e5f6a7b8)
281
+ npx eslint src tests
282
+ npx eslint src tests\n[token-goat: delta] 2 of 5 prior issues resolved; remaining: 3
283
+
284
+ [mcp ] mcp_9f8e7d6c5b4a3210 (token-goat mcp-output mcp_9f8e7d6c5b4a3210)
285
+ mcp:mcp__plugin_github_github__get_check_runs {"owner":"..."}
286
+ ... eslint warnings found in 2 files during CI ...
287
+ ```
288
+
289
+ Results are ranked by relevance (BM25 via SQLite FTS5, falling back to a plain substring scan if FTS5 is unavailable), newest indexed entries win ties. `--type bash|web|mcp` narrows to one cache type; `--limit <n>` caps the result count (default 10); `--json` emits `{ id, cacheType, label, snippet, storedAt }[]` instead. The index is built incrementally as entries are cached — there is no separate rebuild step.
290
+
291
+ Run `token-goat recall` with **no query** to browse instead of search: every cached entry across all three types, newest first, in the same format and honoring the same `--type`/`--limit`/`--json` flags. This is the case where the index matters most — the ids have scrolled out of context and you have no term to search for, so the alternative is running `bash-history`, `web-history`, and `mcp-history` in turn.
292
+
293
+ ### Hint efficacy tracking
294
+
295
+ Every hint hook (the re-read/dedup/surgical-read nudges in the Bash, Read, and Edit hooks) is
296
+ worth its keep only if it's actually followed. `token-goat hint-stats` reports, per hint
297
+ category: how many times it fired, how many times a later Bash command in the same session
298
+ actually invoked the specific `token-goat` command (or referenced the specific cached-output id)
299
+ the hint pointed at, the resulting efficacy percentage, whether the category is currently
300
+ auto-suppressed, and the `spent` column (bytes of hint text actually injected into context for
301
+ that category — the real cost of emitting it, not just how often it fired):
302
+
303
+ ```
304
+ $ token-goat hint-stats
305
+ category emitted acted-on efficacy suppressed manual+ manual- spent
306
+ bash_redirect 42 9 21.4% no 0 0 3150
307
+ bash_recall 18 15 83.3% no 0 0 1080
308
+ read_reread_dedup 11 2 18.2% no 0 0 660
309
+ read_structural_nav 7 1 14.3% yes 0 1 420
310
+ edit_reread_suggest 3 0 0% no 0 0 180
311
+
312
+ TOTAL saved=48200 spent=5490 net=42710
313
+ ```
314
+
315
+ `spent` (and the `TOTAL` line's `spent`/`net`) render `n/a` instead of a fake `0` whenever a
316
+ category — or, for the total, the whole store — has no tracked spend figure at all: either
317
+ nothing has fired yet, or every emission predates this feature and was recorded before spend
318
+ tracking existed. A partially-tracked category shows the real sum plus how many legacy rows it
319
+ excludes, e.g. `120 (2 legacy)`, rather than silently blending unknown-cost rows into the total
320
+ as if they cost nothing.
321
+
322
+ A category is auto-suppressed for its harness once it has at least `hint_stats.min_sample_size`
323
+ emissions (default 5) AND its efficacy falls below `hint_stats.suppress_threshold_pct` (default
324
+ 15%) — the sample-size floor exists so a category is never suppressed off a single unlucky
325
+ emission. Once suppressed, that hook stops emitting that category until `token-goat hint-stats
326
+ --reset` clears the tracked data. Configure both knobs with `token-goat config set hint_stats.min_sample_size <n>` / `token-goat config set hint_stats.suppress_threshold_pct <pct>`.
327
+
328
+ "Acted on" is a real, session-scoped signal (the exact file path or cached-output id the hint's
329
+ own text pointed at is checked against the next few tool calls in that session) — not a guess —
330
+ but it is a proxy for correlation, not proof of causation: a match means the agent ran the
331
+ suggested command shortly after the hint, not that the hint necessarily caused it. A hint whose
332
+ text has no extractable path/id (a small minority of branches) is counted as emitted with no
333
+ automatic "acted on" credit. `--mark-effective <category>` / `--mark-ineffective <category>`
334
+ record a separate manual vote as a human override/supplement for exactly that gap — manual votes
335
+ are shown alongside the automatic percentage but never blended into it. `--json` emits
336
+ `{ category, emitted, actedOn, efficacyPct, suppressed, manualEffective, manualIneffective }[]`.
337
+ Note that what this feature calls "harness" (Claude Code, Codex, Gemini, ...) is not the same as
338
+ "which LLM model" — no bridge in this codebase exposes an LLM model identifier to hooks, so
339
+ harness is the closest real signal available.