docs: make every AGENTS.md cite code, not docs or issues #113

Merged
sulthan merged 1 commits from docs/agents-cite-code-only into main 2026-08-17 13:43:50 +07:00
Owner

Every AGENTS.md now cites code and nothing else.

Why

Two rot mechanisms, same symptom — an agent confidently follows a stale statement:

  1. Non-code citations. A spec, ADR, plan file, or issue records what was true when it was written. Nothing updates it when the decision reverses.
  2. Prose restating mechanism. The code changes, the paragraph doesn't, and the next reader trusts the paragraph.

Code is the only source true at read time.

What changed

All three files: removed every ADR ref, spec/plan pointer (docs/superpowers/specs/*, plans/*, docs/research/*), DEPLOY.md/REDEPLOY.md, docs/agents/*, and issue number. Facts those links carried are restated inline — the tea command set and the five triage label strings now live in the root Forge section. ### Domain docs is deleted: it pointed only at CONTEXT.md and docs/adr/, neither of which exists.

backend/ and userscript/: rewritten around derivability.

Class In code? Treatment
Structure — packages, routes, env vars, columns yes name the symbol, nothing else
Mechanism — what a function does yes symbol + one line
Rationale — why, what a "simplify" breaks no written out
Measurement — observation against a service we don't control no written out, dated

backend/AGENTS.md 20578 → 15512 bytes, userscript/AGENTS.md 7129 → 5912. Root grows 16905 → 19292: the cost of inlining the docs/agents/* facts plus the new rule.

Rule recorded in root as ## Writing an AGENTS.md. Sole non-code exception is a sibling AGENTS.md. Closing clause: every symbol named must exist, since a dead pointer is a bug rather than a stale sentence.

Harness-agnostic: dropped the Guidance for OpenCode (and Claude Code) openers for plain scope lines.

Verification

Applied the new rule to itself — extracted all 118 backticked identifiers across the three files and checked each against every .go, .js, .sql, .html and .css source. Zero repo symbols missing; the 8 non-matches are external (GM_setValue, navigator.webdriver, HeadlessChrome, curl, …).

That check caught a claim that was already lying on main: the cover section said CoverFetcher was gone, but NewCoverFetcher, TLSCoverFetcher and BrowserCoverFetcher are all live in internal/latest. Now names only the genuinely dead /img/kagane/{id} route. Exactly the failure the rule exists to prevent.

No code touched — documentation only, nothing to test.

Every `AGENTS.md` now cites code and nothing else. ## Why Two rot mechanisms, same symptom — an agent confidently follows a stale statement: 1. **Non-code citations.** A spec, ADR, plan file, or issue records what was true when it was written. Nothing updates it when the decision reverses. 2. **Prose restating mechanism.** The code changes, the paragraph doesn't, and the next reader trusts the paragraph. Code is the only source true at read time. ## What changed **All three files:** removed every ADR ref, spec/plan pointer (`docs/superpowers/specs/*`, `plans/*`, `docs/research/*`), `DEPLOY.md`/`REDEPLOY.md`, `docs/agents/*`, and issue number. Facts those links carried are restated inline — the `tea` command set and the five triage label strings now live in the root Forge section. `### Domain docs` is deleted: it pointed only at `CONTEXT.md` and `docs/adr/`, neither of which exists. **`backend/` and `userscript/`:** rewritten around derivability. | Class | In code? | Treatment | |---|---|---| | Structure — packages, routes, env vars, columns | yes | name the symbol, nothing else | | Mechanism — what a function does | yes | symbol + one line | | Rationale — why, what a "simplify" breaks | **no** | written out | | Measurement — observation against a service we don't control | **no** | written out, dated | `backend/AGENTS.md` 20578 → 15512 bytes, `userscript/AGENTS.md` 7129 → 5912. Root grows 16905 → 19292: the cost of inlining the `docs/agents/*` facts plus the new rule. **Rule** recorded in root as `## Writing an AGENTS.md`. Sole non-code exception is a sibling `AGENTS.md`. Closing clause: every symbol named must exist, since a dead pointer is a bug rather than a stale sentence. **Harness-agnostic:** dropped the `Guidance for OpenCode (and Claude Code)` openers for plain scope lines. ## Verification Applied the new rule to itself — extracted all 118 backticked identifiers across the three files and checked each against every `.go`, `.js`, `.sql`, `.html` and `.css` source. Zero repo symbols missing; the 8 non-matches are external (`GM_setValue`, `navigator.webdriver`, `HeadlessChrome`, `curl`, …). That check caught a claim that was **already lying** on `main`: the cover section said `CoverFetcher` was gone, but `NewCoverFetcher`, `TLSCoverFetcher` and `BrowserCoverFetcher` are all live in `internal/latest`. Now names only the genuinely dead `/img/kagane/{id}` route. Exactly the failure the rule exists to prevent. No code touched — documentation only, nothing to test.
sulthan added 1 commit 2026-08-17 13:39:50 +07:00
A spec, ADR, plan file, or Gitea issue records what was true when it was
written and then goes stale silently, so an agent that follows the pointer
reads a decision that may already have been reversed. Code is the only
source true at read time.

Strip every non-code citation from the three AGENTS.md files (ADRs, spec
and plan files, docs/research, docs/agents/*, DEPLOY/REDEPLOY, and issue
numbers), restating inline any fact the linked doc actually carried: the
tea command set and triage label strings move into the root Forge section.
The Domain docs subsection goes entirely, as it pointed only at CONTEXT.md
and docs/adr/, neither of which exists.

Then rewrite the backend and userscript files around derivability, since
prose that restates mechanism rots the same way a doc link does. Structure
and mechanism now name a symbol and stop; rationale, rejected alternatives
and dated measurements stay written out, because code cannot carry them.
Record that split as a rule in the root file.

Verified by extracting all 118 backticked identifiers and checking each
against the Go, JS, SQL, HTML and CSS sources. That caught one claim that
was already lying: the old cover text said CoverFetcher was gone, but
NewCoverFetcher, TLSCoverFetcher and BrowserCoverFetcher are all live in
internal/latest, so the sentence now names only the dead /img/kagane route.

Also drop the "Guidance for OpenCode (and Claude Code)" openers, so the
files read the same under any harness.
sulthan merged commit 766aa8f00d into main 2026-08-17 13:43:50 +07:00
Sign in to join this conversation.