Wiki Store
Wiki Store
Section titled “Wiki Store”The wiki holds what BoB has learned about its own tooling and skills: one page per failure mode, strategy or workaround, each citing the traces it came from. The skill proposer reads it to decide what to change. It lives in BOB_SOURCE, is checked by
make check, retires what stops being true, and never carries a client fact (#2388, part of #2387).
Why the wiki exists and how it fits the skill-evolution loop is the design in Skill evolution: traces, a wiki and skills. This page is the contract the tools enforce.
Layout
Section titled “Layout”wiki/├── patterns/<slug>.md authored — one page per pattern├── index.md derived — generated by scripts/wiki/index.js├── logs.md appended — one row per maintainer run├── skill-impact.md appended — one row per skill proposal└── .maintain-state.json written — the maintainer's watermark| Path | Written by | Rule |
|---|---|---|
patterns/<slug>.md |
The maintainer (#2389), through a PR a person merges | Lowercase kebab slug. Edits are patches: merge evidence, bump count, extend last_seen. A page is never deleted. |
index.md |
node scripts/wiki/index.js |
Never edited by hand. make check fails when it does not match the pages. |
logs.md |
The maintainer run | One row per run, appended. |
skill-impact.md |
The gate harness, not a model | One row per proposal, appended. |
.maintain-state.json |
The maintainer run | The last record consumed per project and store; see the maintainer run. |
wiki/ is not deployed: deploy.sh syncs named surfaces into BOB_HOME, and
the wiki is not one of them.
Page frontmatter
Section titled “Page frontmatter”A page starts with frontmatter that schemas/wiki-page.schema.json
validates, then a # Title line and the text.
---kind: failure-modeskills: [warp-drive, commit]evidence: - paulirv/bigbrain#1856 - loop-note:3f2a9c01b7defirst_seen: 2026-09-12last_seen: 2026-10-01count: 3defect: paulirv/bigbrain#1856status: active---
# The docs hook does not fire when there is nothing to tick| Key | Required | Value |
|---|---|---|
kind |
yes | failure-mode (what goes wrong and why), strategy (what worked) or workaround (a low-level fix that helped one model in one harness — a proposer treats it as evidence, not as a step to put in a skill) |
skills |
yes | One or more names of skills, commands or agents in this repo (skills/, commands/, agents/ or their registry/ twins) |
evidence |
yes | One or more trace references, in the forms below. Never copied trace text. |
first_seen, last_seen |
yes | YYYY-MM-DD; first_seen is not after last_seen |
count |
yes | Times seen, 1 or more. A recurrence bumps it; it never becomes a second page. |
defect |
no | owner/repo#n: the bug the pattern describes or works around. The page retires when it closes. |
status |
yes | active or retired |
retired_reason |
no | Written by retire.js when it retires the page |
The frontmatter is a strict YAML subset: key: value, key: [a, b], or key:
followed by - item lines. Anything else is a lint error, so every reader
parses a page the same way.
Evidence ref forms
Section titled “Evidence ref forms”| Form | Points at |
|---|---|
#N, owner/repo#N |
An issue: a lesson, a decision, a harness defect, a session report |
loop-note:<12 hex> |
A loop note, by its signature() |
ledger:<12 hex> |
A session-ledger record, by the first 12 hex of the SHA-1 of its line (ledger records carry no id) |
session:<id> |
A harness session id, 8 or more of A-Z a-z 0-9 _ - |
ext:<kind>:<hash> |
A record in another project’s store, opaque on purpose: the kind of trace and a 12–64 hex hash. A client’s repo name, path or issue URL never appears in a ref. |
The lint checks the form. Resolving a ref is the reader’s job.
The lint
Section titled “The lint”make check-wiki (part of make check) runs node scripts/wiki/lint.js.
--root DIR grades another checkout; --json prints wiki-lint/1. Exit 0 is
clean, 1 is findings, 2 is a usage or config error.
| Rule | Fails when |
|---|---|
page |
A page has no frontmatter, fails the schema, has a slug that is not lowercase kebab, has no evidence, cites a ref outside the forms above, names a skill that does not exist, or has first_seen after last_seen |
index |
wiki/index.md differs from what index.js renders from the pages |
log |
logs.md or skill-impact.md is missing, its header is not exact, or a row breaks the format below |
inject |
A file in hooks/, templates/hooks/, commands/, registry/commands/ or a provisions/*.json manifest names wiki/ |
tenant |
A path or line under wiki/ contains a tenant literal |
credential |
A line under wiki/ matches the credential catalogue and is not a placeholder; the match is printed masked to four characters |
allow |
scripts/checks/release-content-allow.json has an entry covering wiki/ |
The two tables
Section titled “The two tables”Both are markdown tables with a fixed header. A table with no rows is valid: that is how the repo ships them.
logs.md, one row per maintainer run:
| Date | Sources | Read | Refused | Created | Updated ||------|---------|------|---------|---------|---------|| 2026-10-09 | loop-notes, ledger | 12 | 1 | — | docs-hook-silent |Sources is a comma list of trace store names. Read and Refused (the
records the client-data scrub refused) are whole numbers. Created and
Updated are comma lists of existing page slugs, or — for none.
skill-impact.md, one row per proposal:
| Date | Skill | PR | Pages cited | Score before | Score after | Outcome ||------|-------|----|-------------|--------------|-------------|---------|| 2026-10-09 | commit | #4300 | docs-hook-silent | 0.50 | 0.62 | accepted |Skill is an existing skill, command or agent. PR is #N or owner/repo#N.
Pages cited is a non-empty list of existing slugs. The scores run 0 to 1:
before is the best validation score without the change, after is the score with
it. Outcome is accepted or rejected, and accepted requires after to be
strictly higher than before, the eval gate’s rule (#2390).
The index
Section titled “The index”node scripts/wiki/index.js # write wiki/index.mdnode scripts/wiki/index.js --check # exit 1 when the committed index is staleOne line per active page, grouped by kind and sorted by slug: title, skills, count, last seen and defect. Retired pages are left out.
Retirement
Section titled “Retirement”node scripts/wiki/retire.js # report: what would retire, what is stalenode scripts/wiki/retire.js --apply # retire pages whose defect closednode scripts/wiki/retire.js --max-age-days 90 # staleness threshold (default 180)| Rule | What happens |
|---|---|
| Defect closed | An active page whose defect: issue is closed retires. The state comes from scripts/lib/defect-status.js, cached for 6 hours. A forge that cannot be reached gives unknown, which counts as open: a page never retires on a failed lookup. --apply sets status: retired, adds a retired_reason: line, changes nothing else, and regenerates the index. |
| Stale | An active page whose last_seen is older than the maximum age is listed. Nothing changes, even with --apply: an old pattern may still be true. BOB_WIKI_STALE_DAYS sets the default age. |
| Recurrence | The maintainer’s job: a repeat is new evidence on the existing page, not a new page, and a retired page that recurs is reopened. |
A retired page stays in patterns/ and in git history. --json prints
wiki-retire/1. Exit 0 means nothing to retire, or retired with --apply; 1
means pages would retire on a dry run.
The maintainer run
Section titled “The maintainer run”bob wiki maintain (scripts/wiki/maintain.js, #2389)
writes patterns/, logs.md, index.md and the watermark. /trace-mining and
bob tick call it. The how-to is Consolidate traces into the wiki.
bob wiki maintain [--project DIR] [--source DIR] [--dry-run] [--max-records N] [--max-chars N] [--since YYYY-MM-DD] [--json]| Step | Contract |
|---|---|
| Collect | One project’s stores: loop-notes, decision-log, harness-defects, ledger (no-trigger, improvised), lessons (open), session-reports. Only records after the watermark; a store with no watermark starts at --since (default 30 days back). Each record carries a ref in an evidence form: bigbrain records are cited directly, any other project’s only as ext:<kind>:<hash>. A bigbrain project is any checkout or worktree sharing BOB_SOURCE’s git directory. |
| Scrub | A record from another project that contains a tenant literal is refused. A record matching the credential catalogue is refused, from any project. With no operator resolved, every record from another project is refused. Refused records are counted and consumed, never written. |
| Bound | Oldest first, at most --max-records (8) kept records, each cut to --max-chars (15,000). The rest waits for the next run. |
| Consolidate | One claude -p call with tools disallowed. The prompt is registry/agents/wiki-maintainer.md, the known items, the current index and pages, and the packet, all on stdin. The answer is one JSON object {edits: [...], notes}. BOB_WIKI_MAINTAINER names another command with the same contract. |
| Apply | The script owns the frontmatter. create needs a kebab slug, a kind, at least one existing skill, a title and at least one packet ref; first_seen, last_seen and count come from the cited records. update merges new refs, bumps count by each ref added or recurring, extends last_seen, appends the optional text as a dated paragraph, and reopens a retired page with a note. A ref the page already cites recurs when its record is newer than last_seen. An unknown op, an invented ref, an unknown skill or an update of a missing page is refused and listed in the PR. Nothing is deleted or rewritten. |
| Propose | Through a worktree on wiki-maintain/<date>-<project key>-<hash> from the main branch: the edits, the watermark, one logs.md row and the regenerated index. The wiki lint grades the result first; a finding under wiki/ stops the run. Then one commit (through the repo’s hooks), a push and one PR with the packet summary. The checkout is never touched and master never receives a commit. |
The watermark is wiki/.maintain-state.json: {version, projects: {<key>: {<store>: {ts, key}}}}, where <key> is bigbrain or ext-<12 hex> (a hash of
the project’s origin, never its name). The run also mirrors it to
$BOB_HOME/.wiki-maintain-state.json, and each store reads the later of the two
positions. The mirror covers a run whose PR is still open on this machine; the
committed copy covers every machine after the merge. A run over the same inputs
is therefore a no-op: no agent call, no branch, no PR, no log row.
| Exit | Meaning |
|---|---|
| 0 | opened (a PR), noop (nothing new) or dry-run |
| 1 | the run failed (the agent, the lint, the push or the PR); nothing is consumed and the next run retries |
| 2 | usage or config: no BOB_SOURCE checkout, or no wiki store in it |
--json prints wiki-maintain/1: verdict, project {key, bigbrain}, per-store
sources {new, read, refused, error}, read, refused, left_over, the
packet (refs, never text), refusals, watermark, created, updated,
reopened, rejected, pr, branch and reason.
Client data
Section titled “Client data”The wiki is in the product repository, and every client installs from a tag of it. A client project’s traces may teach the wiki about a BoB item; no client fact may reach it — no client code, path, issue text or name.
Two gates hold that line:
- The lint, in
make check, runs the release content gate’s tenant and credential rules over every file underwiki/. The tenant literals come from the operator profile’stenants[]. With no operator resolved, the lint printstenant rule: not runand grades everything else. - The release content gate (reference) reads
every tracked file at release time,
wiki/included, and refuses a release when no operator resolves. The lint fails if its allow-list ever exemptswiki/.
Who reads the wiki
Section titled “Who reads the wiki”Only the skill proposer (#2391).
No SessionStart hook injects it, no command loads it, and it is not a
provisioned item. The paper behind the design found that an agent with the
wiki in its context solves tasks from the wiki, so its traces stop showing what
the skills lack. The lint’s inject rule keeps it that way.
See also
Section titled “See also”- Skill evolution: traces, a wiki and skills — the design
- Release Content Gate — the release-time client-data barrier
- Tracker labels — the issues pages cite as evidence