librarian — the single documentation owner
Requires: the sibling protocols skill (shared protocol masters) and a valid skills.config.json (create with the config skill). Missing either → halt with that exact pointer; never guess.
Docs names come from config. Every docs/… path below is the DEFAULT. Resolve folder and file names from skills.config.json → docs.layout (defaults when unset) before reading or writing — a path typed from memory writes a second tree beside the real one. See ../protocols/references/docs-convention.md.
Project rules. Read .supermodo/rules/librarian.md if present, plus any
.supermodo/rules/INDEX.md rows naming librarian — that file IS this project's
librarian process and replaces the defaults below wherever they overlap. Contract:
../protocols/references/rules.md. Never in that file, so never switchable off:
sole ownership of docs/, never inventing technical content, never hand-editing
generated files, never mutating git, and every guarantee under "Lifecycle pass"
below. Starting point: rules-templates/standard.md.
Sole owner of documentation mutations. Never invent technical content; docs
reflect what code and verification evidence establish, nothing more. Every
run starts at the docs router (docs.entry from config, default
docs/README.md). Never infer current work from docs/archive/.
Read ../protocols/references/docs-convention.md (the layout + rules you enforce),
../protocols/references/reports.md (drift/decision inputs), ../protocols/references/questions.md,
../protocols/references/grilling.md (for --task intake), and
../protocols/references/promotion.md (for --promote and --absorb). Validate config FIRST
per the config contract — halt on missing/invalid config, naming the field,
and point at config. Never mutate git (no add/commit/merge/rebase/push).
Config & scripts
- Read
skills.config.json; verify configVersion: 1 (lower → halt, run
config --upgrade; higher → halt, update the installed skills).
- Docs router =
docs.entry (default docs/README.md).
- Docs scripts resolve relative to THIS installed skill folder:
scripts/docs-check.ts, scripts/docs-generate.ts (plain Node, zero
deps) — invoked
node <skill-dir>/scripts/docs-check.ts <project-root> <docs.entry> [docs.conventions]
(always pass the configured docs.entry as the second argument — both
scripts derive the docs directory from it — and docs.conventions as the
third when set).
Only when commands.docsCheck / commands.docsGenerate are set in config
do those argv arrays override the bundled scripts (a project override, not
a config-supplied path to the bundle). First use of a configured command
in a session requires explicit user approval.
Modes
- no args — full lifecycle pass (below).
work (standalone closeout) and
flow stage 7 invoke this.
--backlog <op> — operate ONLY on docs/work/BACKLOG.md (below).
--task [description] — new-task intake (below): grill → create the
triad.
--priorities — write confirmed triage answers into the items they
belong to (below). Nothing else.
--promote <report-path> [finding-id…] — turn named findings from a
run artifact into work items (below). User-invoked only.
--absorb — one-time, explicit-only sweep of pre-existing
documentation outside the convention (below). Never runs implicitly.
Never combine a backlog op, --task, --priorities, --promote, or
--absorb with the full lifecycle pass implicitly.
--task intake
Turn a request into a docs/work/ triad via the grilling protocol —
flat (work/<task-slug>/) by default, or inside a program
(work/<program>/NN-<slug>/, next free NN) when the user names one or
the task clearly belongs to an existing program (confirm, never guess).
Three sources feed it:
- free text — full intake (the steps below);
--backlog graduate <slug> — this same flow, seeded from that
backlog entry;
- an existing
docs/work/ triad (flat or program initiative) — no
creation: validate it
against the convention, grill ONLY the gaps found (missing acceptance
evidence, stale plan, tasks without IDs), and refine in place.
Confirm the ask. Until grill resolves and the user signs off, hold the
proposal in session state — create/edit NO documentation file yet.
Run the grilling protocol (invoke grill, or follow
../protocols/references/grilling.md directly): twin-agent adversarial interview —
independent plans, disprove rounds, class-scoped question routing, custom
answers re-fought once. If the opposite provider is unavailable, degrade
honestly (labeled single-model), never fake a second opinion.
On user sign-off, create the triad from the convention:
spec.md — goal, non-goals, scope, acceptance evidence, plus the work
metadata from the docs convention: Created: YYYY-MM-DD, a Priority:
line from the worklist intake questions
(../protocols/references/worklist.md — ask them here, they are part
of intake), and a ## Open questions checklist with immutable
<!-- question:slug --> IDs for anything the grill left owed by the
user. One priority per triad — if the grill settled on work that
does not share one, that is more than one item
(../protocols/references/promotion.md).
plan.md — approach, steps, risks, alternatives considered.
tasks.md — checklist with immutable inline task IDs
(- [ ] Do X <!-- task:do-x -->), kebab-case, unique, never reused.
Durable decisions → new ADRs; both positions of each resolved question
logged.
If it graduated from a backlog entry, replace that entry with a dated
graduation pointer to the new triad (never erase history), and carry its
stored priority across — it was already answered and confirmed by the user,
and re-asking is how a frozen value drifts. Ask the intake questions only
when the entry carried none.
Carry the VALUE, re-emit the field name. The two files spell the field
differently — priority: P1 — … indented under a backlog entry,
Priority: P1 — … at the top level of spec.md. Copying the source line
verbatim lands a lowercase, indented key in spec.md, which the worklist
reads as no valid priority at all and renders as provisional P2 — unset.
The backlog entry is being replaced by a pointer in this same step, so the
confirmed P0 is then gone from both files. Take everything after the colon
and write Priority: <that value>.
A priority-source: derived marker on the entry carries across too, as
Priority-source: on the triad. Dropping it graduates an unconfirmed rank
into a confirmed-looking one — the same silent loss as above, running the
other way, and worse because it destroys the only record that nobody chose
the value.
Run docs-generate, then docs-check. Report.
Do not implement the plan, edit production code, or start work.
--backlog operations (on docs/work/BACKLOG.md)
list [term] — show matching live and struck-through entries.
add <slug> <text> — entry in the convention's exact grammar
(- **<slug>** (YYYY-MM-DD): <text> — see Dependencies in the docs
convention) under the best existing section; keep the user's wording, add
constraints as indented lines. Dependencies use the exact form
depends: <slug>[, <slug>…] on its own indented line (the only
machine-parsed constraint). Run the worklist intake questions
(../protocols/references/worklist.md) and record the confirmed
priority: as a second indented line; the user may decline, leaving the
entry provisional.
edit <slug> <text> — change only the named entry.
drop|remove <slug> <reason> — strike through with a dated reason
(remove is a compat alias); never erase history.
reap — delete only already-dropped entries after confirming their
disposition is recorded elsewhere or intentionally abandoned.
graduate <slug> — run --task intake seeded from that entry.
next — alias for the next skill: hand over to it and let it run in full
(its own board, its own triage gate, its own report and page). This op is a
redirect, not a librarian operation: none of the --backlog rules above
apply to it, and it is NOT covered by "backlog ops write no report" —
suppressing next's report because it was reached through this alias would
lose the board. Librarian defines no selection rules of its own; selection
stays with the user.
--priorities — record confirmed triage answers
The receiving door for next --triage. That skill runs the interview and
owns the semantics; it cannot write documentation, so the confirmed lines
arrive here. This mode exists so triage answers reach disk in the same run
they were given — a priority the user confirmed and nobody stored will be
asked for again, which is the one outcome triage must never produce.
Input arrives in the invocation itself — one pair per line, nothing else:
work:csv-export — P2 — capability: exports are the top support request
backlog:rate-limit-headers — P3 — improvement: nice-to-have for API consumers
Identity (work:<slug>, work:<program>/NN-<slug> or backlog:<slug>), an
em dash, then the priority VALUE — P<0-3> — <classification>: <justification>
and nothing more. The value carries no field name: the Priority: /
priority: prefix belongs to the destination file and step 3 adds it, so a
line arriving with one already attached has it stripped, never doubled.
You did not see the interview that produced these and must not reconstruct it:
what is in the list is what gets written, and if the list is empty or absent,
say so and write nothing rather than going looking for answers elsewhere.
Resolve each identity to its file: a triad → its spec.md; a backlog
entry → its line in docs/work/BACKLOG.md. Unresolvable or ambiguous →
write nothing for that one and report it; never guess which item was meant.
Validate each line against the worklist grammar
(../protocols/references/worklist.md: P<0-3> — <classification>: <justification>). Malformed → reject that line, report it, keep going.
Look before writing, then write ONE field. Triage collects items whose
priority line is missing or malformed, so "no valid priority" does not
mean "no priority line" — appending to a file that already has a broken one
leaves two, which the grammar forbids and which makes every later reader
disagree about the real value. Scan the destination for any existing
priority field first, case-insensitively — Priority-source: is a
different field and never counts as one, or confirming a derived item
would read as "two priority fields" and refuse the one write it exists
for — and act on what is there:
| found in the destination |
do |
| nothing |
add the field: Priority: on its own line in spec.md, priority: indented under the entry in BACKLOG.md |
| one MALFORMED field |
replace that line in place — same position, correct grammar. This is the repair triage was run for. |
one VALID field marked Priority-source: derived |
replace the value in place and delete the marker line. This is the normal path, not an override: the item was ranked by a tool, the interview is the human confirming it, and an answer that leaves the marker behind means --triage will ask again next week. Delete the marker even when the confirmed value equals the derived one — what changed is who owns it. |
| one VALID field, unmarked |
write nothing, report the conflict, leave the stored value alone — UNLESS the user directed this change themselves, naming the item and the new value. The refusal exists to stop silent re-triage, not to stop the owner correcting a value. Report every replacement, with the old value. |
| two or more priority fields |
write nothing, report it for explicit repair. Which one the user meant is not knowable, and picking one silently discards the other. |
Never append a second field on any path. docs-check runs at step 5, after
the write — it reports a duplicate, it does not prevent one.
Touch no other CONTENT: no lifecycle pass, no archiving, no promotion, no
other field of any file, no file not named in the list.
Run docs-generate, then docs-check. Generated navigation is mechanical
output, not content — refreshing it is expected here and is the one thing
step 4 does not forbid. Report per item: written, rejected (with why), or
already set.
Report the outcome per item so the caller can tell the user exactly which
answers are now stored and which are not.
--promote — turn findings into items
Receives run artifacts: a hunt report, a tests audit, their shards.
../protocols/references/promotion.md owns the semantics — read it and
follow it literally. Nothing here restates it.
/supermodo:librarian --promote <report-path> [finding-id…]
User-invoked only. No finding ids given → ask which to promote, default none.
No grill: a confirmed finding already survived a finder and a skeptic.
With nobody to ask (a subagent or flow run), selection still blocks —
no ids, no promotion — but grouping and priority proceed on their derived
values. Each such item gets a Priority-source: derived — <assumption> <date>
line naming what was assumed, and the same question goes in the report's
questions. Report status: needs-input: the work is startable, the ranking
is the tool's until someone confirms it.
- Resolve the report path (containment per the reports protocol). Read the
findings from the machine-readable record, never the prose; no record →
refuse, naming the skill that owes one.
- Derive the shard directory, require the report's
findings frontmatter to
agree, and check every id carries its run_stamp. Track findings by the
pair (run identity + id) throughout.
- Keep only promotable verdicts. Name every refusal and why.
- Never assign, adjust or infer a severity. Missing → hand it back.
- Preflight, unlocked (it informs step 6, which waits on a person): scan
Promoted-from / Promoted-ids across live and archived triads. Report
what is already promoted and where. Never delete or replace anything.
- Group, then settle each group's priority — mechanical for hunt defects,
asked once per group otherwise. Show the grouping before writing.
- Take the report lock, re-run the preflight inside it, create what was
confirmed one item at a time and atomically — assemble each in a temp
directory, check it with
node <skill-dir>/scripts/docs-check.ts --item <that directory>, then rename it into docs/work/ — extend rather than
duplicate a live match, and release the lock on every exit.
- Touch
BACKLOG.md only when the user asked for an entry by name.
- Run docs-generate, then docs-check. Report per finding: which item it
became, or why it did not.
--absorb — sweep pre-existing documentation (explicit flag only)
One-time onboarding sweep for repos that had documentation before
supermodo. It runs ONLY when invoked with this flag — it is not part of the
lifecycle pass; config bootstrap directs the user to run it once after
scaffolding when its scan saw docs outside the target paths.
Discover candidates read-only, in BOTH places docs hide:
- OUTSIDE
docs/: root ARCHITECTURE.md/CONTRIBUTING.md, notes/,
wiki exports, per-package README.mds, …
- INSIDE
docs/ but outside the convention: any file that is not the
router, CONVENTIONS.md, or under work/, decisions/,
reference/, archive/ — e.g. a pre-existing docs/architecture.md
or docs/setup/ from before supermodo.
Exclude vendored/generated content (node_modules, lockfiles, files
carrying the <!-- supermodo:generated --> marker). The root
README.md is a candidate for LINKING from the router, never for
moving.
Classify each candidate from its content: verified contract →
docs/reference/; durable decision → new ADR; planned/ongoing work →
backlog entry or triad; tool- or ecosystem-facing file that must stay at
its path (per-package README, CONTRIBUTING, LICENSE-adjacent) → keep in
place + link from the router; stale or superseded → deletion candidate.
Anything classified as work gets the worklist intake questions
(../protocols/references/worklist.md, "Every item is born with a
priority") as part of its disposition — asked once, with the file in front
of the user, before the entry or triad is written. An absorb is usually the
FIRST supermodo run in a repository that already has years of work in it;
skipping the questions here is what produces a first board of thirty
P2 — unset rows, which is precisely the state the user is running absorb
to get out of. Batch them with the file's disposition questions rather than
as a second pass — one interruption per file, not two. A decline leaves
that item provisional, which is fine; not asking is not.
One file is not one item. A TODO.md listing thirty unrelated things
of different urgency absorbs as several items, by the cohesion test in
../protocols/references/promotion.md — never as one triad whose priority
is whichever line the reader noticed first. Absorb is usually the first
supermodo run in a repository with years of work in it, so this is where a
single mis-sized item does the most damage.
Disposition plan — approval-gated, two questions per file (questions
protocol; files may be grouped by proposed disposition, but every file
is listed individually).
Write the plan and render it BEFORE asking
(../protocols/references/reports.md, "Show what you are asking about") —
an absorb sweep routinely covers forty files, and forty dispositions read
as chat bullets get approved unread. Draw it as a supermodo:tree of the
proposed destination, every candidate appearing once under where it is
going, state ok moved / warn kept in place and linked / bad
deleted, and meta carrying the reason and the inbound-dependency count.
The per-file questions follow it, and the report is where the user checks
what they are answering about.
The questions themselves:
- Keep the content? Is this file relevant enough for its content to
live in the documentation — and where (reference / ADR / backlog /
stay-and-link)?
- Delete the original? Asked only WITH the dependency list: every
inbound link, code reference (grep), and tooling/CI path that points
at the file. Unresolved dependents → never delete; propose updating
the dependents or leaving a pointer stub instead.
Execute only the approved dispositions (write-temp-then-rename).
Moves carry content verbatim; anything condensed is labeled a summary
with a pointer to its source. Nothing is deleted or moved without its
per-file approval.
Run docs-generate, then docs-check. Complete the report started at step 3
with the per-file outcomes — including every file deliberately left
untouched — and move its frontmatter off needs-input.
questions is emptied either way; the questions were answered, and
that is true regardless of how execution then went. Leaving them parks the
run in the archive's "Needs you" tab forever.
status is earned, not assumed. ok ONLY when every approved
disposition executed and both docs-generate and docs-check came back
clean. Anything else — a move that failed, a delete that could not
complete, a red docs-check — is failed, naming the exact operation that
broke and the file it was on.
This step moves and deletes documentation. A partial absorb leaves the
docs tree half-migrated, with links pointing at files that are no longer
there, and it is the single most expensive state this skill can produce.
Reporting that as ok because the run reached the end hides it at exactly
the moment the user needs to see it — and the archive, which is where they
would look, would be showing a clean green run.
Lifecycle pass (no args)
The sequence is the project's. It lives in .supermodo/rules/librarian.md
— materialized from rules-templates/standard.md when the project has not
written its own — and that file says which steps run, in what order, and when
a pass is triggered. What follows is what a pass must GUARANTEE whatever order
it runs in; none of it is in the rules file, so none of it can be switched off:
- The docs checker runs, and its complete issue list is the pass's worklist. A
pass never ends with the checker unrun or its output unread.
- Completed work is verified against CODE AND EVIDENCE before anything is
promoted or archived. A spec or plan is never evidence.
- The reference tree holds only verified contracts. An assumption is promoted
only when evidence, verification date and revalidation trigger are all
recorded.
- ADR bodies and original decision metadata are immutable after acceptance;
only lifecycle fields update, and only mechanically.
- Archiving moves the whole work folder VERBATIM, under the convention's
flattened naming (
YYYY-MM-<task-slug>, initiatives
YYYY-MM-<program>-<NN-slug>; a program whose last initiative archives sends
its README to YYYY-MM-<program>/ and the empty dir is removed).
- Generated files and nav sections are never hand-edited. Navigation is
regenerated and the checker re-run before the pass is called done.
- Mechanical drift in a reference doc whose code changed is repaired;
a SUBSTANTIVE conflict stops and goes to the user (questions protocol).
Nothing is written that current code and evidence do not establish.
Flow integration (stage 7)
When invoked as flow stage 7, additionally ingest the run's stage reports
(../protocols/references/reports.md format): read every drift_notes and queued
decisions entry from stages 1–6 and persist them here — ADRs for durable
decisions, triad/reference updates for drift. This is the ONLY stage besides
stage 1 where docs mutate; stage agents only reported drift, they never wrote.
Resolve real paths and stay within the project before any .skills/supermodo/
read (containment rule).
Guardrails
- Single documentation owner: never delegate doc mutation to a second owner;
other skills report drift, librarian resolves it once.
- Librarian is the ONLY writer of
Priority:, Priority-source:, Mixed:,
Created: and ## Open questions. The next skill and every other reader
hands its proposed lines here; they never write docs themselves.
- Librarian never invents or revises a finding's severity — that judgment
belongs to the subagents that produced it
(
../protocols/references/promotion.md).
- Never hand-edit generated files or nav sections.
- Never read archive prose by default — only for a specifically identified
provenance need.
- Never mutate git.
- Report any technical judgment that cannot be established from current code
and evidence, rather than inventing it.
Report
Summarize: task closeout, reconciled instructions/agent definitions,
promoted / split / archived / generated files, docs-check result before and
after, and any user decisions still required. Concise chat reporting per
output.verbosity (default concise); generated artifacts always follow the
convention formats.
Persist and publish
Per ../protocols/references/reports.md ("What earns a report"), which of
librarian's modes produce one is not uniform — the rule is whether the run
produced reasoning that exists nowhere else:
| mode |
report |
| lifecycle pass (no args) |
yes — the docs-check delta, what was promoted, archived and split, and the decisions still owed live only here |
--task |
yes — the grill transcript and the resolved intake answers exist nowhere but this file |
--promote |
yes — which findings became which items, the bands confirmed, and every finding deliberately left in the report live only here; without it the user cannot audit the promotion and will redo it by hand |
--absorb |
yes — the per-file dispositions, including every file deliberately left untouched |
--backlog add/edit/drop/reap/list |
no — write nothing, render nothing |
--backlog next |
not librarian's — this is an alias; the next skill runs and writes its own report exactly as it always does. Librarian adds nothing and suppresses nothing. |
--priorities |
no — the lines are in the files; the caller reports the outcome |
A backlog operation's entire result is the line it wrote in BACKLOG.md:
already permanent, already in git, and it reaches the user on the next board
as an item. A second copy under .skills/supermodo/ teaches nobody anything,
and a browser tab announcing a one-line insert is an interruption charged
against a five-second task. Say what changed in chat and stop — no file, no
page, no renderer call.
For the modes that DO earn one: write it to
.skills/supermodo/librarian/<YYYYMMDD-HHMMSS>.md, set task: when the run
was about one work item (--task always is), then publish it:
node <skills>/reports/scripts/render.ts --root <project-root> --report <that path>
and NAME the page in your final message. Sections, in this order: What
changed · Docs-check (issues before vs after as a two-bar
supermodo:bars, state bad → ok — a before/after pair is the
comparison a bar chart is for; when both numbers are zero, write the sentence
instead) · Promoted / archived · Decisions owed by the user (also in the
questions frontmatter — that is what surfaces them in the archive index).
Inside a flow run none of this applies: the stage report is the artifact and
the orchestrator renders the one run page.
1---2name: librarian3description: Sole owner of documentation mutations: run the lifecycle pass to close out completed work, reconcile docs and agent definitions with code, promote verified contracts, record ADRs, archive finished tasks, regenerate navigation, and repair links. Also manages the backlog, runs new-task intake, promotes hunt or test-audit findings into work items (--promote), and (with --absorb) performs the one-time sweep that classifies and absorbs pre-existing documentation into the convention. Use for docs maintenance, task closeout, documentation or instruction drift, backlog operations, `--task` intake, `--promote` of findings into triads, `--absorb` onboarding of existing docs, or a flow stage-7 alignment pass.4---56# librarian — the single documentation owner78> **Requires:** the sibling `protocols` skill (shared protocol masters) and a valid `skills.config.json` (create with the `config` skill). Missing either → halt with that exact pointer; never guess.910> **Docs names come from config.** Every `docs/…` path below is the DEFAULT. Resolve folder and file names from `skills.config.json` → `docs.layout` (defaults when unset) before reading or writing — a path typed from memory writes a second tree beside the real one. See `../protocols/references/docs-convention.md`.1112> **Project rules.** Read `.supermodo/rules/librarian.md` if present, plus any13> `.supermodo/rules/INDEX.md` rows naming `librarian` — that file IS this project's14> librarian process and replaces the defaults below wherever they overlap. Contract:15> `../protocols/references/rules.md`. Never in that file, so never switchable off:16> sole ownership of `docs/`, never inventing technical content, never hand-editing17> generated files, never mutating git, and every guarantee under "Lifecycle pass"18> below. Starting point: `rules-templates/standard.md`.1920Sole owner of documentation mutations. Never invent technical content; docs21reflect what code and verification evidence establish, nothing more. Every22run starts at the docs router (`docs.entry` from config, default23`docs/README.md`). Never infer current work from `docs/archive/`.2425Read `../protocols/references/docs-convention.md` (the layout + rules you enforce),26`../protocols/references/reports.md` (drift/decision inputs), `../protocols/references/questions.md`,27`../protocols/references/grilling.md` (for `--task` intake), and28`../protocols/references/promotion.md` (for `--promote` and `--absorb`). Validate config FIRST29per the config contract — halt on missing/invalid config, naming the field,30and point at `config`. Never mutate git (no add/commit/merge/rebase/push).3132## Config & scripts3334- Read `skills.config.json`; verify `configVersion: 1` (lower → halt, run35 `config --upgrade`; higher → halt, update the installed skills).36- Docs router = `docs.entry` (default `docs/README.md`).37- Docs scripts resolve **relative to THIS installed skill folder**:38 `scripts/docs-check.ts`, `scripts/docs-generate.ts` (plain Node, zero39 deps) — invoked40 `node <skill-dir>/scripts/docs-check.ts <project-root> <docs.entry> [docs.conventions]`41 (always pass the configured `docs.entry` as the second argument — both42 scripts derive the docs directory from it — and `docs.conventions` as the43 third when set).44 Only when `commands.docsCheck` / `commands.docsGenerate` are set in config45 do those argv arrays override the bundled scripts (a project override, not46 a config-supplied path to the bundle). First use of a configured command47 in a session requires explicit user approval.4849## Modes5051- **no args** — full lifecycle pass (below). `work` (standalone closeout) and52 `flow` stage 7 invoke this.53- **`--backlog <op>`** — operate ONLY on `docs/work/BACKLOG.md` (below).54- **`--task [description]`** — new-task intake (below): grill → create the55 triad.56- **`--priorities`** — write confirmed triage answers into the items they57 belong to (below). Nothing else.58- **`--promote <report-path> [finding-id…]`** — turn named findings from a59 run artifact into work items (below). User-invoked only.60- **`--absorb`** — one-time, explicit-only sweep of pre-existing61 documentation outside the convention (below). Never runs implicitly.6263Never combine a backlog op, `--task`, `--priorities`, `--promote`, or64`--absorb` with the full lifecycle pass implicitly.6566## `--task` intake6768Turn a request into a `docs/work/` triad via the grilling protocol —69flat (`work/<task-slug>/`) by default, or inside a program70(`work/<program>/NN-<slug>/`, next free `NN`) when the user names one or71the task clearly belongs to an existing program (confirm, never guess).72Three sources feed it:7374- **free text** — full intake (the steps below);75- **`--backlog graduate <slug>`** — this same flow, seeded from that76 backlog entry;77- **an existing `docs/work/` triad** (flat or program initiative) — no78 creation: validate it79 against the convention, grill ONLY the gaps found (missing acceptance80 evidence, stale plan, tasks without IDs), and refine in place.81821. Confirm the ask. Until grill resolves and the user signs off, hold the83 proposal in session state — **create/edit NO documentation file yet**.842. Run the grilling protocol (invoke `grill`, or follow85 `../protocols/references/grilling.md` directly): twin-agent adversarial interview —86 independent plans, disprove rounds, class-scoped question routing, custom87 answers re-fought once. If the opposite provider is unavailable, degrade88 honestly (labeled single-model), never fake a second opinion.893. On user sign-off, create the triad from the convention:90 - `spec.md` — goal, non-goals, scope, acceptance evidence, plus the work91 metadata from the docs convention: `Created: YYYY-MM-DD`, a `Priority:`92 line from the worklist intake questions93 (`../protocols/references/worklist.md` — ask them here, they are part94 of intake), and a `## Open questions` checklist with immutable95 `<!-- question:slug -->` IDs for anything the grill left owed by the96 user. **One priority per triad** — if the grill settled on work that97 does not share one, that is more than one item98 (`../protocols/references/promotion.md`).99 - `plan.md` — approach, steps, risks, alternatives considered.100 - `tasks.md` — checklist with **immutable inline task IDs**101 (`- [ ] Do X <!-- task:do-x -->`), kebab-case, unique, never reused.102 Durable decisions → new ADRs; both positions of each resolved question103 logged.1044. If it graduated from a backlog entry, replace that entry with a dated105 graduation pointer to the new triad (never erase history), and carry its106 stored priority across — it was already answered and confirmed by the user,107 and re-asking is how a frozen value drifts. Ask the intake questions only108 when the entry carried none.109110 **Carry the VALUE, re-emit the field name.** The two files spell the field111 differently — ` priority: P1 — …` indented under a backlog entry,112 `Priority: P1 — …` at the top level of `spec.md`. Copying the source line113 verbatim lands a lowercase, indented key in `spec.md`, which the worklist114 reads as no valid priority at all and renders as provisional `P2 — unset`.115 The backlog entry is being replaced by a pointer in this same step, so the116 confirmed P0 is then gone from both files. Take everything after the colon117 and write `Priority: <that value>`.118119 **A `priority-source: derived` marker on the entry carries across too**, as120 `Priority-source:` on the triad. Dropping it graduates an unconfirmed rank121 into a confirmed-looking one — the same silent loss as above, running the122 other way, and worse because it destroys the only record that nobody chose123 the value.1245. Run docs-generate, then docs-check. Report.125126Do not implement the plan, edit production code, or start `work`.127128## `--backlog` operations (on `docs/work/BACKLOG.md`)129130- `list [term]` — show matching live and struck-through entries.131- `add <slug> <text>` — entry in the convention's exact grammar132 (`- **<slug>** (YYYY-MM-DD): <text>` — see Dependencies in the docs133 convention) under the best existing section; keep the user's wording, add134 constraints as indented lines. Dependencies use the exact form135 `depends: <slug>[, <slug>…]` on its own indented line (the only136 machine-parsed constraint). Run the worklist intake questions137 (`../protocols/references/worklist.md`) and record the confirmed138 `priority:` as a second indented line; the user may decline, leaving the139 entry provisional.140- `edit <slug> <text>` — change only the named entry.141- `drop|remove <slug> <reason>` — strike through with a dated reason142 (`remove` is a compat alias); never erase history.143- `reap` — delete only already-dropped entries after confirming their144 disposition is recorded elsewhere or intentionally abandoned.145- `graduate <slug>` — run `--task` intake seeded from that entry.146- `next` — alias for the `next` skill: hand over to it and let it run in full147 (its own board, its own triage gate, its own report and page). This op is a148 redirect, not a librarian operation: none of the `--backlog` rules above149 apply to it, and it is NOT covered by "backlog ops write no report" —150 suppressing `next`'s report because it was reached through this alias would151 lose the board. Librarian defines no selection rules of its own; selection152 stays with the user.153154## `--priorities` — record confirmed triage answers155156The receiving door for `next --triage`. That skill runs the interview and157owns the semantics; it cannot write documentation, so the confirmed lines158arrive here. This mode exists so triage answers reach disk in the same run159they were given — a priority the user confirmed and nobody stored will be160asked for again, which is the one outcome triage must never produce.161162**Input arrives in the invocation itself** — one pair per line, nothing else:163164```165work:csv-export — P2 — capability: exports are the top support request166backlog:rate-limit-headers — P3 — improvement: nice-to-have for API consumers167```168169Identity (`work:<slug>`, `work:<program>/NN-<slug>` or `backlog:<slug>`), an170em dash, then the priority VALUE — `P<0-3> — <classification>: <justification>`171and nothing more. The value carries no field name: the `Priority:` /172` priority:` prefix belongs to the destination file and step 3 adds it, so a173line arriving with one already attached has it stripped, never doubled.174175You did not see the interview that produced these and must not reconstruct it:176what is in the list is what gets written, and if the list is empty or absent,177say so and write nothing rather than going looking for answers elsewhere.1781791. Resolve each identity to its file: a triad → its `spec.md`; a backlog180 entry → its line in `docs/work/BACKLOG.md`. Unresolvable or ambiguous →181 write nothing for that one and report it; never guess which item was meant.1822. Validate each line against the worklist grammar183 (`../protocols/references/worklist.md`: `P<0-3> — <classification>:184 <justification>`). Malformed → reject that line, report it, keep going.1853. **Look before writing**, then write ONE field. Triage collects items whose186 priority line is missing *or malformed*, so "no valid priority" does not187 mean "no priority line" — appending to a file that already has a broken one188 leaves two, which the grammar forbids and which makes every later reader189 disagree about the real value. Scan the destination for any existing190 priority field first, case-insensitively — `Priority-source:` is a191 different field and never counts as one, or confirming a derived item192 would read as "two priority fields" and refuse the one write it exists193 for — and act on what is there:194195 | found in the destination | do |196 | --- | --- |197 | nothing | add the field: `Priority:` on its own line in `spec.md`, ` priority:` indented under the entry in `BACKLOG.md` |198 | one MALFORMED field | replace that line in place — same position, correct grammar. This is the repair triage was run for. |199 | one VALID field marked `Priority-source: derived` | replace the value in place and **delete the marker line**. This is the normal path, not an override: the item was ranked by a tool, the interview is the human confirming it, and an answer that leaves the marker behind means `--triage` will ask again next week. Delete the marker even when the confirmed value equals the derived one — what changed is who owns it. |200 | one VALID field, unmarked | write nothing, report the conflict, leave the stored value alone — UNLESS the user directed this change themselves, naming the item and the new value. The refusal exists to stop silent re-triage, not to stop the owner correcting a value. Report every replacement, with the old value. |201 | two or more priority fields | write nothing, report it for explicit repair. Which one the user meant is not knowable, and picking one silently discards the other. |202203 Never append a second field on any path. `docs-check` runs at step 5, after204 the write — it reports a duplicate, it does not prevent one.2054. Touch no other CONTENT: no lifecycle pass, no archiving, no promotion, no206 other field of any file, no file not named in the list.2075. Run docs-generate, then docs-check. Generated navigation is mechanical208 output, not content — refreshing it is expected here and is the one thing209 step 4 does not forbid. Report per item: written, rejected (with why), or210 already set.211212Report the outcome per item so the caller can tell the user exactly which213answers are now stored and which are not.214215## `--promote` — turn findings into items216217Receives run artifacts: a `hunt` report, a `tests audit`, their shards.218**`../protocols/references/promotion.md` owns the semantics — read it and219follow it literally.** Nothing here restates it.220221```222/supermodo:librarian --promote <report-path> [finding-id…]223```224225User-invoked only. No finding ids given → ask which to promote, default none.226**No grill:** a confirmed finding already survived a finder and a skeptic.227228**With nobody to ask** (a subagent or `flow` run), selection still blocks —229no ids, no promotion — but grouping and priority proceed on their derived230values. Each such item gets a `Priority-source: derived — <assumption> <date>`231line naming what was assumed, and the same question goes in the report's232`questions`. Report `status: needs-input`: the work is startable, the ranking233is the tool's until someone confirms it.2342351. Resolve the report path (containment per the reports protocol). Read the236 findings from the machine-readable record, never the prose; no record →237 refuse, naming the skill that owes one.2382. Derive the shard directory, require the report's `findings` frontmatter to239 agree, and check every id carries its `run_stamp`. Track findings by the240 pair (run identity + id) throughout.2413. Keep only promotable verdicts. Name every refusal and why.2424. Never assign, adjust or infer a severity. Missing → hand it back.2435. **Preflight, unlocked** (it informs step 6, which waits on a person): scan244 `Promoted-from` / `Promoted-ids` across live and archived triads. Report245 what is already promoted and where. Never delete or replace anything.2466. Group, then settle each group's priority — mechanical for hunt defects,247 asked once per group otherwise. Show the grouping before writing.2487. **Take the report lock**, re-run the preflight inside it, create what was249 confirmed one item at a time and atomically — assemble each in a temp250 directory, check it with `node <skill-dir>/scripts/docs-check.ts --item251 <that directory>`, then rename it into `docs/work/` — extend rather than252 duplicate a live match, and release the lock on every exit.2538. Touch `BACKLOG.md` only when the user asked for an entry by name.2549. Run docs-generate, then docs-check. Report per finding: which item it255 became, or why it did not.256257## `--absorb` — sweep pre-existing documentation (explicit flag only)258259One-time onboarding sweep for repos that had documentation before260supermodo. It runs ONLY when invoked with this flag — it is not part of the261lifecycle pass; `config` bootstrap directs the user to run it once after262scaffolding when its scan saw docs outside the target paths.2632641. **Discover** candidates read-only, in BOTH places docs hide:265 - OUTSIDE `docs/`: root `ARCHITECTURE.md`/`CONTRIBUTING.md`, `notes/`,266 wiki exports, per-package `README.md`s, …267 - INSIDE `docs/` but outside the convention: any file that is not the268 router, `CONVENTIONS.md`, or under `work/`, `decisions/`,269 `reference/`, `archive/` — e.g. a pre-existing `docs/architecture.md`270 or `docs/setup/` from before supermodo.271272 Exclude vendored/generated content (`node_modules`, lockfiles, files273 carrying the `<!-- supermodo:generated -->` marker). The root274 `README.md` is a candidate for LINKING from the router, never for275 moving.2762. **Classify** each candidate from its content: verified contract →277 `docs/reference/`; durable decision → new ADR; planned/ongoing work →278 backlog entry or triad; tool- or ecosystem-facing file that must stay at279 its path (per-package README, CONTRIBUTING, LICENSE-adjacent) → keep in280 place + link from the router; stale or superseded → deletion candidate.281282 **Anything classified as work gets the worklist intake questions**283 (`../protocols/references/worklist.md`, "Every item is born with a284 priority") as part of its disposition — asked once, with the file in front285 of the user, before the entry or triad is written. An absorb is usually the286 FIRST supermodo run in a repository that already has years of work in it;287 skipping the questions here is what produces a first board of thirty288 `P2 — unset` rows, which is precisely the state the user is running absorb289 to get out of. Batch them with the file's disposition questions rather than290 as a second pass — one interruption per file, not two. A decline leaves291 that item provisional, which is fine; not asking is not.292293 **One file is not one item.** A `TODO.md` listing thirty unrelated things294 of different urgency absorbs as several items, by the cohesion test in295 `../protocols/references/promotion.md` — never as one triad whose priority296 is whichever line the reader noticed first. Absorb is usually the first297 supermodo run in a repository with years of work in it, so this is where a298 single mis-sized item does the most damage.2993. **Disposition plan — approval-gated, two questions per file** (questions300 protocol; files may be grouped by proposed disposition, but every file301 is listed individually).302303 Write the plan and render it BEFORE asking304 (`../protocols/references/reports.md`, "Show what you are asking about") —305 an absorb sweep routinely covers forty files, and forty dispositions read306 as chat bullets get approved unread. Draw it as a `supermodo:tree` of the307 proposed destination, every candidate appearing once under where it is308 going, `state` `ok` moved / `warn` kept in place and linked / `bad`309 deleted, and `meta` carrying the reason and the inbound-dependency count.310 The per-file questions follow it, and the report is where the user checks311 what they are answering about.312313 The questions themselves:314 1. **Keep the content?** Is this file relevant enough for its content to315 live in the documentation — and where (reference / ADR / backlog /316 stay-and-link)?317 2. **Delete the original?** Asked only WITH the dependency list: every318 inbound link, code reference (grep), and tooling/CI path that points319 at the file. Unresolved dependents → never delete; propose updating320 the dependents or leaving a pointer stub instead.3214. **Execute** only the approved dispositions (write-temp-then-rename).322 Moves carry content verbatim; anything condensed is labeled a summary323 with a pointer to its source. Nothing is deleted or moved without its324 per-file approval.3255. Run docs-generate, then docs-check. Complete the report started at step 3326 with the per-file outcomes — including every file deliberately left327 untouched — and move its frontmatter off `needs-input`.328329 **`questions` is emptied either way**; the questions were answered, and330 that is true regardless of how execution then went. Leaving them parks the331 run in the archive's "Needs you" tab forever.332333 **`status` is earned, not assumed.** `ok` ONLY when every approved334 disposition executed and both docs-generate and docs-check came back335 clean. Anything else — a move that failed, a delete that could not336 complete, a red docs-check — is `failed`, naming the exact operation that337 broke and the file it was on.338339 This step moves and deletes documentation. A partial absorb leaves the340 docs tree half-migrated, with links pointing at files that are no longer341 there, and it is the single most expensive state this skill can produce.342 Reporting that as `ok` because the run reached the end hides it at exactly343 the moment the user needs to see it — and the archive, which is where they344 would look, would be showing a clean green run.345346## Lifecycle pass (no args)347348**The sequence is the project's.** It lives in `.supermodo/rules/librarian.md`349— materialized from `rules-templates/standard.md` when the project has not350written its own — and that file says which steps run, in what order, and when351a pass is triggered. What follows is what a pass must GUARANTEE whatever order352it runs in; none of it is in the rules file, so none of it can be switched off:353354- The docs checker runs, and its complete issue list is the pass's worklist. A355 pass never ends with the checker unrun or its output unread.356- Completed work is verified against CODE AND EVIDENCE before anything is357 promoted or archived. A spec or plan is never evidence.358- The reference tree holds only verified contracts. An assumption is promoted359 only when evidence, verification date and revalidation trigger are all360 recorded.361- ADR bodies and original decision metadata are immutable after acceptance;362 only lifecycle fields update, and only mechanically.363- Archiving moves the whole work folder VERBATIM, under the convention's364 flattened naming (`YYYY-MM-<task-slug>`, initiatives365 `YYYY-MM-<program>-<NN-slug>`; a program whose last initiative archives sends366 its README to `YYYY-MM-<program>/` and the empty dir is removed).367- Generated files and nav sections are never hand-edited. Navigation is368 regenerated and the checker re-run before the pass is called done.369- Mechanical drift in a reference doc whose code changed is repaired;370 a SUBSTANTIVE conflict stops and goes to the user (questions protocol).371 Nothing is written that current code and evidence do not establish.372373## Flow integration (stage 7)374375When invoked as `flow` stage 7, additionally ingest the run's stage reports376(`../protocols/references/reports.md` format): read every `drift_notes` and queued377`decisions` entry from stages 1–6 and persist them here — ADRs for durable378decisions, triad/reference updates for drift. This is the ONLY stage besides379stage 1 where docs mutate; stage agents only reported drift, they never wrote.380Resolve real paths and stay within the project before any `.skills/supermodo/`381read (containment rule).382383## Guardrails384385- Single documentation owner: never delegate doc mutation to a second owner;386 other skills report drift, librarian resolves it once.387- Librarian is the ONLY writer of `Priority:`, `Priority-source:`, `Mixed:`,388 `Created:` and `## Open questions`. The `next` skill and every other reader389 hands its proposed lines here; they never write docs themselves.390- Librarian never invents or revises a finding's severity — that judgment391 belongs to the subagents that produced it392 (`../protocols/references/promotion.md`).393- Never hand-edit generated files or nav sections.394- Never read archive prose by default — only for a specifically identified395 provenance need.396- Never mutate git.397- Report any technical judgment that cannot be established from current code398 and evidence, rather than inventing it.399400## Report401402Summarize: task closeout, reconciled instructions/agent definitions,403promoted / split / archived / generated files, docs-check result before and404after, and any user decisions still required. Concise chat reporting per405`output.verbosity` (default concise); generated artifacts always follow the406convention formats.407408## Persist and publish409410Per `../protocols/references/reports.md` ("What earns a report"), which of411librarian's modes produce one is **not** uniform — the rule is whether the run412produced reasoning that exists nowhere else:413414| mode | report |415| --- | --- |416| lifecycle pass (no args) | **yes** — the docs-check delta, what was promoted, archived and split, and the decisions still owed live only here |417| `--task` | **yes** — the grill transcript and the resolved intake answers exist nowhere but this file |418| `--promote` | **yes** — which findings became which items, the bands confirmed, and every finding deliberately left in the report live only here; without it the user cannot audit the promotion and will redo it by hand |419| `--absorb` | **yes** — the per-file dispositions, including every file deliberately left untouched |420| `--backlog add/edit/drop/reap/list` | **no** — write nothing, render nothing |421| `--backlog next` | **not librarian's** — this is an alias; the `next` skill runs and writes its own report exactly as it always does. Librarian adds nothing and suppresses nothing. |422| `--priorities` | **no** — the lines are in the files; the caller reports the outcome |423424A backlog operation's entire result is the line it wrote in `BACKLOG.md`:425already permanent, already in git, and it reaches the user on the next board426as an item. A second copy under `.skills/supermodo/` teaches nobody anything,427and a browser tab announcing a one-line insert is an interruption charged428against a five-second task. Say what changed in chat and stop — no file, no429page, no renderer call.430431For the modes that DO earn one: write it to432`.skills/supermodo/librarian/<YYYYMMDD-HHMMSS>.md`, set `task:` when the run433was about one work item (`--task` always is), then publish it:434435```436node <skills>/reports/scripts/render.ts --root <project-root> --report <that path>437```438439and NAME the page in your final message. Sections, in this order: **What440changed** · **Docs-check** (issues before vs after as a two-bar441`supermodo:bars`, `state` `bad` → `ok` — a before/after pair is the442comparison a bar chart is for; when both numbers are zero, write the sentence443instead) · **Promoted / archived** · **Decisions owed by the user** (also in the444`questions` frontmatter — that is what surfaces them in the archive index).445446Inside a `flow` run none of this applies: the stage report is the artifact and447the orchestrator renders the one run page.