Skip to content

Latest commit

 

History

History
240 lines (197 loc) · 19.1 KB

AGENTS.md

File metadata and controls

240 lines (197 loc) · 19.1 KB

AGENTS.md: the operating layer

Tool-agnostic front door. Any agent runtime (Claude Code, Codex, Gemini, a human) reads this first to learn how work is done in this repo. It carries the portable operate-contract: what to read, how to run a unit of work, when work is done, and when to stop and ask.

Enforcement boundary (read this first)

This file is a contract, not a guardrail. Enforcement is Claude-Code-only: the hooks (safety-gate, push-to-main blocker, anti-rationalization Stop hook, the verification pipeline) are what actually block bad outcomes, and they run only under Claude Code. Under any other runtime (Codex, Gemini, a bare LLM) AGENTS.md is advisory only: it tells an agent what to do, but nothing enforces it. Do not assume the guardrails are portable. They are not, until the v3.x multi-runtime agent-hook work lands. See docs/PHILOSOPHY.md (honesty rule: never over-claim portable enforcement) and CLAUDE.md for the CC-specific layer (hooks, slash commands, plugin). The full layering contract, which hook backstops what and why (hard / advisory / convenience), is docs/architecture.md "Hook fallback layer".

The rest of this file is four portable zones. The goal-crafter (commands/assign.md) projects them into a six-section /goal (see "How a goal is composed" at the end).


1. Read in this order

Orient before you touch anything. Read top to bottom; stop when you have enough.

  1. AGENTS.md (this file) - how work is done here; the operate-contract.
  2. CLAUDE.md - the Claude-Code layer: stack, structure, rules, hooks, commands, plugin.
  3. docs/specs/SPEC-NNN-.md - the active spec; the shared contract for the cycle. Read its ## Verification and ## After state before implementing.
  4. docs/architecture.md / WORKFLOW.md / docs/data-flow.md - reference, not required per task. Read docs/architecture.md for how the pieces fit; docs/data-flow.md for how DATA moves (the signal path telemetry -> proposal -> board, the ledger write/read paths, the module map); read WORKFLOW.md for the lanes and the gate at each phase boundary, and its "Mega-goal delegate execution" section for how a multi-sub-goal mega-goal run dispatches (delegate mode: one fresh headless session per sub-goal; /goal stays the official outer loop either way).

2. Task loop

How to do one unit of work. The smallest verifiable increment, verified, committed.

Skill routing in an adopted repo. Idea or design intent ("design X", "brainstorm X", "thiết kế X", "should we build X") enters through /kit:think, then the opt-in /kit:design. Bug intent ("fix this", "the test fails", "bị lỗi") enters through /kit:debug. Third-party process skills that overlap them (superpowers brainstorming, systematic-debugging) serve repos the kit has not adopted; here they would run a parallel pipeline outside the gate ledger and the ship-gate, so route past them.

  1. Take work. Handed a task: use it. Handed a WAVE (2+ items approved in one conversation): work it from the conversation, one item at a time, and never mint board rows for it. A follow-up the session does not finish goes in its final report. A board row happens only when the operator asks for one or the work is blocked outside the session; sessions that filed rows as a side effect grew one board by 13 to 25 rows a day. The board-row-gate hook enforces this under Claude Code: a commit that adds a new row needs a board-row-ok: <reason> line in its message (a repo opts out with [gate] board_row_gate = false in its committed .kit.toml). Not handed one: pull the board's top queued item, bash "${DWARVES_KIT:-$HOME/.claude/dwarves-kit}/lib/board/backlog.sh" next, claim it (goal-registry) and flip it to claimed (the /kit:assign --next flow). The BACKLOG is the board; its Status column is the state machine (queued -> claimed -> speccing -> validated -> executing -> shipped, + parked/ dropped). Operator-named work is unchanged; pull is an additional trigger, never a daemon.
  2. Classify the type, then size the lane. bash "${DWARVES_KIT:-$HOME/.claude/dwarves-kit}/lib/classify/task-type-classify.sh" classify "<task>" first: spec-feature picks a lane below; any other type (incident / reconcile / operate / planning / learning / eval / research / review / doc / migration / data-tool) runs its TYPE LOOP per WORKFLOW.md ## Type loops, with its executor from the registry's agent column. The lane is STILL sized for every type (it is the evidence contract ship-gate enforces via the spec's Lane: header; the type is the content contract, WORKFLOW.md ### Lane x type composition). For code: pick tiny / normal / full / bug / backfill per WORKFLOW.md; default to normal; the classifier only suggests full, and the diff floor at push applies full-lane gates to hard paths. Between classification and done comes the grill (/kit:grill, or its one-question-at-a-time discipline driven inline): interview until the task is actually understood, type-shaped questions, recommended answers, contradictions checked against the repo, answers WRITTEN as they resolve (glossary / sparse ADR / the goal draft's Context). Tiny lane exempt. Record the grill's disposition either way: bash "${DWARVES_KIT:-$HOME/.claude/dwarves-kit}/lib/gate/gate-ledger.sh" record <rid> grill ran "<N> branches resolved", or, when the conversation already resolved the banks, ... record <rid> grill skipped "<why>"; a skip without a reason is invisible to telemetry, which defeats the point. Then phase 0: define the done scenario (bash "${DWARVES_KIT:-$HOME/.claude/dwarves-kit}/lib/gate/proof-gate.sh" contract "<task>" + the type's test-design dialect, test-design-standard §5b) BEFORE any work runs; the grill's answers are the done's raw material, and the goal draft carries the Done = line.
  3. Read the spec and its acceptance criteria. For a spec-driven task: the active spec's task row, its AC, its ## Verification, and its ## After state. No spec (tiny lane): the one obvious edit.
  4. Implement the smallest verifiable increment. One logical change. No speculative features, no premature abstraction; clarity over cleverness.
  5. Verify. Run the spec's ## Verification command (or the lane's check). Do not claim a result you did not run.
  6. Commit. Conventional commit, one logical change. No spec/ticket IDs in the subject line.

