Skip to content

docs(agents): rebuild AGENTS.md and add the review loop - #200

Merged
haydenshively merged 21 commits into
mainfrom
agents-md-canonical-rewrite
Sep 4, 2026
Merged

docs(agents): rebuild AGENTS.md and add the review loop#200
haydenshively merged 21 commits into
mainfrom
agents-md-canonical-rewrite

Conversation

@haydenshively

@haydenshively haydenshively commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

AGENTS.md had become a changelog of the repo rather than an instruction set for working in it — 301 lines billed on every request, of which Architecture Overview and Linear Integration alone were 45%, all of it facts that README.md, docs/INDEX.md, and .husky/commit-msg already own. This rebuilds it from first principles at 102 lines, gives every evicted rule exactly one home, and repairs the surfaces it now delegates to.

Along the way it fixes a real bug: knip false-failing inside nested worktrees, which had been worked around for a month by telling people to keep worktrees outside the repo.

Changes

Instruction fileAGENTS.md is now the real file with CLAUDE.md and .cursorrules symlinked to it (inverting the old direction). Seven sections: orientation, Never, Funds at risk, Working, Done, Traps, and an Elsewhere routing table. Adds what was missing — that these programs sign transactions and move real funds — plus traps that were only ever in operators' heads.

Review loop.agents/skills/review-loop/SKILL.md is the single home for one procedure with three parameterizations (TIBs, implementations, PR-review responses): satisficing self-check, independent reviewer in the background, own readability pass without touching semantics, then dedupe → synthesize → decide incorporate/drop/defer. Writing that engine into three command files would have guaranteed drift.

knip inside worktrees.gitignore had .claude/worktrees/ unanchored, so the pattern matched that segment at any depth; run from inside a worktree, knip matched every file via its absolute path, concluded the tree was gitignored, and reported everything as unused. Anchored to /.claude/worktrees/. Git behavior is identical.

Linear — routing moves from a stale Curator default to the Bots team; create-issue.md was sending every ticket to a dead Curator Backlog project. Deferred review findings now carry Provenance > code-review and link their originating PR or TIB.

Conventions — coding rules evicted from AGENTS.md land in docs/CONVENTIONS.md, including a comment policy that was previously only in a Claude-specific user file that Codex never reads.

Devin.devin/config.json imports the repo's rules, skills, and commands via read_config_from.claude; that mechanism does not import subagents, so .devin/agents/ holds thin manifests that pin model and tool surface and defer to .claude/agents/<name>.md for instructions. Models are pinned by role: fable for documentor (the TIB role), opus for the specialists. The clean-room agent needs no pin — it is a subagent_general and inherits the session model, so a TIB session started on Fable covers the whole TIB path.

Two traps are documented rather than left to be discovered: an unpinned custom subagent silently falls back to a fast cheap model, and a Devin session with no codex binary would drop the loop's cross-vendor pass down to Opus-reviewing-Opus with nothing saying so. Hence independent-reviewer (pinned to codex) as the fallback, and Exec(codex) pre-approved. Devin support is best-effort: fable is not a documented Devin identifier and could not be verified from here.

Missiondocs/MISSION.md arrived as a copy from morpho-apps and still described Next.js, React, wagmi, @repo/web3, @repo/ui, a design system, Core Web Vitals, VVRM, and AI QA driving a real UI. The North Star and principles transfer; the instantiations are retargeted at bots, and Pillar B now names the threat model that actually applies here — these bots hold keys and broadcast with no human per action, so the risk is our own transactions.

TIB-2026-09-03 records the decision and the admission criteria for anything added back; TIB-2026-04-16 gets an addendum, since it recorded the opposite intent.

Size

Area Files + Net
docs 29 +1158 −408 +750
ci 5 +43 −3 +40
total 34 +1201 −411 +790

tokei over the touched files: 171 lines of code, 3,476 of prose. It counts Markdown as comments, so the +962 is almost entirely documentation — the only executable changes are the pre-push hook and shell snippets.

Test Plan

CI covers lint, typecheck, knip, and tests. Three things it cannot check:

  • pnpm exec knip --directory .claude/worktrees/<any> exits 0 — the fix's whole point. Worktrees created before this branch carry the old rule in their own checkout and need a rebase first.
  • readlink CLAUDE.md .cursorrules both print AGENTS.md after checkout — oxfmt runs over *.md and a write-through would silently un-do the inversion.
  • Cold read: ask a fresh session what makes a change funds-at-risk, where the commit title rule is enforced, and where worktrees go. All three should come from AGENTS.md alone.

