AGENTS.md · git:20260614.73f02bc · 2026-06-14 · sha256 04a43e65fc2d4cdb
AGENTS.md git:20260614.73f02bcA
Immutable. This exact content is served forever at /api/v1/blob/04a43e65fc2d4cdb.
# Compound Learning
<!-- This file is the project's persistent memory across AI sessions.
It accumulates patterns, gotchas, and decisions so that each session
builds on what previous sessions learned — rather than rediscovering
the same things from scratch.
IMPORTANT: This file is often generated or updated by LLM agents.
Review new entries with the same scepticism you would apply to any
generated content. Entries should reflect observed reality in the
codebase, not aspirational conventions. An entry in GOTCHAS that
does not reflect an actual problem that was actually solved is noise
that increases the cognitive cost of every future session. -->
## STYLE
<!-- Patterns and idioms that work well in this codebase.
Each entry: what to do, and why it works here. -->
- All hook scripts are advisory only — they warn but never block.
Output uses JSON `systemMessage` format so Claude Code surfaces
the message without interrupting the session flow.
- Reflection-driven amendments may go through `chore`-labelled PRs
even when behavioural, provided four preconditions hold: (a) the
reflection has been captured in `REFLECTION_LOG.md` and merged via
PR; (b) the work is scoped in a tracked GitHub issue with
explicit "in scope" and "out of scope" sections; (c) the
implementation is additive (new sub-phase, new reference file)
or conservatively bounded (new behaviour applies incrementally
with a CHANGELOG note governing how aggressively); (d) the
version bump and CHANGELOG entry are honest about the
behavioural change. The `chore` label exempts spec-first ordering
and adjudication constraints; the version-consistency check still
applies. Reserve full feature-flow ceremony (spec → diaboli →
adjudicate → implement → diaboli code-mode → adjudicate) for
*net-new capability* (the Choice Cartographer was the canonical
feature PR); use chore for *refining existing capability driven
by captured signal* (Units A and B for the assessor). The
distinction is calibrated rather than codified — judgement, not a
rule. (Source: REFLECTION_LOG 2026-04-28 entry on Units A and B,
building on the marker-bump and Cartographer flows from earlier
in the same conversation.)
## GOTCHAS
<!-- Traps, surprises, and non-obvious constraints. Entries
accumulate as the pipeline discovers them.
Each entry: what the trap is, and how to avoid it. -->
- When adding a new deterministic constraint (like ShellCheck),
always run a test pass against the full codebase before promoting
— including files created earlier in the same session. ShellCheck
found 4 issues in scripts that had passed both implementer and
spec compliance review. Deterministic tools catch what LLM review
misses. (Source: REFLECTION_LOG 2026-04-06)
- Worktree-isolated subagents lose Bash permissions — the `.claude/
settings.local.json` allow-list does not propagate to worktree
paths. Use regular background agents on separate branches instead,
but expect branch cross-contamination when multiple agents share
the same repo. Plan for cherry-pick cleanup when dispatching
parallel implementation agents without worktrees.
(Source: REFLECTION_LOG 2026-04-07)
- Background subagents may lack Write/Edit permissions even when the
parent context has them. For write-heavy tasks (e.g. generating
full documentation pages), either use foreground agents so the user
can approve tool calls, or have the parent extract content from
subagent output and do the writes itself. The subagent output logs
at `/private/tmp/claude-*/tasks/<agent-id>.output` contain the
drafted content even when writes were denied.
(Source: REFLECTION_LOG 2026-04-11)
- Before proposing a new CI workflow, grep `.github/workflows/` for
related checks. This project already has version-check.yml,
lint-markdown.yml, harness.yml, gc.yml, and pages.yml. Proposing
a duplicate wastes a branch cycle and erodes trust.
(Source: REFLECTION_LOG 2026-04-11)
- This project's harness is self-referential — the plugin defines
the harness framework, and its own HARNESS.md uses that framework.
Changes to template files (`templates/HARNESS.md`) do not
automatically propagate to the project's root `HARNESS.md`. The
command-prompt sync and plugin manifest currency GC rules are
critical here to catch drift. (Source: REFLECTION_LOG 2026-04-06)
- Long uninterrupted sessions degrade judgment in ways that are
invisible from inside the session — output keeps flowing, but
pattern-matching narrows and surprise-detection drops. Take a
time-based break (90-minute self-check, end-of-day stop) rather
than a task-based one. Specifically: if the next decision involves
judgment about *whether* to do something (vs how to do it), and
you've been working continuously for 90+ minutes, defer the
decision to a fresh session. Task-based stops ("when this is done")
routinely paper over depletion because the task always extends.
(Source: 2026-04-28 assessment Q4 — depletion-management gap.)
## ARCH_DECISIONS
<!-- Key architectural decisions and the reasoning behind them.
Each entry: what was decided, why, and what the alternatives were. -->
- Decision: content-emitting agents in this codebase use a three-part trust
architecture — **agent-emit + dispatcher-persist + human-disposes**. The
agent's tool boundary is research-and-author only (no Edit, no Bash); the
agent returns content as a string; the dispatching command writes the file
after a structured human review (accept / edit / re-run / abort). This
pattern is in production across three agents: `advocatus-diaboli`,
`choice-cartographer`, and `model-card-researcher`. Three repetitions
promote it from convention to named architecture (Hunt/Thomas's Rule of
Three). Future research-and-author agents in this codebase should default
to this shape unless an explicit reason argues otherwise. The two halves
are: (1) tool-boundary — minimum-trust-surface, no shell, no edit; (2)
human-gate — structured review summary, named dispositions, command
refuses to persist when the agent emits a refusal string (e.g.
model-card-researcher's REFUSED: line for unconfirmed model existence).
**Ordering invariant (promoted from S4 cartographer Story #1): the human
disposition must PRECEDE the write — the dispose-then-write ordering is the
invariant, not merely the agent/command tool split.** The S4 `/diagnose`
spec's pre-diaboli draft satisfied the tool split (read-only agent, command
writes) yet wrote the file *then* printed a summary, reducing the human gate
to a post-hoc read; only the diaboli (O1) caught it. A spec can honour the
pattern's name and still break its invariant, so check the ordering, not just
the tool boundary. `/diagnose` is the fourth production instance. Watch item:
`/diagnose` ships only accept/abort, a narrower disposition vocabulary than
the named architecture's accept/edit/re-run/abort and the model-card
precedent; if that narrowing recurs on the next command spec, the divergence
may warrant its own sub-rule. **Resolved (S3 `/cost-estimate` story #1,
2026-06-12): the next command spec (`/cost-estimate`) shipped the FULL
accept/edit/re-run/abort vocabulary, so the narrowing did NOT recur —
`/diagnose`'s accept/abort was a one-off, not a convention, and the
contemplated sub-rule is not warranted. `/cost-estimate` is the fifth
production instance, ships the full vocabulary, and honours the dispose-then-
write ordering.**
Source: `docs/superpowers/stories/model-cards-plugin-design.md` stories
#7 and #8 (original promotion); `docs/superpowers/stories/dl-s4-diagnose-command-design.md`
story #1 (ordering-invariant sharpening); `docs/superpowers/stories/cost-estimate-command-design.md`
story #1 (watch-item resolution).
- Decision: **an agent that DERIVES a judgment a human previously SUPPLIED
carries a disclosure obligation** — the disclosure-of-derived-judgment
contract. When an agent emits a value that was formerly ground-truth supplied
by a human (a derived *prediction*, not an inspected fact), the artefact must
disclose, in four parts, what it **included**, what it consciously
**excluded**, its **confidence**, and the **failure direction** when
confidence is below high — and never present a silent boundary or a single
number as fact. Reason: a supplied input cannot be wrong; a derived one can
under- or over-reach, so the derivation manufactures a correctness risk the
supplied case never had, and the four-part disclosure is what keeps the
derived value honest (it does not make it *useful* — that is a separate
validation question). This complements, and is disposed over through, the
agent-emit/dispatcher-persist/human-disposes architecture above: the
disclosure is the thing the human disposes over. Worked instance: the
`cost-estimation` skill's estimate-record operationalises it as a format
contract — token/time/cost ranges with per-axis confidence, an
included/excluded/confidence/failure-direction prose body, and `cost_usd`
omitted-with-disclosure rather than guessed when ungrounded. The same
principle independently surfaced for the diagnostic-legibility pipeline-map's
derived task→scope resolution, and a **third time** in the `cost-estimator`
agent (S2), which operationalises it *behaviourally* in three new places:
inference-basis disclosure on a derived `target_kind`, tier-label provenance
on a derived `generated_by`, and blended-rate-skew disclosure on a derived
cost. **The Rule of Three has fired** — three independent surfacings (format
contract, task→scope resolution, agent behaviour) confirm this is a
cross-cutting decision, not feature-local. Scope note: it is now a confirmed
cross-cutting design discipline, but still **not an enforced invariant**
beyond each component's own validation checklist — a trust-surface audit
should read the disclosure obligation, not just the tool list. Future "let
the agent infer X that the human used to supply" features inherit this
obligation rather than re-deriving it.
Source: `docs/superpowers/stories/cost-estimation-skill-design.md` story #8
(original promotion); `docs/superpowers/stories/cost-estimator-agent-design.md`
story #2 (Rule-of-Three confirmation, 2026-06-11).
- Decision: **a change to a shared/merged contract gets its own owning slice
with its own adversarial pass — a consumer never mutates the contract it
consumes.** When a slice discovers it needs to change a merged contract a
reference, schema, or format that other slices depend on (e.g. a
`skills/<name>/references/<contract>.md`), carve the change into a dedicated
slice that **owns** that artefact and runs its own diaboli pass, rather than
mutating it in-place from a consumer slice. Reason: a contract change folded
into a consumer slice (a) conflates owner and consumer roles, and (b) inherits
only that consumer's adversarial budget, which is scoped to the consumer's
behaviour — **not** the contract's backward-compatibility, the property that
most needs scrutiny. Worked instance: the per-stage `cost_usd` format change
was split out of S2 (the `cost-estimator` agent, a pure consumer of the
estimate-record format) into its own slice #377, which owns
`estimate-record-format.md` and earned a dedicated two-round diaboli pass that
hammered the backward-compat demonstration (the `iff` trap; the rate-consistent
worked example) a consumer-scoped review would have missed. Cost accepted:
slice proliferation — a small contract fix carries full feature-PR ceremony.
Pairs with the agent-emit/dispatcher-persist boundary above: a consumer
neither *writes* the contract nor *edits* it. Watch item: this is the **first
worked instance** of the precedent the S2 cartographer named; confirm the rule
on the next contract-change slice (Rule of Three).
Source: `docs/superpowers/stories/cost-estimator-agent-design.md` story #5
(precedent named, accepted); `docs/superpowers/stories/format-revision-per-stage-cost-design.md`
story #1 (first worked instance, promoted 2026-06-11).
- Decision: hook scripts never block, only warn. Reason: this is a
plugin used across diverse projects — blocking hooks could break
workflows the plugin authors cannot predict. Advisory messages let
users decide how to act. Alternative considered: configurable
blocking (rejected — complexity not justified for the advisory
value these hooks provide).
- Decision: health snapshots are generated artifacts committed
directly to main. Reason: they do not affect behaviour and
gating them on PR review would add friction to the observability
cadence. Alternative considered: PR workflow for snapshots
(rejected — would discourage frequent snapshot generation).
- Decision: every command that produces structured output parsed by
downstream consumers must include a validation checkpoint step.
The pattern is: generate, read back, check against format spec,
fix in place. Reason: agents consistently drift from format specs
under cognitive load — the governance-auditor ignored its own
9-field format spec, /harness-health generated deprecated YAML
blocks. Reference templates set intent but do not guarantee
compliance. The checkpoint is the verification layer, analogous
to type checking in compiled code. Alternative considered:
relying on agent instructions alone (rejected — proven unreliable
across 8 commands). Alternative considered: hook-based validation
(rejected — hooks are advisory-only with 30-second timeouts, too
limited for format verification). (Source: REFLECTION_LOG 2026-04-15)
- Decision: advocatus-diaboli is hard-wired into the spec-first pipeline as an
agent-enforced PR constraint from the outset (Option B — not optional, not
advisory). The agent is dispatched after spec-writer and before plan approval;
the plan-approval gate refuses progression while any disposition is `pending`;
the harness-enforcer checks objection record completeness at PR time.
Alternatives considered and rejected: (1) manual invocation only — discovers
utility in early PRs but never creates discipline; users skip it under pressure;
(2) advisory gate without constraint — same failure mode; the gate exists only
when someone remembers to run it; (3) deterministic schema check alone — can
verify no `pending` values remain but cannot detect rubber-stamping
(`disposition: accepted, rationale: "ok"` would pass). Agent enforcement is
chosen because "resolved" is a judgment call on rationale quality. Conditions
under which this would be revisited: if disposition distribution clusters on
`deferred — not material` over a meaningful sample (20+ PRs), tune the SKILL.md
charter (tighten evidence requirements, raise the evidence bar) before weakening
the constraint. Do not weaken the constraint at first friction — that builds
ceremony, not a gate.
- Decision: diaboli runs at two dispatch points (spec-time and code-time) using
a single agent with mode-based category weighting. One agent, two dispatches —
not two agents. Spec-time dispatch runs after spec-writer, before plan approval;
code-time dispatch runs once after the final code-reviewer PASS (or escalation),
before integration-agent. The integration-approval gate mirrors the plan-approval
gate: refuses while any code-mode disposition is `pending`. Alternatives
considered and rejected: (1) separate code-diaboli agent — rejected: duplicates
charter, fragments maintenance, creates divergent evolution risk; (2) running
diaboli inside the code-reviewer loop per cycle — rejected: burns tokens on draft
code, and adversarial review of drafts conflates the code-reviewer's constructive
role with diaboli's adversarial one; (3) running code-time diaboli only for PRs
above a size threshold — rejected: premature optimisation without
disposition-distribution data to justify it. Conditions for revisit: if code-time
disposition distribution diverges sharply from spec-time across a meaningful sample
(20+ PRs), consider whether the two modes need genuinely separate charters rather
than weighting.
- Decision: diaboli activity is surfaced as descriptive stats in existing
observability surfaces (`/superpowers-status` Section 7 and the harness-health
snapshot Diaboli panel) without thresholds or new enforcement, pending a
reflection-informed evaluation. Alternatives considered and rejected:
(1) adding a disposition-balance GC rule now — rejected because no data yet
exists on what healthy looks like, and a premature threshold creates
rubber-stamping pressure (the exact failure mode the mechanism is designed to
prevent); (2) adding a separate `/diaboli-status` command — rejected because it
fragments the observability surface; status and health are already the canonical
panels and adding a third creates a maintenance surface with no corresponding
benefit. Conditions under which this is revisited: after 10 fully-resolved
objection records OR by 2026-07-19, whichever comes first — write a reflection
on the observed patterns (disposition distribution, mean objections, median
days) and decide whether a threshold or GC rule is warranted. The revisit
output is a reflection entry, not an automatic constraint.
- Decision: cross-cutting methodology lives in
`skills/<skill-name>/references/<contract>.md` files, consumed by
multiple agents/commands/skills via reference rather than inlined
at each consumer. The pattern has four instances in production:
`skills/choice-cartographer/references/validation-checks.md` (the
cartographer's validation checkpoint, consumed by the
`/choice-cartograph` command and the orchestrator's step 5);
`skills/ai-literacy-assessment/references/habitat-discovery.md`,
`tool-config-evidence.md`, and `sophistication-markers.md` (the
assessor's discovery, parallel-tool, and sophistication
methodologies, each consumed by `assessor.agent.md`,
`harness-discoverer.agent.md`, the `assess` command, and the
`ai-literacy-assessment` SKILL). Edits to a contract land in one
place and propagate; consumers reference the file by path rather
than duplicating its content. Alternatives considered and
rejected: (1) inline the methodology in each consumer — rejected:
silently drifts as one consumer is edited and the others are not,
which is the exact failure mode the references-file idiom
prevents (caught explicitly in code-mode diaboli on PR #210, see
O8 of `docs/superpowers/objections/choice-cartographer-code.md`);
(2) put the methodology in the SKILL.md itself — rejected: SKILL
files are loaded as context for the agent's reasoning, but the
methodology is also consumed deterministically by validation
checkpoints and command processes, which need a stable file
reference. Conditions under which the idiom should be revisited:
if a reference file accumulates more than ~250 lines or three
obviously distinct contracts, split it; the value is one contract
per file. (Source: REFLECTION_LOG 2026-04-28 entry on Units A and
B for the assessor.)
- Decision: a "natural home" hand-off in slice N does not bind slice N+1.
When a slice defers a concern by pointing at a later slice as its "natural
home", that pointer is a *suggestion*, not a commitment the later slice
inherits — the later slice is free to decline it, and when it does, the
concern is orphaned unless deliberately re-filed. Repeatedly handing the
same concern forward ("the next slice will own this") accrues **deferred-
concern-accretion debt**: by the time the chain's parent issue closes, the
concern has no tracking home and falls through the gap. Rule: when a slice
declines an inherited hand-off, either (a) absorb it, or (b) re-file it as a
standalone issue with its own lifecycle **AND bind it to a *scheduled
deliverable* — a concrete slice that produces the concern's triggering event,
not an unscheduled precondition or a bare "filed somewhere"** — never leave it
implicit in a closed slice's "out of scope" section. **Sharpening (S3
`/cost-estimate` story #7): re-filing to an unbound issue whose trigger no
slice causes is itself a buck-pass — the home must be a deliverable the roadmap
schedules, not an event it never reaches.** Worked instance: the
diagnostic-legibility invocation-persistence corpus for the Phase-C
escalation trigger was deferred at S2b, pointed at S4 by S3 §8 as its
"natural home", and declined by S4 — three consecutive deferrals with the
parent (#327) closing. Re-filed as standalone issue #350 at S4 adjudication.
Second worked instance (S3 `/cost-estimate`): the #377-deferred absolute-rate
check was re-filed at S3 and bound to S6/#373 as a blocking required
deliverable, with S6 extended to own first-snapshot capture so the triggering
event (the first cost-present record) is actually scheduled — correcting a
draft that keyed the trigger on an unscheduled "first cost-present record"
event no slice produced.
Alternative considered and rejected: trusting the §8 "out of scope" note to
carry the concern forward — rejected because closing the parent removes the
natural tracking issue and the note becomes archaeology no one re-reads.
Source: `docs/superpowers/stories/dl-s4-diagnose-command-design.md` story #8
(original promotion); `docs/superpowers/stories/cost-estimate-command-design.md`
story #7 (bind-to-a-scheduled-deliverable sharpening, 2026-06-12); tracking
issues #350, #373.
- Decision: **the S6 per-PR actuals calibration format assumes an
orchestrator pipeline run; cost from a direct-authoring session belongs in
the quarterly snapshot, not the per-PR record.** The per-PR actuals format
(`skills/cost-tracking/references/per-pr-actuals-format.md`) is built around
the five pipeline stages (spec-writer / tdd-agent / implementer /
code-reviewer / integration-agent) and exists to narrow per-stage **token**
ranges against this repo's history. A session that produced its PRs by
**direct authoring** (no orchestrator dispatch) has no per-stage attribution,
so forcing its cost into the per-PR format yields a record with every
`tokens_by_stage[].tokens` = `unavailable` that calibrates nothing. The right
home for that data is the **quarterly cost snapshot**
(`observability/costs/<date>-costs.md`), whose per-model Model-Breakdown shape
matches what Claude Code's `/cost` actually reports and grounds the estimator's
`$/token` rate. Reason: the two actuals formats answer different questions —
per-PR/per-stage *token* calibration vs per-model *dollar* grounding — and the
data source (`/cost`, a per-model session total) fits only the latter; the
`unavailable` discipline is honest but a record full of it is worthless.
Worked instance: the 2026-06-14 session shipped S4–S6 by hand, so `/cost`
($287.64, per-model, cache-dominated) was captured as the first cost snapshot
(#391) and a per-PR record was **deliberately not written** because it would
have been an empty shell. Future per-stage token calibration must come from a
real orchestrator run, where the integration-agent captures stage actuals at
merge from figures the human supplies. Watch item: first worked instance —
confirm on the next direct-vs-pipeline cost capture (Rule of Three).
Source: `REFLECTION_LOG.md` 2026-06-14 (Proposal #2); snapshot
`observability/costs/2026-06-13-costs.md`; PR #391.
- Decision: the verifier-watch (`cognitive-reservoir` skill,
`reservoir-warden` agent, `/reservoir` command, `reservoir-check` Stop
hook) is **advisory-only and is NOT a Constraint** — do not promote it
into a CI gate. Reason: the mechanism watches the *human verifier*, the
one actor every other enforcement surface trusts blindly. It counts
observable proxies (session span, decision volume, context switches,
wall-clock hour) and infers risk, but the inputs cannot support a
precise measurement of cognitive state. Constraints are gates with a
scope that can fail CI; wiring a human-state advisory into a blocking
gate would (a) defeat its purpose — the engineer's *prohairesis* must
stay theirs, the warden watches but never chooses — and (b) overclaim a
precision the proxies lack. So it lives in its own `Cognitive
reservoir` HARNESS.md block (opt-in, never the Constraints section),
never blocks a commit/merge/session, never exits non-zero, and
persists **no** record of the human's state to disk. This generalises
the existing "hook scripts never block, only warn" decision to a
stronger rule for human-state observation: such a mechanism must also
never be a fatigue *score* and must keep contested science (ego
depletion, the hungry-judges figure) out of its assertions — the
honesty rule is load-bearing, not flavour. A future contributor who
"promotes" the warden into a blocking gate or a single combined score
has broken the design, not improved it. Alternative considered:
modelling it as a soft (non-blocking) Constraint for visibility in
health snapshots (rejected — even a non-blocking Constraint frames it
as a measured gate and invites later hardening). Source: spec
`docs/superpowers/specs/2026-06-14-reservoir-warden-design.md`
(Approach, FR-011); builds on the line-201 advisory-hook decision.
## TEST_STRATEGY
<!-- How tests are structured in this project. Helps agents write consistent
tests without reading every test file from scratch. -->
- This project has no application code or test suite. Content is
validated by markdownlint (CI), ShellCheck, bash -n syntax checks,
and gitleaks secret scanning. All validation is deterministic and
runs in the harness CI workflow.
## DESIGN_DECISIONS
<!-- Interface contracts, data shapes, and design choices that are stable and
that agents should not second-guess without good reason. -->
- Plugin components follow strict naming: skills use `SKILL.md`
inside `skills/<name>/`, agents use `<name>.agent.md`, commands
use `<name>.md`, hook scripts use `<name>.sh` (kebab-case). All
names are lowercase kebab-case except `SKILL.md`.