One unit of work, with what enforces each step:

  board row or operator ask
        |
        v
  classify type + size lane ----> grill ----> Done = <scenario>   [phase 0]
        |                                          |
        |                                          v
        |                                   the check that will
        |                                   prove it, named now
        v
  implement the smallest verifiable increment
        |
        v
  run the check yourself ......... a local run, not a remote one; a claim
        |                          you did not run is not a result
        v
  commit ......................... commit-format hook  [HARD]
        |
        v
  record the gate you ran ........ gate-ledger
        |
        v
  push / open the PR ............. ship-gate + push-to-main blocker  [HARD]
                                   (a lane gate with no `ran` or `override`
                                    entry refuses the push)

The check is local by contract. A repo may or may not run anything of its own after the push, so treat a remote pipeline as a second opinion and never as the verification a task loop owes. Read the repo's own README or CONTRIBUTING for what it runs and when.

If you cannot make progress, see zone 4 (Pause if) and stop with a named blocker note. Do not churn.

One rid per run, derived from the branch. <rid> everywhere below is $(bash "${DWARVES_KIT:-$HOME/.claude/dwarves-kit}/lib/gate/gate-ledger.sh" rid): the branch slug (type/ prefix stripped), the same key hooks/ship-gate.sh checks at push, so assign-time records and ship-time enforcement meet with no mirror re-records. Derive it AFTER the work branch exists; the verb refuses master/main/detached.

Show the road, then your position on it. Right after a lane is committed, print the checklist the run will walk: bash "${DWARVES_KIT:-$HOME/.claude/dwarves-kit}/lib/gate/gate-ledger.sh" plan <lane>. At each phase entry, print where the run stands: bash "${DWARVES_KIT:-$HOME/.claude/dwarves-kit}/lib/gate/gate-ledger.sh" progress <rid> <lane> (one status line: <rid> · <lane> · step k/n (<phase>) + the ✓/▶/· checklist). For the full story of a past or in-flight run: bash "${DWARVES_KIT:-$HOME/.claude/dwarves-kit}/lib/telemetry/lane-telemetry.sh" trace <rid>.

Escalate the review for enforcement surfaces. A run touching lib/ or hooks/ uses /kit:review-team (multi-lens), not a single reviewer. /kit:battery is gated by size: a SMALL change (lib/gate/battery-gate.sh prints SKIP) owes a proof of done instead.

Record your gates. When you run a phase gate (/kit:spec, /kit:spec-validate, /kit:execute, /kit:review, /kit:docs, /kit:ship, ...), record it so the run is auditable: bash "${DWARVES_KIT:-$HOME/.claude/dwarves-kit}/lib/gate/gate-ledger.sh" record <rid> <Phase> ran; record a deliberate skip as skipped "<why>". The ship-gate hook refuses a push whose lane has a required gate with no ran/override entry. Phase ORDER matters too: the lane plan is the V-model descent order; bash "${DWARVES_KIT:-$HOME/.claude/dwarves-kit}/lib/gate/gate-ledger.sh" descent <rid> <lane> names out-of-order records, surfaced at ship as an advisory. Full convention + the logged-override path: WORKFLOW.md "## Gate ledger and ship enforcement".

Gates are also MEASURED, not just recorded. Beside ran/skipped, bash "${DWARVES_KIT:-$HOME/.claude/dwarves-kit}/lib/gate/gate-ledger.sh" outcome <rid> <phase> start|end [caught=<bool>] brackets a gate with a duration and whether it caught a defect, on the same additive marker convention (a fourth | OUTCOME | line beside | GATE | / | DEBT | / | TOKENS |; existing readers ignore it). The only live emitter today is hooks/ship-gate.sh at the ship boundary, HOOK-ENFORCED but ship-boundary-only, not yet per-phase; read it back with outcome-read. A parallel wave closes the SPEC-number race at dispatch, not at spec-time. lib/queue/orchestrate.sh's own wavefront dispatch atomically reserves a number per sub-goal via bash "${DWARVES_KIT:-$HOME/.claude/dwarves-kit}/lib/spec/spec-next.sh" reserve (a portable mkdir-mutex over an append-only reservations ledger) before any worker can race spec-next.sh next; a standalone session still calls spec-next.sh next directly, unaffected. Generate the confirmation table, never hand-author it. bash "${DWARVES_KIT:-$HOME/.claude/dwarves-kit}/lib/gate/proof-table-gen.sh" <rid> renders docs/verification/generated/<rid>.md from the same gate/run ledger (surfacing the OUTCOME column above when present); see docs/verification/README.md "Generators write run ledgers, never the canonical." Full detail on all three, plus the two advisory measurement gates (coverage-delta, mutation-smoke): WORKFLOW.md "## Gate ledger and ship enforcement" and "## Advisory measurement gates".

3. Done means

A task or goal is done only when its acceptance criteria are met AND the verifier actually ran the check, not when you claim they pass. Self-reported "done" is not proof. The check compares against the Done = scenario defined at phase 0, whatever the work's type (PHILOSOPHY §6 N3): if no done scenario was defined before the work ran, the work was not assignable, and "done" has nothing to be measured against.

Concretely, done means: acceptance criteria met, the check actually ran (not just asserted), review recorded + report written, and the final response says what changed and what was not attempted. If you could not run the check, report that plainly; the anti-rationalization hook is the backstop for premature completion under Claude Code, but the honesty obligation is yours under any runtime.

Show the proof, never only describe it. A proof of done carries what the run really printed: the test recap or the tail of the run under an Output: line, or a committed screenshot or GIF for visual work (a video or a demo flow is linked beside it). The ship-gate refuses a proof whose green run is typed words alone. The same captured output goes in the final response, with the PR link, and in the PR body (wrap land builds the body from the proof file). A final response that says only "tests pass" has shown nothing. With [proof] visual = true, a UI change also owes an image through bin/proof-asset put; proof-gate.sh contract names what each task type owes.

Run tests the fast way. Iterate on one suite (bash tests/test-<name>.sh). Check regressions once, with bash tests/run-all.sh --changed --time: it runs only the suites the diff against origin/master touches, in parallel. Never loop over suites one by one, and never clone master to compare a baseline. The full --all glob takes about 25 minutes, and a nightly job runs it on the operator's host, so a session or worker never runs it. A spec line such as "no regression in every tests/test-wrap*.sh" means --changed, which selects those suites when the diff touches their modules.

Deployable-done (ADR-0028, reusing ADR-0025). DEPLOYABLE work is anything that runs somewhere, a service, a daemon, a feature behind a flag, or any change lib/gate/proof-ledger.sh classify puts in its stateful class (deploy / rollout / production / migration / schema / database / persistent-state signals in the diff or commit subjects). For deployable work, done = a deploy-proof + a UAT/acceptance run: the existing ADR-0025 stateful proof shape (a recorded run with Command:/Exit: AND a rollback note or [UNAVAILABLE: reason]) PLUS a UAT/acceptance line recording that the change was exercised in the target environment and accepted. This is enforced at ship by the SAME hooks/ship-gate.sh -> proof-ledger.sh check wall every stateful change already passes through, the ship-gate already DETECTS deployability (it classifies stateful), so a deployable item marked done without the deploy-proof is blocked exactly like any other unproven stateful change, or needs a logged override (proof-ledger.sh override <slug> "<reason>"). INERT, library, refactor, and docs work (the inert/behavioral classes) is unchanged, it owes no deploy-proof or UAT.

