corpus-flow
Skill0 starsChanged 4 months agoMITView on GitHub
Run a project's knowledge and work as an LLM-maintained wiki ("corpus") at the repo root — a curated wiki/ synthesis layer plus a todos→briefs→done+log work lifecycle. The LLM owns synthesis; the human curates sources and asks questions. Use when the user says "add a todo", "promote to a brief", "work on <brief>", "mark this done + log it", "what does the wiki say about X", "ingest this finding", "lint the corpus", "/corpus-flow", or wants durable, wiki-style project knowledge + task tracking (not the ephemeral in-session TodoWrite list). Bootstraps ./corpus on first use.
We split this skill into the rules it gives an agent
34 rules. About 0 are common, 19 are distinctive, and 15 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈19
Distinctive · estimate
This author's own choices. Worth a look.
15
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 124
Definitions only: No implementation detail, no spec, no scratch notes.
- Distinctive: line 131
Conflicts are findings: If code or docs use a term against its definition, that is a real inconsistency: fix one side, don't quietly add a …
- Distinctive: line 142
One concept per file: When a page passes ~200 lines or starts straddling two topics, split it and cross-link.
- Very specific: line 144
Born from ingest: When a finding is named repeatedly but has no page (§6), create one and link it from index.md.
- Very specific: line 190
Read index.md. Then read at most 2–3 wiki pages.
- Very specific: line 194
Never read briefs/ or todos/ wholesale.
- Very specific: line 196
Prefer the summary: line over opening the page.
- Distinctive: line 230
If they're missing, create:
- Very specific: line 246
READ/SKIP/SKILLS table, and the knowledge-routing table (§0b).
- Distinctive: line 265
Keep index.md and log.md minimal — they are navigation aids, not content.
- Distinctive: line 370
When the user is ready to actually build a todo (or files a brief directly).
- Very specific: line 381
Use 2-digit padding (07, 42) unless existing briefs use more.
- Very specific: line 405
If promoting from a todo, mark the source todo status: promoted (add a line linking the brief) or delete it — ask which the user prefers if …
- Distinctive: line 414
When the user says "work on brief NN" / "let's build this".
- Distinctive: line 434
If the brief or codebase already answers a branch, resolve it yourself and say so — don't ask the user what you can read.
- Distinctive: line 444
Write the implementation plan back to the user (and, if it changes the spec, fold the resolved decisions into the brief file so it stays …
- Distinctive: line 467
When the work is done and verified.
- Very specific: line 507
Update navigation: if a new wiki page was added: cross-link it from index.md.
- Distinctive: line 510
Commit only if asked.
- Distinctive: line 516
When the user asks "what does the corpus/wiki say about X" / "how does Y work here".
- Distinctive: line 526
If the answer is non-trivial and reusable, file it back as a new or updated wiki page rather than letting it disappear into chat.
- Distinctive: line 534
When the user shares a result, a decision, an exploration outcome, or a brief lands — anything that should become standing knowledge.
- Very specific: line 539
If it's a spec, drop the raw artifact in briefs/.
- Very specific: line 543
If the concept is named but has no page yet, create one (one concept per file) and cross-link it from index.md.
- Very specific: line 546
Keep decisions.md for locked tech/design choices.
- Distinctive: line 553
When the user says "lint the corpus" / "is the wiki stale".
- Very specific: line 597
If a claim is stale, fix the page (it's the LLM's to curate) and note it in log.md.
- Distinctive: line 623
Sharpen fuzzy terms: When a word is overloaded, propose the precise one.
- Distinctive: line 628
Cross-reference with code: If the user states how something works and the source disagrees, surface it.
- Very specific: line 668
When that happens, keep a glossary map at corpus/wiki/glossary.md that points at per-context pages rather than defining everything itself:
- Distinctive: line 734
Numbers are stable: Never renumber a brief when it moves between dirs.
- Distinctive: line 750
Source-of-truth ordering: when pages or beliefs disagree:
- Very specific: line 757
Verify any path/function/commit a page names before acting on it — pages drift.
- Very specific: line 759
Don't edit a done/ brief; don't let durable findings rot in chat.
≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Corpus Flow — a project's knowledge + work as an LLM-maintained wiki
A corpus is a small LLM-maintained wiki living in corpus/ at the repo
root. The governing split: the human curates the sources and asks the
questions; the LLM curates the synthesis and tracks the work. It is the
durable counterpart to TodoWrite (ephemeral, in-session only) and to chat
(which evaporates) — reusable findings get folded back into the corpus, not
left in conversation or personal memory.
The three layers
corpus/
CLAUDE.md schema + conventions for THIS corpus (written on bootstrap)
index.md content catalog — generated from each page's `summary:` frontmatter
routing.md which question goes to which layer (wiki / code graph / grep / tests)
lint.sh health check: frontmatter, link resolution, page size, stale paths
log.md chronological record of every meaningful change
todos/ captured ideas/tasks as prose (pre-spec)
briefs/ raw, immutable task specs
todo/ done/ superseded/
wiki/ LLM-curated synthesis pages — the actual knowledge base
overview.md, architecture.md, decisions.md, status.md, open-questions.md, …
test-plans/ (optional) plain-text browser test plans + latest RESULTS
index.md TP-NN-<slug>.md … RESULTS.mdtest-plans/ is an optional adjacent layer — present only in projects with a
UI worth walking in a real browser. It holds plain-text, human-or-agent-runnable
plans (one TP-NN-<slug>.md per area, an index.md catalog, a RESULTS.md
snapshot of the latest run); the actual browser bring-up/fixtures live outside
the corpus (e.g. a gitignored playwright/ hub). It is authored by the
ui-test-plans skill, not this one — corpus-flow
just gives it a home so runs feed findings back as todos/briefs and a log.md
line. Skip it entirely for backend/CLI/library projects.
- briefs/ — raw, immutable. Each file is a task spec used to direct a
slice of work (often by a subagent). Once in
done/orsuperseded/, do not edit it. New work gets a new brief intodo/. - wiki/ — the LLM owns this. Synthesis, entity pages, concept pages, current status. Edited freely as understanding evolves. This is where durable knowledge accrues.
- index.md + log.md + todos/ — navigation and capture aids. Updated on every meaningful change.
The work lifecycle moves a single piece of work left-to-right; the wiki layer is the standing knowledge the work draws from and feeds back into:
todos/<slug>.md capture an idea/task as prose
│ (promote)
▼
briefs/todo/<NN>-<slug>.md a numbered work spec, ready to build
│ (grill → plan → implement)
▼
briefs/done/<NN>-<slug>.md moved verbatim (number kept) + outcome note
│
├─► log.md one chronological entry per meaningful change
└─► wiki/ fold durable findings into the synthesis pagesPick the matching section below by what the user asked. If ambiguous, ask one question to disambiguate, then proceed.
The wiki — what it is and what pages live in it
The wiki is not a freeform dump of notes. It is a small set of curated pages,
each with one job and its own curation discipline. The point is that a reader
(human or a fresh agent) opens index.md, sees the catalog, and lands on the one
page that answers their question — without spelunking the code or the brief
archive. Knowledge that doesn't fit one of the standing pages gets its own
concept page, not a paragraph wedged into an unrelated one.
A typical wiki has a spine of standing pages plus entity/concept pages that grow as the project does.
The spine (most projects want these)
overview.md— what this project is, in a paragraph: the pitch, the lineage, the cast/major components, and what lives where at the top level. The orientation page. Short and stable.architecture.md— the structural map: workspaces/packages, layers and their dependency direction, the data-flow / main loop, the big boundaries. "How is it put together." Updated when structure shifts, not on every change.decisions.md— locked tech/design choices, listed so future briefs and reviews don't relitigate them. Each is a settled call ("npm workspaces, not pnpm"; "pinned versions"; "no.jsimport suffixes"). Changing one requires an explicit revisit + alog.mdnote — you don't quietly flip a decision. This page wins overstatus.mdfor choices not formally revisited.Record a decision only when all three hold — otherwise the page fills with obvious choices and stops being read:
- Hard to reverse — changing your mind later has real cost.
- Surprising without context — a future reader will ask "why this way?"
- A genuine trade-off — there were real alternatives and one was picked.
Format per entry: the call, the date, the alternatives rejected, and the reason. The reason is the load-bearing part — a decision with no why cannot be revisited intelligently, only obeyed or broken.
status.md— a dated snapshot of current state: a terse one-liner per brief/area and a short "where things stand" paragraph. Detail is pushed down, not duplicated — the brief file owns the full spec,log.mdowns the history. Re-stamp the date when you update it. It's the living dashboard, kept deliberately thin.open-questions.md— only the genuinely unresolved. The moment a question is answered or shipped, delete it from here — its history lives instatus.md+log.md. This page must never accumulate resolved cruft, or it stops being trustworthy as "what's actually open."glossary.md— the project's vocabulary: one canonical definition per term the project uses in a specific way, each with the synonyms it displaces. This is the page that stops three people (and three agents) calling the same thing three names. Format and the multi-context variant: §9.Rules that keep it useful:
- Definitions only. No implementation detail, no spec, no scratch notes. If an entry starts explaining how something works, that belongs on a concept page and the glossary should link to it.
- Only terms with a project-specific meaning. "Cache" does not need an entry; "a run" does, if this project means something particular by it.
- Write it the moment a term is settled, usually mid-
grill-me— not in a batch later, when the precise wording that made it click is gone. - Conflicts are findings. If code or docs use a term against its definition, that is a real inconsistency: fix one side, don't quietly add a second sense. A term with two live meanings is two terms, and needs two names.
Entity / concept pages (grow with the project)
One page per meaningful concept, subsystem, or entity — e.g. economy.md,
world-generation.md, animation.md, performance.md, system-ordering.md.
Each is the single home for its topic: the synthesis of how that thing works,
the decisions specific to it, the open threads, and links into the code. Rules:
- One concept per file. When a page passes ~200 lines or starts straddling two topics, split it and cross-link.
- Born from ingest. When a finding is named repeatedly but has no page (§6),
create one and link it from
index.md. A concept mentioned across three pages but owned by none is a lint finding (§7). - Code refs are relative and verifiable. They drift — §8 before quoting.
What makes it a wiki (not a notes folder)
- Synthesis over transcript. A page states the current understanding, not a
log of how you got there. The chronology is
log.md's job. - The LLM curates, freely. Rewrite a page as understanding improves; don't append-only. Stale phrasing is a bug to fix, not history to preserve.
- Every page is reachable from
index.md(the catalog). Orphans get linted. - Pages can drift from code — they're a view, not the truth. Source-of-truth ordering (Conventions) and §8 verification keep them honest.
Frontmatter + the retrieval budget
A corpus exists to make an agent cheaper, not just better-informed. A wiki you must read to discover is irrelevant has already cost you the tokens. So every wiki page opens with exactly two keys:
---
summary: <one line — what question this page answers. The triage signal.>
updated: <YYYY-MM-DD>
---summary: is the load-bearing one. It is written for an agent deciding whether
to open the page, not as a title. "Ranked optimization backlog, filtered against
what the code actually does, and what is explicitly not worth doing at this scale"
tells you whether to open it; "Performance notes" does not.
This is the atomic-note idea (Zettelkasten / A-Mem) applied to a repo wiki: one concept per note, each carrying an LLM-written description, so retrieval lands in a small budget instead of pulling whole documents.
index.md is generated from those summaries — one line per page,
bash corpus/lint.sh --index. Never hand-maintain the catalog, and never let
index.md duplicate a list that another page already owns (a brief catalog belongs
in status.md; index.md links to it).
The budget, stated in corpus/CLAUDE.md so a fresh agent inherits it:
- Read
index.md. Then read at most 2–3 wiki pages. - Needing more than three is a signal, not a licence to read more: a page is straddling topics and must split, or the summaries aren't sharp enough. Fix the cause.
- Never read
briefs/ortodos/wholesale.status.mdholds every brief's state in one line; open a brief only for the spec that directed specific work. - Prefer the
summary:line over opening the page. That is what it is for.
The two-graph model — the corpus is the why, not the what
The corpus answers why the code is the way it is: decisions, intent, history. It is authored, git-reviewed, and a source of truth.
It is the wrong tool for what the code is: "who calls X", "what breaks if I change X", "where does feature Y live". Those belong to a code graph — a generated, disposable symbol index (tree-sitter → SQLite, served over MCP). It is regenerated from source, never hand-maintained, and never a source of truth.
Keeping them separate is what protects the budget above. An agent that greps and
reads twenty files to answer a structural question has blown its context before it
reaches the wiki; an agent that asks the wiki a structural question gets a stale
answer. Route each to its own layer (see the table in routing.md, §0).
Never let the code graph's output be written into the wiki as fact. The graph is a lookup, not a finding.
0 — Bootstrap (first use in a project)
corpus/ always lives at the repo root (./corpus). Before any operation,
ensure the skeleton exists:
mkdir -p corpus/todos corpus/briefs/todo corpus/briefs/done \
corpus/briefs/superseded corpus/wikiIf they're missing, create:
corpus/CLAUDE.md— the schema/conventions for this corpus. Adapt the Conventions and Workflows sections at the bottom of this skill into a concise per-project version (so a fresh agent opening the repo learns the rules without this skill loaded). Note the source-of-truth ordering and tell agents to readindex.mdfirst.corpus/index.md— the content catalog (what lives where), starting with links to CLAUDE.md, log.md, and the wiki pages. This is the front door.corpus/log.md— a# Logheading and nothing else yet.corpus/wiki/glossary.md— created lazily: the moment the first term is settled (usually mid-grill-me), not as an empty stub at bootstrap. An empty glossary teaches a fresh agent nothing; a missing one at least prompts the question. Same fordecisions.md.corpus/routing.md— the routing profile read by theorchestrateskill (the front door): implement/review/PR skill choices, an intent table, a READ/SKIP/SKILLS table, and the knowledge-routing table (§0b). Seed it withImplement skill: plan-split-dispatchand stub the rest — see the template in theorchestrateskill. Iforchestratedoes the bootstrap it enriches this by scanning the repo; created here so the file always exists. Link it fromindex.md.corpus/lint.sh— the health check (§7). Write it at bootstrap so the invariants are enforceable from day one, not aspirational prose. It must check: every wiki page hassummary:+updated:frontmatter; every relative link resolves; no page exceeds ~200 body lines (frontmatter excluded); no page references a directory layout the repo has since abandoned.--indexregeneratesindex.md's catalog block from the summaries. Exit non-zero on failure so it can gate a commit.- The wiki spine — at minimum seed
corpus/wiki/status.md(the living dashboard). Also seedoverview.md,architecture.md,decisions.md, andopen-questions.mdwhen you have enough to say — even a stub paragraph each is better than a missing page, because it gives ingest (§6) a home to grow into. See the wiki section above for what each page is for. Don't fabricate content to fill them; a one-line "TODO: …" stub is fine. Every page gets frontmatter, stubs included.
Keep index.md and log.md minimal — they are navigation aids, not content. Tell the user you bootstrapped the corpus; don't make it a ceremony. Do not commit anything in this skill unless the user explicitly asks — the user controls when corpus changes land in git.
0b — Add the code-graph layer (the what)
The corpus is the why layer (synthesis, decisions, status). A generated code graph is the complementary what layer — call graph and impact/blast radius for change-planning. A corpus without it leaks tokens on structural questions ("who calls X", "what breaks if I change Y"). During bootstrap, or when the user asks to add it, stand this layer up.
The method lives in the personal codegraph skill —
the graph-first / grep-verify loop, the pinned install, the accuracy-envelope
benchmark, and the when-to-trust-vs-verify triggers. Follow it; do not
re-derive it here. This section is only how the result plugs into the corpus:
- Bootstrap per the
codegraphskill, and commit the wiring. Install pinned (@colbymchenry/codegraph@<pin>, MIT but effectively single-maintainer, a supply-chain surface even offline),codegraph init, telemetry off, confirm the native backend, gitignore.codegraph/. Commit the MCP registration into the repo.mcp.jsonrather than leaning on a per-devcodegraph install: a manual per-dev step reliably never gets run, so the graph tool silently stays absent from most sessions and the whole layer goes dead (the failure mode this skill exists to prevent). Point the server at the index with an env-overridable path so one canonical index is shared read-only across worktrees instead of re-inited per throwaway tree:serve --mcp --no-watch --path ${CODEGRAPH_INDEX_PATH:-<index-dir>}(Claude Code expands${VAR:-default}in.mcp.json, so the committed default works for a single checkout while worktree users export the absolute path once). Wrap the build in a one-command task-runner script (e.g.npm run codegraph:init/codegraph:sync) so onboarding is one line, not a hunt through the docs. Do not skip its benchmark: the tool istree-sitter + a heuristic resolver, not a compiler, so token-savings claims hold only for the queries it is good at and it is silently wrong elsewhere. The envelope is per-repo. - Write the per-repo project skill at
.claude/skills/codegraph/SKILL.mdcarrying the measured envelope: a use it for table (callers, impact/blast radius, first map of an unfamiliar area) and an explicit do NOT use it for list — rename/"every usage" completeness (usegrep -rnw), the conflated duplicate-name list from the benchmark, and any correctness invariant a guard test already covers. It lives in the project, never in personal skills: its whole value is the repo-specific accuracy numbers, which cannot be written once and reused. (The personalcodegraphskill supplies the method; the project skill records what the method measured here.) - Make the numbers durable in the corpus. File the benchmark as a
wiki/code-graph.mdpage, and add the knowledge-routing table tocorpus/routing.md(question shape → layer: wiki / code graph / grep / tests) so the graph becomes a first-class member of this project's structure, not a rediscovered afterthought.
The working rule, everywhere: lead with the graph to locate and scope;
verify with grep or a guard test before acting on completeness. A cheap wrong
answer is worse than no answer.
1 — Add a todo (capture)
For a durable task/idea/follow-up the user wants to keep. Prose, not a formal spec yet.
- Get the todo text. If the user gave a bare "add a todo" with no content, ask what it is — one question, then proceed.
- Derive a kebab-case slug from the gist (e.g. "fix the scalloped shore mask" →
fix-scalloped-shore-mask). Filename:corpus/todos/<slug>.md— do NOT date-prefix the name; the date lives in thecreated:frontmatter below. On a name clash, append-2,-3, …. Write the file:
--- title: <one-line title> created: <YYYY-MM-DD> status: open tags: [<optional>] --- # <title> <The task in the user's framing — what needs doing and why.> ## Context <Motivation, related files, constraints. Relative markdown links to code or corpus pages where relevant. Omit the whole section if there's nothing.> ## Acceptance <What "done" looks like, if the user stated it. Omit if unclear.>Fill only sections you have real content for; drop the empty ones. Stay faithful to the user's wording — don't invent scope or acceptance criteria.
- Confirm: report the clickable relative path + a one-line summary. One todo
per file (multiple todos → one
Writeeach).
2 — Promote a todo to a brief
When the user is ready to actually build a todo (or files a brief directly).
Pick the next number. Briefs are numbered with a zero-padded prefix that is stable for the life of the file. Find the current max across
corpus/briefs/{todo,done,superseded}/and add 1:ls corpus/briefs/todo corpus/briefs/done corpus/briefs/superseded 2>/dev/null \ | grep -oE '^[0-9]+' | sort -n | tail -1Use 2-digit padding (
07,42) unless existing briefs use more.Write
corpus/briefs/todo/<NN>-<slug>.mdas a self-contained work spec a fresh agent could execute without other context:# Task <NN> — <Title> ## Context <Why this exists, the problem, links to the source todo and relevant code.> ## Files you OWN <Paths this work creates/edits. Be specific — this is the contract.> ## Files you must NOT touch <Anything adjacent that another change owns, integration points, generated files. Omit if nothing applies.> ## What to do <The plan, concrete enough to act on. Numbered steps if multi-part.> ## Acceptance <Observable "done" — tests pass, behavior X, typecheck clean, etc.>- If promoting from a todo, mark the source todo
status: promoted(add a line linking the brief) or delete it — ask which the user prefers if unclear; default to marking it promoted so the trail survives. - Confirm the brief path. Don't start building yet unless the user said to.
3 — Work a brief: grill → plan → implement
When the user says "work on brief NN" / "let's build this". Three phases, in order. Do not write implementation code before the plan is acknowledged.
3a — Grill the design (inline, or via the grill-me skill)
Interrogate the brief until the design is unambiguous. Ask the user pointed questions — one tight batch, not a stream — covering whichever of these actually have open branches:
- Scope boundary. What's explicitly in vs. out? What's the smallest version that counts as done?
- Unknowns. Any value, path, format, or behavior the brief leaves implicit?
- Collisions. What existing code/data does this touch or risk breaking? (Verify by reading the code — don't guess.)
- Failure modes. What's the expensive-to-be-wrong part, and how do we know it's right?
- Invariants. Does this project have load-bearing constraints (seeded RNG,
enforced palette, layering rules, pinned deps)? Check
corpus/CLAUDE.mdand the repo's conventions; confirm the brief respects them.
If the brief or codebase already answers a branch, resolve it yourself and say so — don't ask the user what you can read. Stop grilling when no branch with a material consequence is still open.
If the richer standalone
grill-meskill is available and the design is large or contentious, you may run that instead of this inline pass — but this inline grill is the default and keeps the skill self-contained.
3b — Plan
Write the implementation plan back to the user (and, if it changes the spec, fold the resolved decisions into the brief file so it stays the source of truth). Get an acknowledgement before building. Use EnterPlanMode/ExitPlanMode if the harness supports it.
3c — Implement
Build per the plan. If the brief decomposes into ≥3 independent chunks (several
mechanical), dispatch it via plan-split-dispatch — it splits the work,
classifies each chunk hard/easy, and runs hard→opus / easy→sonnet as fresh
subagents with curated context (cheap tokens on cheap work, lean controller).
Pass the brief + the project's READ/SKIP/SKILLS rows from corpus/routing.md.
For a 1–2 chunk or single-indivisible brief, implement inline — the dispatch tax
isn't worth it.
Either way: honor the brief's "Files you OWN / must NOT touch". Verify against the brief's Acceptance — run the project's typecheck/tests/build as applicable; report results faithfully (failing tests get said so, with output).
4 — Complete a brief + log it + fold into the wiki
When the work is done and verified.
Move the brief, keep its number:
git mv corpus/briefs/todo/<NN>-<slug>.md corpus/briefs/done/<NN>-<slug>.md \ 2>/dev/null || mv corpus/briefs/todo/<NN>-<slug>.md corpus/briefs/done/<NN>-<slug>.mdA brief in
done/is immutable — don't edit it later. Append a short outcome note at the bottom only at move time (what actually shipped vs. the spec, anything deferred). If later work undoes a done brief, move it tosuperseded/with a one-line top note explaining why — never rewrite history.Append a
log.mdentry at the bottom (chronological, newest last):## [<YYYY-MM-DD>] done | Brief <NN> — <one-line what-shipped> <2–5 lines: what landed, key files/decisions, what was deferred, how it was verified. Link the brief and any wiki page. Absolute dates only.>Other entry kinds:
todo(brief filed),maintenance,incident,decision,ingest,lint,resume.A
resumeentry is the checkpoint written when a long run is paused (e.g. the user hits a quota/usage limit and asks to stop for a fresh session). It captures enough for a cold start next session: what is done (with the contracts dependents need), what is in-flight or next, the branch + last commit, and any open decisions.plan-split-dispatchwave-mode writes one at a wave boundary; keep it at the bottom oflog.md(or a dedicatedcorpus/resume-<YYYY-MM-DD>.mdwhen the state is large) so the next session reads it first.- Fold durable findings into
wiki/(this is the step that makes it a wiki, not a task tracker). If the work changed how the system behaves or revealed something reusable, update the affected synthesis page(s) —status.mdalways, plus the relevant entity/concept page,decisions.mdif a choice was locked,open-questions.mdif a question opened or closed. See §6 (Ingest). A finding that lives only in the brief or the log will be missed by the next reader; the wiki is where standing knowledge belongs. - Update navigation if a new wiki page was added: cross-link it from
index.md. - Confirm: report the moved path, the log entry, and which wiki pages changed. Commit only if asked.
5 — Query the wiki (answer a question against the corpus)
When the user asks "what does the corpus/wiki say about X" / "how does Y work here".
- Read
index.mdfirst; triage on thesummary:lines. Respect the retrieval budget — index plus at most 2–3 pages. - Drill into the wiki pages, not the codebase — unless the wiki points you at specific code, or you need to verify a claim (see §8).
- Structural questions are not wiki questions. "Who calls X", "what breaks if
I change X", "where does feature Y live" go to the code graph (§0b), and
"did I get every usage" goes to
grep. Checkrouting.mdfirst. - If the answer is non-trivial and reusable, file it back as a new or updated wiki page rather than letting it disappear into chat. Then answer.
- Honor the source-of-truth ordering (see Conventions) when pages disagree.
6 — Ingest a finding (new source / new knowledge)
When the user shares a result, a decision, an exploration outcome, or a brief lands — anything that should become standing knowledge. Triggers: "ingest this", "remember that we decided…", "fold this into the wiki", or naturally at the end of §4.
- If it's a spec, drop the raw artifact in
briefs/. Otherwise summarize the finding inline. - Update the affected wiki pages —
status.md, the relevant entity/concept page,open-questions.md. Edit freely; the wiki is the LLM's to curate. - If the concept is named but has no page yet, create one (one concept per
file) and cross-link it from
index.md. - Append a
log.mdentry:## [<YYYY-MM-DD>] ingest | <short title>. - Keep
decisions.mdfor locked tech/design choices; don't relitigate a decision recorded there without flagging it explicitly.
7 — Lint the corpus (periodic health check)
When the user says "lint the corpus" / "is the wiki stale".
Run bash corpus/lint.sh first — it mechanically catches missing frontmatter,
broken relative links, oversized pages, and abandoned path roots. Fix those, then
sweep by hand for what a script can't see:
- Contradictions between pages (e.g.
decisions.mdvsstatus.md). - Stale claims — verify by reading the actual code or running the relevant command before trusting (see §8). The nastiest kind is a page whose top-ranked finding was silently obsoleted by later work; the links still resolve, so only reading the code catches it.
- Orphan pages — no inbound link from
index.mdor another wiki page. - Named-but-pageless concepts — mentioned repeatedly, no page of their own.
- Drifted briefs — a
done/brief whose work has since been undone or replaced → move tosuperseded/with a one-line note. - Straddling pages — two topics in one file → split, even under the line cap.
- Duplicated catalogs — a list
index.mdmaintains that another page owns. - Vocabulary drift — a concept the wiki calls two names, or a
glossary.mdterm the code and docs no longer use that way. Two live meanings for one term is two terms; give the second one its own name rather than widening the definition. - Undefended decisions — a
decisions.mdentry with no why recorded. It cannot be revisited intelligently, only obeyed or broken; reconstruct the reason fromlog.mdor mark it for a revisit.
A large repo reorganization invalidates paths en masse; when the lint reports many broken links, resolve them by basename against the real tree rather than one at a time. Mark obsolete findings obsolete — don't delete the reasoning.
Report findings as a short list; fix the cheap ones inline, surface the rest for
the user to decide. Append a ## [<YYYY-MM-DD>] lint | … entry to log.md
noting what was swept and changed.
8 — Verify before quoting the wiki
A wiki page that names a specific file, function, or commit may have drifted. The wiki reflects what was true when written — it is not authoritative over the code. Before acting on a wiki claim:
- Names a path → check it exists.
- Names a function / flag → grep for it.
- Names a commit →
git log --oneline | grep <hash>.
If a claim is stale, fix the page (it's the LLM's to curate) and note it in
log.md. Never recommend an action based on an unverified wiki claim about
specific code.
9 — Domain modeling (the project's vocabulary + its locked calls)
The wiki records how things work. This section is about the language used to
say it, and the decisions that language encodes. Both live in the wiki spine —
glossary.md and decisions.md — and both are maintained actively, mid-session,
not swept up afterwards.
Vague language is not a documentation problem, it is a design problem wearing a disguise. A team that has not decided whether an account is a Customer or a User has not finished the design, and every brief written on top of that ambiguity inherits it.
9a — The active discipline (during any grill, brief, or review)
Four moves, run continuously — most belong inside grill-me, but they apply
whenever the project is being discussed:
- Challenge conflicts. A term used against its glossary definition is a finding,
not a typo. "
glossary.mddefines cancellation as X; you're describing Y — which is it?" - Sharpen fuzzy terms. When a word is overloaded, propose the precise one. "You said 'account' — Customer or User? Those are different things."
- Stress-test with concrete scenarios. Invent the awkward case and force the boundary. "What happens if they cancel after partial fulfilment?" Boundaries discovered this way are the ones worth writing down.
- Cross-reference with code. If the user states how something works and the source disagrees, surface it. That contradiction is either a stale mental model or a real bug, and both are worth the interruption.
9b — glossary.md entry format
Be opinionated: when several words exist for one concept, pick one and list the losers so they stop coming back.
# Glossary
**Order**:
A customer's committed request for goods, after payment authorisation.
_Avoid_: purchase, transaction
**Invoice**:
A request for payment sent after delivery.
_Avoid_: bill, payment requestRules:
- Definitions, not behavior. Say what it is, not what it does. The moment an entry explains mechanism, that belongs on a concept page — link to it instead.
- One or two sentences. A long definition means the term is doing two jobs.
- Only project-specific terms. "Cache", "retry", "timeout" do not belong here however much the project uses them. Ask: is this concept peculiar to this project, or general programming? Only the former earns an entry.
_Avoid_is the load-bearing half. Listing the rejected synonyms is what actually stops drift; a glossary without them just documents one more option.- Group under subheadings once natural clusters appear; a flat list is fine while it stays short.
9c — Multi-context repos
Most repos have one vocabulary. A monorepo spanning genuinely separate domains (ordering vs billing vs fulfilment) often has several, and forcing them into one glossary is how you get a term with three meanings.
When that happens, keep a glossary map at corpus/wiki/glossary.md that points
at per-context pages rather than defining everything itself:
# Glossary map
## Contexts
- [Ordering](./glossary-ordering.md) — receives and tracks customer orders
- [Billing](./glossary-billing.md) — invoices and payments
## Relationships
- **Ordering → Billing**: Ordering emits `OrderPlaced`; Billing consumes it to invoice
- **Shared**: `CustomerId`, `Money` — same meaning in both, defined hereThe relationships block is the valuable part: it is where the same word having two meanings becomes visible, and where integration decisions get their names. Split only when a real second vocabulary exists — a map over one context is ceremony.
9d — decisions.md entry format
The three-part test (hard to reverse · surprising without context · a real trade-off) governs what gets in. Format:
## Postgres for the read model
_2026-08-14_ — Projections land in Postgres, not the event store.
Rejected: querying the event log directly (too slow past ~10k events),
Elasticsearch (a second operational dependency for no gain yet).One to three sentences is a complete entry. The value is recording that the call
was made and why — not filling in sections. Add Status: superseded by <entry>
only when a decision is actually revisited.
What qualifies, concretely:
- Architectural shape — "monorepo with npm workspaces"; "event-sourced writes".
- Integration patterns — "Ordering and Billing talk via events, never HTTP".
- Technology with lock-in — database, queue, auth, deploy target. Not every library; the ones that would take a quarter to swap.
- Boundary and scope calls — "Customer data is owned by Customer; others hold an ID only". The explicit nos are as valuable as the yeses.
- Deliberate deviations — "manual SQL, not an ORM, because X". Anything a reasonable reader would assume the opposite of. These stop the next agent from "fixing" something intentional.
- Constraints invisible in code — compliance, a partner's latency contract.
- Non-obvious rejections — picked REST over GraphQL for subtle reasons? Record it, or someone proposes GraphQL again in six months.
9e — Where this shows up elsewhere
grill-medoes most of the capturing, mid-interview.improvereadsdecisions.mdbefore vetting, so locked calls are never reported as tech debt.plan-split-dispatchcarries the relevant terms into each chunk's context — a subagent that does not know the vocabulary invents its own.writing-guidelinesflags terminology drift in docs; the fix belongs here, not in the three pages that drifted.corpus-docs-sitecan renderglossary.mdas a reference page directly.
Conventions (load-bearing)
- Numbers are stable. Never renumber a brief when it moves between dirs.
- Every wiki page carries
summary:+updated:frontmatter, andindex.mdis generated from it (bash corpus/lint.sh --index). The summary is the retrieval signal — write it for an agent deciding whether to open the page. - The retrieval budget is a rule, not advice.
index.md+ at most 2–3 pages. Needing more means a page must split. - Standard markdown links, relative to the file's own location — not Obsidian
[[wikilinks]]. Repos render in VSCode/GitHub, where standard links are clickable. (Code refs fromwiki/are../../src/...; frombriefs/<area>/<state>/they're one level deeper.) - Absolute dates (
2026-06-15), never "yesterday". - One concept per file. Split a page that grows past ~200 body lines or straddles two topics.
- The corpus is the why; a code graph is the what. Never answer a structural question from the wiki, and never write a code graph's output into the wiki as fact (§0b).
- Source-of-truth ordering when pages or beliefs disagree:
- The actual code wins over any wiki claim.
- A brief in
done/wins overwiki/if the wiki hasn't caught up. decisions.mdwins overstatus.mdfor tech choices not formally revisited.- An external spec (e.g. an upstream README the project tracks) wins for design disagreements in its domain. Verify any path/function/commit a page names before acting on it — pages drift.
- The LLM owns
wiki/; briefs are immutable; index/log are navigation. Don't edit adone/brief; don't let durable findings rot in chat. - One commit per meaningful corpus change (when committing) so
log.mdand git history agree. Never commit without the user asking. TodoWriteis for the in-session task list;corpus/is durable. Don't conflate them. Likewise prefer the corpus over personal memory for project-specific, reusable knowledge.
In this repository29 other files it gives its agents.
- skills/vercel-composition-patterns/AGENTS.mdAGENTS.md
- skills/vercel-react-best-practices/AGENTS.mdAGENTS.md
- skills/vercel-react-native-skills/AGENTS.mdAGENTS.md
- skills/vercel-react-view-transitions/AGENTS.mdAGENTS.md
- bootstrap-vps-deploySkill
- codegraphSkill
- corpus-docs-siteSkill
- design-md-librarySkill
- design-taste-frontendSkill
- diagram-designSkill
- grill-meSkill
- high-end-visual-designSkill
- impeccableSkill
- improveSkill
- industrial-brutalist-uiSkill
- minimalist-uiSkill
- orchestrateSkill
- plan-split-dispatchSkill
- readme-docsSkill
- redesign-existing-projectsSkill
- thermo-nuclear-reviewSkill
- ui-test-plansSkill
- unslopSkill
- vercel-composition-patternsSkill
- vercel-react-best-practicesSkill
- vercel-react-native-skillsSkill
- vercel-react-view-transitionsSkill
- web-design-guidelinesSkill
- writing-guidelinesSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