AGENTS.md becomes the real file; CLAUDE.md and .cursorrules symlink to it,
inverting the previous direction. The instruction file goes from 301 lines /
2,259 words to 92 / 826 — it had become a changelog of the repo rather than an
instruction set for working in it, with nearly every feature PR appending a
paragraph.

Architecture Overview and Linear Integration were 45% of the file and were
already carried by README.md, docs/INDEX.md, and .husky/commit-msg. Coding
rules move to docs/CONVENTIONS.md, Linear team IDs to docs/GUIDANCE.md; the
tech-stack versions, scope tables, anti-rationalization table, and
reverted-architecture narrative are deleted.

Adds what was missing: that these programs sign transactions and move real
funds, a funds-at-risk trigger list, and a Traps section for hazards that are
not discoverable from the code (worktree placement vs knip, gh stack, log
fields as a dashboard interface, soltag's silent empty-ABI degradation).

Fixes the surfaces AGENTS.md now delegates to: docs/INDEX.md linked 13 of 28
TIBs and 2 of 6 bots, README.md named 5 of 9 packages, and both specialist
agents cited a packages/abis that does not exist. Adds a .husky/pre-push guard
so "never push to main" has a mechanism.

TIB-2026-09-03 records the decision and the admission criteria; TIB-2026-04-16
gets an addendum, since it recorded the opposite intent.
Adds .agents/skills/review-loop/SKILL.md as the single home for one procedure
with three parameterizations: TIBs, implementations, and PR-review responses.
All three share the same engine — satisficing self-check, dispatch independent
reviewers in the background, do the readability pass without touching semantics
until they report, then dedupe, synthesize, and decide incorporate / drop /
defer. Writing that engine into three command files would have guaranteed drift.

TIBs additionally get a clean-room subagent (never a fork, which would inherit
context) and a two-round Codex reviewer whose session id is recorded in a
git-ignored docs/decisions/<stem>.sessions file, so the implementation review can
resume the reviewer that already argued about the spec.

AGENTS.md gains six lines: the satisficing check before presenting a plan or
proposal, and a pointer to the skill. 99 lines, still inside the TIB's budget.

Linear filing now routes to Bots with surface labels and no project, per
docs/GUIDANCE.md; create-issue.md was sending everything to a Curator Backlog
project. PR descriptions lead with intent and carry a src/test/docs/ci size
table from git numstat plus tokei, which counts Markdown as prose so a docs PR
does not read as thousands of lines of code.
knip exits 1 from inside a worktree nested under .claude/worktrees/ — knip.json's
.claude/** ignore only applies to runs started from the repo root. Verified by
running pnpm knip inside .claude/worktrees/unwire-v1-ci. The previous wording
called that path sanctioned, which reintroduces the false-positive wall that
masks real findings.
`.claude/worktrees/` was unanchored, so the pattern matched that segment at any
depth. Run from inside a nested worktree, knip matched every file against its own
repo's rule via the absolute path, concluded the whole tree was gitignored, found
no entry points, and reported ~29 files plus a pile of devDependencies as unused.
The wall of false positives is what buried real findings on PR #184.

Anchoring to `/.claude/worktrees/` binds the pattern to the repo root, which is
the only place the directory exists — git behavior is byte-for-byte identical.
Verified: knip exits 0 inside `.claude/worktrees/unwire-v1-ci` with the anchored
pattern and 1 without, `git check-ignore` still resolves, root knip still clean.

Worktrees can now live inside the repo again, so the guidance shrinks to one line.
Worktrees created before this lands carry the old rule in their own checkout and
need a rebase onto main.
A ticket born from a review loop now carries Provenance > code-review and links
the PR or TIB it came from, so what the loop keeps punting stays auditable.
Provenance is deliberately separate from status: the status says the work is not
being done yet, the label says where the ticket came from.
docs/CONVENTIONS.md carried generic when-to-comment boilerplate with nothing about
length or what a docstring should contain. The substantive policy lived only in a
Claude-specific user file, which Codex — a first-class reviewer here via the
review-loop skill — never reads.

Ports it: default to none, ~3 lines max, TSDoc only where there is real nuance and
stating the guarantee rather than the algorithm, one home per explanation, inline
comments only where code looks wrong without them and only with a citation.
Reconciles pithy with quoter-bot's jsdoc:check — pithy is not absent.
@haydenshively haydenshively self-assigned this Sep 4, 2026
Adds .devin/config.json with read_config_from.claude, which pulls in AGENTS.md
rules (via the CLAUDE.md symlink), the review-loop skill, and .claude/commands as
skills. Subagents are explicitly not imported by that mechanism, so .devin/agents/
carries four thin manifests that pin model and tool surface and defer to
.claude/agents/<name>.md for the instructions — one home, no copied prose.

Every manifest pins model: because an unpinned custom subagent silently falls back
to SWE-1.6, which would quietly degrade the review loop rather than fail it.
The model rule is role-based, not session-based: Fable for anything touching a
TIB, Opus otherwise. documentor pins fable; reviewer, protocol-engineer, and
product-manager pin opus. The clean-room agent needs no pin — it is a
subagent_general and inherits the session model, so starting a TIB session on
Fable covers the whole TIB path.

Also records the guardrail: an agent must never rewrite .devin/agents/ to match
the model it is running on. Those manifests declare intent; mirroring the session
into them dirties tracked files every run and makes committed state depend on who
ran last.
The loop's independent reviewer is Codex on GPT Sol because it is a different
vendor from whatever wrote the code — that independence is the point, not the
model's ranking. A Devin session may have no codex binary and no
~/.codex/sessions/, in which case the loop would quietly fall back to the reviewer
subagent, which is Opus. An Opus session reviewed by an Opus subagent is not an
independent pass and nothing in the output says so.

Adds an independent-reviewer manifest pinned to the codex model as the fallback,
and pre-approves Exec(codex) so the preferred CLI path is not gated on an
approval prompt. Requires naming which reviewer actually ran.
MISSION.md arrived as a copy from morpho-apps and still described Next.js, React,
wagmi, @repo/web3, @repo/ui, a design system, Core Web Vitals, accessibility,
VVRM, ActionFlows, and AI QA driving a real UI — none of which exist here.

The North Star, guiding principles, pillars, and horizons transfer unchanged; the
concrete instantiations did not. New bots come from @repo/bot-kit and @repo/swaps,
bug reports reproduce against a pinned anvil fork rather than a preview deploy,
currency means Node/viem/Morpho SDK rather than a Next.js major, and the
data-flow question is discovery-to-broadcast rather than chain-to-UI.

Pillar B is retargeted at the threat model that actually applies: these bots hold
keys and broadcast with no human approving each action, so the risk is our own
transactions — unbounded approvals, a broadcast that skipped simulation, bounds
that stopped binding, a lost nonce cursor — and signing is a fail-closed boundary.

Adds one success criterion with no analogue in an app repo: a bot that cannot act
safely must halt loudly, because idle-because-healthy and idle-because-broken look
identical from outside.
@haydenshively
haydenshively marked this pull request as ready for review September 4, 2026 03:41
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 4, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-04T03:51:19.582247Z 13059f3 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

chatgpt-codex-connector[bot]

This comment was marked as resolved.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 potential issues.

3 flags not posted on this PR by your GitHub settings — view them in Devin Review. (Configure)

Devin Review

Comment thread .claude/commands/pr-describe.md Outdated
Comment thread .agents/skills/review-loop/SKILL.md Outdated
The devin CLI is installed now, so the slugs could finally be checked. Three were
wrong and one was outright broken:

- documentor had model: fable, which is NOT a valid slug — Fable 5.1 is the one
  family with no alias. Now claude-fable-5-1-high.
- the specialists used the opus alias; now claude-opus-5-high, explicit about
  reasoning level, which is the thing that matters for a reviewer.
- independent-reviewer used the codex alias (GPT-5.3-Codex, 400K context). Devin
  also offers gpt-5-6-sol-high — the same model the Codex CLI path uses — so both
  routes now review identically instead of one silently being a different, older
  OpenAI model.

Records the sharper trap: devin doctor loads profiles and reports zero failures
with a bogus model value, verified with model: fable. A misspelled pin degrades as
silently as an absent one, so slugs get cross-checked against devin models list.
It passed on a malformed allowed-tools one-liner as well as on a bogus model
slug — the check confirms profiles load, not that their contents mean anything.
Two open review findings from Devin on PR #200.

tokei was invoked through xargs without -r. GNU xargs runs its command once even
with empty input, and tokei with no paths scans the whole repository, so a
deleted-only PR would have reported the repo's totals as the size of the diff.
BSD/macOS xargs already declines to run on empty input and accepts -r as a no-op,
so one portable flag covers both; verified empty input now invokes nothing and a
real diff still measures.

The .sessions path was anchored to docs/decisions/, which strands the record for a
bot- or package-scoped TIB away from the TIB itself and defeats the sibling lookup
the implementation review depends on. It is now derived from the TIB's own path,
which is also why the ignore rule is recursive.
Parameterization C read 'First dispatch B's independent reviewer, then do B's own
pass and synthesis' — an unconditional instruction to re-review on every PR-comment
response. That over-corrected an earlier finding which said C never mentioned the
reviewer at all: it went from silent to always, skipping the intended once.

The independent pass runs once after the implementation, in B. The findings being
answered in C are themselves an independent review, so another round on a routine
comment-fix buys nothing. It is now the implementer's call, with a stated trigger —
when the response stops being a fix and starts being an implementation — and a
requirement to say which reviewer ran, or that none did and why.
Three places where addressing review feedback drifted from the stated rule.

create-issue.md's worked example treated 'align lint config with morpho-apps' as a
Morpho-owned dependency and punted it to the user. It is work in this repo, so it
goes to Bots; the surface-to-the-user rule is about dependencies. Replaced with two
examples that each demonstrate one branch correctly — an in-repo ticket with no
fitting label, and a real dependency (blue-sdk) that does get surfaced.

start.md marked labels optional. Labels are the routing mechanism that the
no-projects decision depends on, and create-issue.md already stated them as
expected, so the two commands disagreed.

start.md also claimed the Linear agent 'routes tickets by label' — an unverified
mechanism. It assigns projects; how it decides is not ours to assert.
C was written as a prohibition — 'do not dispatch another by default' — which says
what not to do without saying what the sequence is. It is now the sequence, and the
relationship to B is stated outright: same loop, ordering inverted. B implements,
then asks for review and reads it. C reads the review, implements, and only
sometimes asks for another.

Because a round of implementation and review has already completed, C enters at the
Engine's step 4 rather than the top: dedupe and decide on the findings in hand,
implement what was incorporated, then dispatch a reviewer only when something
substantial changed — with edits to the TIB or plan as the signal, since a moved
intent means nobody has reviewed what now exists.

Entropy is promoted from one of two trailing additions to the constraint governing
all of C, and named against each step: which findings to act on, whether to
implement at all, and how much new surface a fresh review would need to cover.
The 1-2-3-4 numbering asserted a sequence the parameterizations do not share. C is
the proof: it opens on what was step 4, then implements, then conditionally does
step 2 — so the numbers described A and B and quietly mislabelled C.

The pieces are now named — Self-check, Independent review, Own pass, Synthesis —
and each parameterization opens with its own explicit Order line. Synthesis keeps
internal ordering because its parts genuinely feed each other; that is scoped to
the piece rather than implied across all of them.

The no-semantic-edits rule was riding on the old adjacency of steps 2 and 3. It is
restated as what it actually is: a concurrency rule binding whenever review and own
pass overlap, in any parameterization.
Consistency pass before merge, all three the same defect: a fact stated in more
than one file, where only one copy got fixed.

docs/GUIDANCE.md still described the .sessions record as
docs/decisions/<tib-stem>.sessions — the root-anchored form Devin flagged and that
was corrected in the skill and the documentor agent, surviving here in a third
copy. It now derives from the TIB's own path like the others.

babysit-pr.md restated Parameterization C rather than pointing at it, and had
already drifted: it carried the old dedupe/synthesize/decide phrasing and omitted
the implement and conditional-review steps entirely. It now points.

documentor.md recapped Parameterization A's sequence, which A's own Order line
owns. Trimmed to a pointer; the .sessions instruction stays, since that is an
action the documentor takes rather than a restatement.
@haydenshively
haydenshively merged commit ef334bc into main Sep 4, 2026
4 checks passed
@haydenshively
haydenshively deleted the agents-md-canonical-rewrite branch September 4, 2026 22:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants