grain — ask the repository which exemplar to copy
grain has mined this repository's syntax trees and whole git history into a model of what is practiced here: the
groups of similar code, where they live, what they import, extend, decorate, return, how they are named, which
files historically change together, the recurring shapes of past commits, and the values (enum members, string
literals) that travel together. It does not replace reading one good exemplar — it replaces guessing which one,
and it catches the departure you would not have noticed.
Run it
From the repository root, through Bash:
node "${CLAUDE_PLUGIN_ROOT}/bin/grain.mjs" <command> …
Run it as-is from the session's working directory — no leading cd (the sandbox may refuse the cd, and grain finds
the repository root itself; --repo <path> points it at another checkout). Every answer ends with as of <sha> (the
commit the model was computed from); +dirty means the file you asked about was read from your uncommitted worktree. A missing or stale index builds/refreshes itself before answering
(full history once, incremental afterwards) — let a slow first run finish.
Four questions
Everything below reduces to four questions. Each has a command you can ask directly, and — for three of them — a
moment where grain already asks it for you, unbidden:
| Question |
Ask |
Grain already asks it |
| Where does this belong, and what's expected there? |
where <intent> — once, with the repo's own words |
before you Write a new file (placement note, from the path alone) |
| How has a change like this actually been done here before? |
how <intent> — cites real commits, not a guess |
before your prompt is even read, when it resembles a certified shape or clearly matches past changes (see below) |
| What already IS this concept in this codebase? |
what <words> — declarations, values, spread, siblings, commit mentions |
nothing automatic — this one is always a deliberate call |
| Does my change conform to the local norm? |
check <file> / check (whole change) / review |
after every edit, and before a git commit runs |
Not a trigger for any of these: reading, investigating, answering questions, touching config or docs.
The voice rule
Every line grain prints as a claim carries one of four voices, marked identically in every command, so you never
have to infer authority from wording:
- practiced — the statistical claim, unmarked (
methods here always call \validate()` — 91% of 120`). The
default; the only voice allowed to carry no marker at all.
- decided — a maintainer's committed override,
decision <typ> (<who> <when>): … (a catalog listing in
report/rules adds the id: decision <typ> (id <8-hex>, <who> <when>): …). The numbers may still disagree —
that is the point. Follow it anyway and say in one line that you did.
- example — one real historical instance,
example (<sha>[ <YYYY-MM>]): "…" (date present on how's commit
citations, sha-only on a history-mention line), never a certified convention.
Follow the files it names, not the words in the message.
- map —
map: …, a structural overview of where things live, not an assertion about how they are written.
Silence is not approval. A hook saying nothing after an edit, a read, or your own prompt means grain had
nothing certified to add — not that it reviewed your work and found it clean. Never re-run a command just to
confirm a silent edit, and never report silence to a user as "verified against the repository's conventions."
How to phrase where
Use the repository's own vocabulary, not yours: the decorator you expect (click.command, Injectable), the base
type (MethodView, IRequest), the file or function name you would look for (response json, cli routes), the
directory word (middleware, extract). Hits come in four kinds — group (similar code, with its conventions),
marker (@decorator / extends X / returns X — where its carriers live), directory, file (with the
matching functions inside it). There is no test/example special-casing: code is code, and a test file CAN out-rank the
source it tests when it matches your words better — for a source change, take the source hit even when it sits second
or third.
- One
where per intent. If it prints the compact map, grain has no lexical hit: pick the closest entry
yourself and open its files. Do not re-ask with synonyms.
note: the top hit matches only «word» of your N words at the top means the ranking is driven by a fraction of
your query — verify before building on it.
- Every card opens with an
in: <module> line (its dependency layer and how many modules depend on it, once the
architecture graph has one — see map below) and a superposition: line: the members laid on top of each
other, the skeleton they share, the slot each fills differently, the skewed ones, the fleet's age. a new member comes with: is the recipe for a new instance. twin: structurally the same as «B» … on a group card names a
role group elsewhere in the repo with the same shape, possibly under a different name.
- An
example (<sha>): "…" line (the old "history bridge") means your word never appears in the code,
but a commit saying it touched the listed files. Follow the files, not the word.
- Retrieval miss ≠ freedom. If every hit lands somewhere unrelated to what you are writing, that is a miss.
Re-ask once with an exact identifier or decorator from the file you expect to edit; if that misses too, open the
nearest sibling of that file and copy it.
- "No strong convention here beyond placement" means grain could not certify a convention at its acceptance
floor. It is not evidence that the neighbours vary. Open the listed exemplar.
How to ask how
how <intent words> answers by example, not by rule: which past commits look like the change you are about to
make, and which files a change like that actually touched, ranked k/K (K = how many of the cited commits touched
that file). When your intent clearly matches a recurring, certified shape of past commits, the answer opens with
that shape's cells ("<label>" (n changes): <cell> (k of n) · …) before the examples — a certified pattern, not
one anecdote. Zero matches falls back to where's own compact map, whole and unmodified — nothing is invented.
Cite the commits it names as evidence, not as instructions to follow verbatim.
How to ask what
what <words> is the concept card: what a word or phrase already IS here, distinct from where ("where should
new code go") and how ("what did past changes look like"). One card: defined: (declarations matching the
words), values: (enum members / string literals from the value index that match), spread: (which modules
carry it), siblings: (other values from the same enum/switch/object), changes: (commit mentions, with a
pointer to how for the shape), used by: (file-level fan-in). Ask it before extending an existing concept, to
see everything grain already knows about it in one place.
How to read check
- Deviations in your change come first, each with
n/N established evidence, the preference gap in bits, and
exemplars. 100% of 29 is a rule — follow it or say in one line why not. 85% of 240 is a tendency.
In this file, \x` (line N) conforms.names a neighbour in the same file to copy;(held since …, last reinforced …)says how old and how alive the rule is;not to copy:on awherecard names the members that deviate. A note endingdeviants get fixes N× more often` means leaving this one uncorrected has a measured, historical cost.
- Pre-existing deviations (scopes you did not touch) are folded into one line. They are not yours to fix;
--all lists them if you are asked to.
- Zero deviations is not a review. If the "conforms to" list is empty or grain says no convention governs the
file, grain knows nothing certified about this kind of file here — say that, or say nothing; never report it to the
user as "verified against the repository's conventions".
missing from your change: at the end names what your change is missing, not what it broke: a co-change
partner this repo's history usually touches alongside the files you changed (the only source a single-file
check <file> shows) — plus, for check's whole-change form and review, a companion file a new
marker-carrier usually comes with, a sibling value (kin:) the rest of an enum/set has that yours does not, and
a cell of a certified change shape (change shape:) your change leaves untouched. Silence means nothing is
missing — there is no "(complete)" line to look for.
decision waiver (<who> <when>): … on a deviation means a maintainer excused this ONE scope from this ONE
convention — the departure is deliberate, say so, and do not "fix" it.
- "This is the local default of this directory — the wider package's norm differs here" means a neighbourhood
habit, not a package-wide law.
- Partitions are style regions cut from the directory tree by compression, not by names —
examples/ or a test tree
usually ends up its own region and its facts stay scoped there (local (examples/)), but nothing is filtered by
name. If the only exemplar you get lives in an examples or test region and you are writing product code, prefer a
sibling in source and say so.
check with no file argument, and review, both mean "my whole uncommitted change" — one aggregated pass,
highest-stakes findings first. Run it when you consider a unit of work done, not just the last file you touched.
grain also speaks unbidden
Six hooks run mid-task, all silent on failure, none ever block:
- Before you
Write a new file, its path is checked against where its name-kin already live — a
[grain] placement: note names the kin directory with counts, weaker rival kin with theirs. It arrives while
changing the directory is still free: weigh it before writing, and if you place deliberately elsewhere, say so
in one line.
- After every
Edit/Write/MultiEdit, the file is re-checked and grain injects [grain] findings ONLY when
it has something on the lines you touched — deviations, maintainer decisions, architecture crossings, a
placement note — plus, on its own line and capped to 3 partners, the other files this repo's own history shows
reliably changing together with the one you just touched. That co-change line can fire even when nothing else
does.
- Before an
Edit/MultiEdit lands, the same co-change evidence for the file about to be touched arrives
ahead of the edit, while touching both halves of an established pair in one pass is still cheap. It shares its
repeat-suppression with the post-edit line above, so you see the pair named once, not twice, in one turn.
- After you
Read a file, if it is itself one of a convention's known deviants, grain says so once — "don't
copy that part" — and points at a conforming sibling elsewhere. Silence means either the file conforms, or it
is a deviant no fact ranks as a top-5 example worth citing.
- Before your prompt is even read, grain checks it against the repository's own history of past changes; if it
strongly resembles a certified change shape or clearly matches how a recognizable kind of change has been done
here before, it injects the certified shape's cells and the places such a change touched — silently, on
everything else.
- Before a
git commit runs (in a Bash tool call), grain reviews the whole staged (or, for -a, worktree)
change ahead of the commit — the same report review would print, budget-capped.
A host with no prompt-submission hook gets none of the how-hook behavior above (confirmed for Codex CLI at
the time of writing). Where this integration cannot inject anything before your prompt is read, start every task
by asking grain how <query> yourself before writing code.
Maintainer commands
report [--top N] / status — the model overview: size, freshness, signal verdict, top conventions with
trends and ages, the measured architecture (modules, dependencies, cycles), the check feedback rate (notes
acted on vs. ignored after warning), and a == health == section flagging conventions worth a decision: costly
deviations, rejected alternatives, conventions carried mostly by agent-authored code, under-adopted shapes,
conventions with several waivers already, dead steers. Every health line ends with a suggested grain decide …
— text, never an executed command.
rules [--out <file>] — the same data as report, rendered as a standalone Markdown document stamped with
the commit, for a maintainer or a coding tool with no terminal and no grain plugin. grain rules > CONVENTIONS.md
already works without a flag.
decide steer <path>#<name> --surfaces <pid,…> [--instead-of <pid,…>] --note "…" — record a maintainer
decision: promote one property of one exemplar repo-wide, in the committed .grain/seeds.jsonl. Capped at half
the real population (it cannot invent a convention nobody has written). When the user says "from now on prefer
X" / "we are moving to Y", offer to record it as a decide steer instead of editing files by hand.
decide boundary <from> --never-imports <to> --note "…" — an architecture decision: new imports crossing it
are flagged at edit time.
decide waive <path>#<name> --on <pid> --note "…" — excuse ONE named scope from ONE convention: check
reports the departure as deliberate instead of an accusation, and the counts still report it as non-conforming.
Refuses when the name is ambiguous — pick the exact scope grain lists.
decide list / decide rm <id> — the decisions in force / withdraw one.
status --json / report --json / export — the same answers as data, for harnesses and training
pipelines, not for a conversation. export dumps the whole model — every convention with its sites, anchors,
trends, groups, markers, co-change, certified change shapes, structural twins — see docs/reference.md for the
schema.
decide is the current name; seed add | add-boundary | list | rm is the same command under its original name —
same records, same effect.
Developer commands
explain <file> [--minbits N] [--top N] — only when the explicit question is "what is local versus global
around this file": the full lattice with no acceptance cut (NORM = accepted, obs = below the gate). Large;
not for a small edit. (spectrum is the same command under its original name.)
selftest [--json] — plants synthetic deviations into conforming exemplars and reports how many this repo's
own model catches: a public, repeatable number for this repository, not a claim taken on faith.
selftest --how [--last N] — a leave-one-out check of how's own precision/recall at predicting a past
commit's files, against a grep baseline, over the last N real commits; a validation procedure, not something to
run mid-task.
map [--json] — a structural overview: dependency layers from leaves to top, the repo's top concepts where
commit messages and code vocabulary agree, the certified change shapes, and how many maintainer decisions are in
force. Good for orienting in an unfamiliar repository before asking anything more specific.
propose [<out-dir>] [--full] [--json <path>] [--holdout <YYYY-MM-DD>] — for a repository with no
.yggdrasil/ yet: mine one. Writes a PROPOSED Yggdrasil architecture graph — node types, nodes, relations,
dependency cycles and mined rules, each with the evidence that produced it — into <out-dir> (default
.yggdrasil-proposal/, self-ignoring; the repository's own .yggdrasil/ is never written). The default
report is short on purpose: the architecture with its counts, the rules a real yg drill proved on this
repository's own code (zero false alarms, at least one caught violation), and the candidates that came close;
everything else is on disk and summarised in one counted line, with --full to print it. With no Yggdrasil
CLI (YG_BIN, or yg on PATH) nothing can be drilled, so nothing is enforced and the report says so. It is
a proposal: a human reviews it and moves it in. Never move it in, and never run yg check --approve, unbidden.
oracle record [--proposal <dir>] [--graph <dir>] [--name <n>] [--out <dir>] [--yes] / oracle score <name-or-dir> [--json] — after a proposal has been read and a graph accepted, the difference between the
two is a measurement oracle. record keeps it (both graphs' structure, the tracked paths each element
selects, and the correction: what was merged, split, renamed, dropped, added); score reports precision and
recall in both directions on the same Jaccard >= 0.5 bar the hand-written oracles are scored with. record
prints what it would store and where and writes NOTHING without --yes — relay that plan and wait, never
add --yes for the user and never pick a destination for them. It stores structure and paths, never file
contents, so scoring later needs no checkout.
advise [--json] [--graph <dir>] — the other direction from propose: for a repository that ALREADY has
a .yggdrasil/, what its own history and imports say about it. Two findings, at very different weights. A
place a finer cut beats on its own evidence is advice: one node owns a pile that is not one thing, and
the report names the node, its size and the directories on offer. Places that change together are not
advice and are deliberately not listed — measured on four hand-written graphs, that evidence names almost
nothing and what it names the graph usually already connects, so the report prints the count, how many are
unconnected, how concentrated they are, and what share of all pairs of places are connected anyway. Relay
those as numbers; never turn one into "add a relation here". --json hands over the whole document if the
user wants the data. It writes nothing and never touches the graph.
refresh [--full] — rebuild the index now (every query already auto-refreshes).
completeness <file…> — ask about files BEFORE editing them, or check several files against each other at
once: the other files this repo's own commit history shows reliably co-changing with the ones given. This is the
same evidence check/how's missing: co-change: line and the co-change hooks above already surface for an
active change; call it directly when there is no change yet to attach it to.
grain informs; it never blocks. No embeddings, no model calls, no network. A convention is a majority, not a
virtue, and uncommitted changes never feed the norm.
1---2name: grain3description: Ask the repository about its own conventions BEFORE writing code. Use whenever you are about to create a source file, add a class/function/handler/command/component/test, are unsure where something belongs, or want to know how a kind of change has been done here before — `grain where <intent>` names the directory, the group and the exemplar to copy; `grain obligation <path>` names what a new file there has historically had to come with; `grain how <intent>` cites the past commits that did something like it; `grain what <words>` reports what a concept already is here; `grain check <file>` shows where your change departs from the local norm; `grain completeness <file>` names co-changing files before you call a change done; `grain propose` mines a whole proposed Yggdrasil architecture graph for a repository that has none. Statistical answers from this repo's code and full git history; tells you which exemplar to open, never blocks.4---56# grain — ask the repository which exemplar to copy78grain has mined this repository's syntax trees and whole git history into a model of what is *practiced* here: the9groups of similar code, where they live, what they import, extend, decorate, return, how they are named, which10files historically change together, the recurring shapes of past commits, and the values (enum members, string11literals) that travel together. It does not replace reading one good exemplar — it replaces guessing which one,12and it catches the departure you would not have noticed.1314## Run it1516From the repository root, through Bash:1718```19node "${CLAUDE_PLUGIN_ROOT}/bin/grain.mjs" <command> …20```2122Run it as-is from the session's working directory — **no leading `cd`** (the sandbox may refuse the `cd`, and grain finds23the repository root itself; `--repo <path>` points it at another checkout). Every answer ends with `as of <sha>` (the24commit the model was computed from); `+dirty` means the file you asked about was read from your uncommitted worktree. A missing or stale index builds/refreshes itself before answering25(full history once, incremental afterwards) — let a slow first run finish.2627## Four questions2829Everything below reduces to four questions. Each has a command you can ask directly, and — for three of them — a30moment where grain already asks it for you, unbidden:3132| Question | Ask | Grain already asks it |33|---|---|---|34| Where does this belong, and what's expected there? | `where <intent>` — once, with the repo's own words | before you `Write` a new file (placement note, from the path alone) |35| How has a change like this actually been done here before? | `how <intent>` — cites real commits, not a guess | before your prompt is even read, when it resembles a certified shape or clearly matches past changes (see below) |36| What already IS this concept in this codebase? | `what <words>` — declarations, values, spread, siblings, commit mentions | nothing automatic — this one is always a deliberate call |37| Does my change conform to the local norm? | `check <file>` / `check` (whole change) / `review` | after every edit, and before a `git commit` runs |3839Not a trigger for any of these: reading, investigating, answering questions, touching config or docs.4041## The voice rule4243Every line grain prints as a claim carries one of four voices, marked identically in every command, so you never44have to infer authority from wording:4546- **practiced** — the statistical claim, unmarked (`methods here always call \`validate()\` — 91% of 120`). The47 default; the only voice allowed to carry no marker at all.48- **decided** — a maintainer's committed override, `decision <typ> (<who> <when>): …` (a catalog listing in49 `report`/`rules` adds the id: `decision <typ> (id <8-hex>, <who> <when>): …`). The numbers may still disagree —50 that is the point. Follow it anyway and say in one line that you did.51- **example** — one real historical instance, `example (<sha>[ <YYYY-MM>]): "…"` (date present on `how`'s commit52 citations, sha-only on a history-mention line), never a certified convention.53 Follow the files it names, not the words in the message.54- **map** — `map: …`, a structural overview of where things live, not an assertion about how they are written.5556**Silence is not approval.** A hook saying nothing after an edit, a read, or your own prompt means grain had57nothing certified to add — not that it reviewed your work and found it clean. Never re-run a command just to58confirm a silent edit, and never report silence to a user as "verified against the repository's conventions."5960## How to phrase `where`6162Use the repository's own vocabulary, not yours: the decorator you expect (`click.command`, `Injectable`), the base63type (`MethodView`, `IRequest`), the file or function name you would look for (`response json`, `cli routes`), the64directory word (`middleware`, `extract`). Hits come in four kinds — **group** (similar code, with its conventions),65**marker** (`@decorator` / `extends X` / `returns X` — where its carriers live), **directory**, **file** (with the66matching functions inside it). There is no test/example special-casing: code is code, and a test file CAN out-rank the67source it tests when it matches your words better — for a source change, take the source hit even when it sits second68or third.6970- **One `where` per intent.** If it prints the compact map, grain has no lexical hit: pick the closest entry71 yourself and open its files. Do not re-ask with synonyms.72- **`note: the top hit matches only «word» of your N words`** at the top means the ranking is driven by a fraction of73 your query — verify before building on it.74- Every card opens with an `in: <module>` line (its dependency layer and how many modules depend on it, once the75 architecture graph has one — see `map` below) and a **`superposition:`** line: the members laid on top of each76 other, the skeleton they share, the slot each fills differently, the skewed ones, the fleet's age. `a new member77 comes with:` is the recipe for a new instance. `twin: structurally the same as «B» …` on a group card names a78 role group elsewhere in the repo with the same shape, possibly under a different name.79- An `example (<sha>): "…"` line (the old "history bridge") means your word never appears in the code,80 but a commit saying it touched the listed files. Follow the files, not the word.81- **Retrieval miss ≠ freedom.** If every hit lands somewhere unrelated to what you are writing, that is a miss.82 Re-ask once with an exact identifier or decorator from the file you expect to edit; if that misses too, open the83 nearest sibling of that file and copy it.84- **"No strong convention here beyond placement"** means grain could not certify a convention at its acceptance85 floor. It is *not* evidence that the neighbours vary. Open the listed exemplar.8687## How to ask `how`8889`how <intent words>` answers by example, not by rule: which past commits look like the change you are about to90make, and which files a change like that actually touched, ranked `k/K` (K = how many of the cited commits touched91that file). When your intent clearly matches a recurring, certified shape of past commits, the answer opens with92that shape's cells (`"<label>" (n changes): <cell> (k of n) · …`) before the examples — a certified pattern, not93one anecdote. Zero matches falls back to `where`'s own compact map, whole and unmodified — nothing is invented.94Cite the commits it names as evidence, not as instructions to follow verbatim.9596## How to ask `what`9798`what <words>` is the concept card: what a word or phrase already IS here, distinct from `where` ("where should99new code go") and `how` ("what did past changes look like"). One card: `defined:` (declarations matching the100words), `values:` (enum members / string literals from the value index that match), `spread:` (which modules101carry it), `siblings:` (other values from the same enum/switch/object), `changes:` (commit mentions, with a102pointer to `how` for the shape), `used by:` (file-level fan-in). Ask it before extending an existing concept, to103see everything grain already knows about it in one place.104105## How to read `check`106107- Deviations **in your change** come first, each with `n/N established` evidence, the preference gap in bits, and108 exemplars. `100% of 29` is a rule — follow it or say in one line why not. `85% of 240` is a tendency.109- `In this file, \`x\` (line N) conforms.` names a neighbour in the same file to copy; `(held since …, last reinforced …)`110 says how old and how alive the rule is; `not to copy:` on a `where` card names the members that deviate. A note111 ending `deviants get fixes N× more often` means leaving this one uncorrected has a measured, historical cost.112- **Pre-existing** deviations (scopes you did not touch) are folded into one line. They are not yours to fix;113 `--all` lists them if you are asked to.114- **Zero deviations is not a review.** If the "conforms to" list is empty or grain says no convention governs the115 file, grain knows nothing certified about this kind of file here — say that, or say nothing; never report it to the116 user as "verified against the repository's conventions".117- **`missing from your change:`** at the end names what your change is missing, not what it broke: a co-change118 partner this repo's history usually touches alongside the files you changed (the only source a single-file119 `check <file>` shows) — plus, for `check`'s whole-change form and `review`, a companion file a new120 marker-carrier usually comes with, a sibling value (`kin:`) the rest of an enum/set has that yours does not, and121 a cell of a certified change shape (`change shape:`) your change leaves untouched. Silence means nothing is122 missing — there is no "(complete)" line to look for.123- `decision waiver (<who> <when>): …` on a deviation means a maintainer excused this ONE scope from this ONE124 convention — the departure is deliberate, say so, and do not "fix" it.125- "This is the local default of this directory — the wider package's norm differs here" means a neighbourhood126 habit, not a package-wide law.127- Partitions are style regions cut from the directory tree by compression, not by names — `examples/` or a test tree128 usually ends up its own region and its facts stay scoped there (`local (examples/)`), but nothing is filtered by129 name. If the only exemplar you get lives in an examples or test region and you are writing product code, prefer a130 sibling in source and say so.131- `check` with no file argument, and `review`, both mean "my whole uncommitted change" — one aggregated pass,132 highest-stakes findings first. Run it when you consider a unit of work done, not just the last file you touched.133134## grain also speaks unbidden135136Six hooks run mid-task, all silent on failure, none ever block:137138- **Before you `Write` a new file**, its path is checked against where its name-kin already live — a139 `[grain] placement:` note names the kin directory with counts, weaker rival kin with theirs. It arrives while140 changing the directory is still free: weigh it before writing, and if you place deliberately elsewhere, say so141 in one line.142- **After every `Edit`/`Write`/`MultiEdit`**, the file is re-checked and grain injects `[grain]` findings ONLY when143 it has something on the lines you touched — deviations, maintainer decisions, architecture crossings, a144 placement note — plus, on its own line and capped to 3 partners, the other files this repo's own history shows145 reliably changing together with the one you just touched. That co-change line can fire even when nothing else146 does.147- **Before an `Edit`/`MultiEdit` lands**, the same co-change evidence for the file about to be touched arrives148 ahead of the edit, while touching both halves of an established pair in one pass is still cheap. It shares its149 repeat-suppression with the post-edit line above, so you see the pair named once, not twice, in one turn.150- **After you `Read`** a file, if it is itself one of a convention's known deviants, grain says so once — "don't151 copy that part" — and points at a conforming sibling elsewhere. Silence means either the file conforms, or it152 is a deviant no fact ranks as a top-5 example worth citing.153- **Before your prompt is even read**, grain checks it against the repository's own history of past changes; if it154 strongly resembles a certified change shape or clearly matches how a recognizable kind of change has been done155 here before, it injects the certified shape's cells and the places such a change touched — silently, on156 everything else.157- **Before a `git commit` runs** (in a Bash tool call), grain reviews the whole staged (or, for `-a`, worktree)158 change ahead of the commit — the same report `review` would print, budget-capped.159160**A host with no prompt-submission hook gets none of the `how`-hook behavior above** (confirmed for Codex CLI at161the time of writing). Where this integration cannot inject anything before your prompt is read, start every task162by asking `grain how <query>` yourself before writing code.163164## Maintainer commands165166- **`report [--top N]`** / **`status`** — the model overview: size, freshness, signal verdict, top conventions with167 trends and ages, the measured architecture (modules, dependencies, cycles), the `check` feedback rate (notes168 acted on vs. ignored after warning), and a `== health ==` section flagging conventions worth a decision: costly169 deviations, rejected alternatives, conventions carried mostly by agent-authored code, under-adopted shapes,170 conventions with several waivers already, dead steers. Every health line ends with a suggested `grain decide …`171 — text, never an executed command.172- **`rules [--out <file>]`** — the same data as `report`, rendered as a standalone Markdown document stamped with173 the commit, for a maintainer or a coding tool with no terminal and no grain plugin. `grain rules > CONVENTIONS.md`174 already works without a flag.175- **`decide steer <path>#<name> --surfaces <pid,…> [--instead-of <pid,…>] --note "…"`** — record a maintainer176 decision: promote one property of one exemplar repo-wide, in the committed `.grain/seeds.jsonl`. Capped at half177 the real population (it cannot invent a convention nobody has written). When the user says "from now on prefer178 X" / "we are moving to Y", offer to record it as a `decide steer` instead of editing files by hand.179- **`decide boundary <from> --never-imports <to> --note "…"`** — an architecture decision: new imports crossing it180 are flagged at edit time.181- **`decide waive <path>#<name> --on <pid> --note "…"`** — excuse ONE named scope from ONE convention: `check`182 reports the departure as deliberate instead of an accusation, and the counts still report it as non-conforming.183 Refuses when the name is ambiguous — pick the exact scope grain lists.184- **`decide list`** / **`decide rm <id>`** — the decisions in force / withdraw one.185- **`status --json` / `report --json` / `export`** — the same answers as data, for harnesses and training186 pipelines, not for a conversation. `export` dumps the whole model — every convention with its sites, anchors,187 trends, groups, markers, co-change, certified change shapes, structural twins — see `docs/reference.md` for the188 schema.189190`decide` is the current name; `seed add | add-boundary | list | rm` is the same command under its original name —191same records, same effect.192193## Developer commands194195- **`explain <file> [--minbits N] [--top N]`** — only when the explicit question is "what is local versus global196 around this file": the full lattice with no acceptance cut (`NORM` = accepted, `obs` = below the gate). Large;197 not for a small edit. (`spectrum` is the same command under its original name.)198- **`selftest [--json]`** — plants synthetic deviations into conforming exemplars and reports how many this repo's199 own model catches: a public, repeatable number for this repository, not a claim taken on faith.200 **`selftest --how [--last N]`** — a leave-one-out check of `how`'s own precision/recall at predicting a past201 commit's files, against a grep baseline, over the last N real commits; a validation procedure, not something to202 run mid-task.203- **`map [--json]`** — a structural overview: dependency layers from leaves to top, the repo's top concepts where204 commit messages and code vocabulary agree, the certified change shapes, and how many maintainer decisions are in205 force. Good for orienting in an unfamiliar repository before asking anything more specific.206- **`propose [<out-dir>] [--full] [--json <path>] [--holdout <YYYY-MM-DD>]`** — for a repository with no207 `.yggdrasil/` yet: mine one. Writes a PROPOSED Yggdrasil architecture graph — node types, nodes, relations,208 dependency cycles and mined rules, each with the evidence that produced it — into `<out-dir>` (default209 `.yggdrasil-proposal/`, self-ignoring; the repository's own `.yggdrasil/` is never written). The default210 report is short on purpose: the architecture with its counts, the rules a real `yg drill` proved on this211 repository's own code (zero false alarms, at least one caught violation), and the candidates that came close;212 everything else is on disk and summarised in one counted line, with `--full` to print it. With no Yggdrasil213 CLI (`YG_BIN`, or `yg` on PATH) nothing can be drilled, so nothing is enforced and the report says so. It is214 a proposal: a human reviews it and moves it in. Never move it in, and never run `yg check --approve`, unbidden.215- **`oracle record [--proposal <dir>] [--graph <dir>] [--name <n>] [--out <dir>] [--yes]` / `oracle score216 <name-or-dir> [--json]`** — after a proposal has been read and a graph accepted, the difference between the217 two is a measurement oracle. `record` keeps it (both graphs' structure, the tracked paths each element218 selects, and the correction: what was merged, split, renamed, dropped, added); `score` reports precision and219 recall in both directions on the same Jaccard >= 0.5 bar the hand-written oracles are scored with. `record`220 prints what it would store and where and writes NOTHING without `--yes` — relay that plan and wait, never221 add `--yes` for the user and never pick a destination for them. It stores structure and paths, never file222 contents, so scoring later needs no checkout.223224- **`advise [--json] [--graph <dir>]`** — the other direction from `propose`: for a repository that ALREADY has225 a `.yggdrasil/`, what its own history and imports say about it. Two findings, at very different weights. A226 place a finer cut beats on its own evidence **is** advice: one node owns a pile that is not one thing, and227 the report names the node, its size and the directories on offer. Places that change together are **not**228 advice and are deliberately not listed — measured on four hand-written graphs, that evidence names almost229 nothing and what it names the graph usually already connects, so the report prints the count, how many are230 unconnected, how concentrated they are, and what share of all pairs of places are connected anyway. Relay231 those as numbers; never turn one into "add a relation here". `--json` hands over the whole document if the232 user wants the data. It writes nothing and never touches the graph.233- **`refresh [--full]`** — rebuild the index now (every query already auto-refreshes).234- **`completeness <file…>`** — ask about files BEFORE editing them, or check several files against each other at235 once: the other files this repo's own commit history shows reliably co-changing with the ones given. This is the236 same evidence `check`/`how`'s `missing: co-change:` line and the co-change hooks above already surface for an237 active change; call it directly when there is no change yet to attach it to.238239grain informs; it never blocks. No embeddings, no model calls, no network. A convention is a majority, not a240virtue, and uncommitted changes never feed the norm.