Understanding is a separate, advisory axis -- orthogonal to Done means above. A design record (before build) and an explainer + quiz nudge (at merge) gate the human's PARTICIPATION and ATTENTION, never correctness: they never change what "done" means here, never block a correct build, and are not enforced by any hook the way the verification gates are. Full model: WORKFLOW.md "## The understanding axis".

4. Pause if (ask a human)

Stop and ask a human before acting on any of these. These are decisions with direction or irreversible cost that a goal loop must not make on its own.

  • Architecture direction - a change to how the pieces fit, a new component, an interface or data-model shape.
  • Source-of-truth hierarchy - which file or section is canonical when two disagree (for example, moving the operate-contract between AGENTS.md, CLAUDE.md, and WORKFLOW.md).
  • Validation removal - weakening, deleting, or bypassing a test, an assertion, a hook, or any guardrail.
  • Risk-classification change - moving an assigned lane lighter, dropping a phase from a lane, or narrowing a hard path or a full-lane trigger. Staying on the default lane after a suggestion is not a lane change; the operator decides whether to assign the heavier one.
  • Privacy / security - secrets, credentials, access scope, anything that touches what data leaves the repo or who can reach it.

When you pause: write the named blocker, state the decision you are not making and why, and stop.

Self-intro (what is running and why)

Every /kit: command opens its FIRST reply with a one-line banner, [kit:<name>] <one-line purpose>, the purpose derived from that command's own frontmatter description. Every dispatched agent opens its report the same way ([kit:<agent>] <one-line purpose>). One banner line, then the real output; never repeated mid-run, and a mode whose contract is stricter (e.g. /kit:start --brief's single line) wins over the banner. A new user should never have to guess what is running or why it fired. Wired concretely into the highest-traffic entries (commands/start.md, commands/assign.md, commands/execute.md); every other command adopts on next touch, and this contract covers them meanwhile.


How the kit composes (subsystem modules)

The kit is a toolbox of self-contained subsystem modules under lib/<subsystem>/ (board, classify, gate, goal, queue, session, spec, stats, telemetry, plus the ledger substrate and single-purpose orphans), not one appliance you switch on. "tool" vs "lib" describes a module's SURFACE (leaf/human vs internal-helper), not its location; there is no separate tools/ tree. Each multi-verb subsystem exposes a standalone <subsystem> <verb> command (board next, gate ledger ..., classify ..., spec ..., goal ..., session ...) that forwards to the script owning that verb; the internal bash "${DWARVES_KIT:-$HOME/.claude/dwarves-kit}/lib/<subsystem>/<file>.sh" form used throughout the task loop still works unchanged. There is no kit uber-dispatcher, each command's own --help is the discovery surface. The read plane is stats: a stateless projection recomputed on demand from the append-only ledger, never a persisted second source of truth.

Adoption is layered, not all-or-nothing. install.sh wires the essential spine unconditionally (the spec-driven development (SDD) ship discipline: safety-gate, ship-gate, spec-drift-guard, secrets-guard, commit-format, anti-rationalization) and opt-in modules only when asked (install.sh --with board,session,stats,...), recording the enabled set in the consumer's kit.toml [modules] manifest, an install artifact that records the choice, never read at runtime. Full adoption model + rationale: docs/PHILOSOPHY.md and README.md.


How a goal is composed (for commands/assign.md)

The goal-crafter projects these four zones into a six-section /goal. The mapping is a composition, not 1:1: two of the six sections come from the active spec, not from this file. Keep the four zone names stable; renaming one without updating commands/assign.md breaks the projection.

/goal section Source
Context-to-read AGENTS.md zone 1 (Read in this order)
Constraints CLAUDE.md / AGENTS.md rules
Operating rules AGENTS.md zone 2 (Task loop)
Validation loop the active spec's ## Verification
Done-when AGENTS.md zone 3 (Done means) + the active spec's ## After state
Pause-if AGENTS.md zone 4 (Pause if)