22653e410a
Eighth and final skill via the boss pattern. implement carries the per-task loop mechanics; implementer + spec-reviewer + quality-reviewer + tester are phase references the implement-orchestrator inhales at each role-switch. All eight skills + their agents now live in the plugin. AILang can switch over by dropping a project profile + removing its in-tree skills/ in a follow-up. Vocabulary substitutions: - AILang → "this project" - milestone → cycle - Boss → orchestrator (consistently) - ailang-implement-orchestrator → implement-orchestrator - ailang-implementer → implementer - ailang-spec-reviewer → spec-reviewer - ailang-quality-reviewer → quality-reviewer - ailang-tester → tester AILang-specific bits dropped or generalized: - `docs/plans/<iteration>.md` / `docs/specs/<milestone>.md` → `paths.plan_dir` / `paths.spec_dir` - `/tmp/ail-iter/<iter_id>/` → `/tmp/iter-<iter_id>/` - `bench/orchestrator-stats/` → `/tmp/iter-<iter_id>/stats.json` with note that a project-configured stats dir can be used - `cargo build --workspace` / `cargo test --workspace` → `commands.build` / `commands.test` - `examples/<name>.ail.json` → "fixture in the project's canonical fixture form" - `crates/ail/tests/e2e.rs` → "the project's E2E test location" - The entire AILang "Architecture rules (binding)" block in implementer (determinism via BLAKE3, LLVM text IR, schema ailang/v0, RC + bump allocator, Type::Fn effects, Implicit-mode rule) → generic "the binding architectural rules are declared in CLAUDE.md and the design ledger" - `git log --all --grep='or.2'` reference in implement-orchestrator → dropped (was AILang project history) - `bench/orchestrator-stats/<YYYY-MM-DD>-iter-<iter_id>.json` → generic stats path with project-configured option - AILang-specific quality-bar examples (Implicit-mode RC unflagged, libllvm call, schema break without migration note) → generic "anything that violates a binding architectural rule from CLAUDE.md / design ledger" - AILang-specific tester examples (`(show 42)` Int dispatch, ailang/v0 schema) → generic "feature X variant" / "API response" / observable-behaviour framing - `Brummel` references → dropped - `notify.sh` hardcoded → "the project's configured notification command" - `iter/...` branches (legacy AILang concept) → "iteration branches are not used" Universal substance preserved verbatim across all six files: - implement SKILL Iron Law (7 lines including new-cycle triggers and BLOCKED.md convention) - Per-task sub-status table (9 rows) - implement-orchestrator: 7-phase process (Phase 0 clean tree, Phase 1 context load mode-dependent, Phase 2 per-task loop with 4 sub-phases, Phase 3 E2E, Phase 4 BLOCKED.md, Phase 5 stats, Phase 6 end-report) - implement-orchestrator: BLOCKED.md template, stats.json schema, end-report fixed structure - implementer: TDD-first discipline, RED-first exceptions, 6-step process, 4-state status protocol - spec-reviewer: missing/unrequested-extra definitions, 7-step process, 4-state status protocol - quality-reviewer: 8 quality-bar categories, severity definitions, 6-step process incl. Strengths-first rule - tester: 4-clause Iron Law, "named property" doctrine, 4-state status protocol Common Rationalisations + Red Flags tables preserved across all six files with vocabulary substitution only. No discipline compressed. All seven sibling skills (boss, brainstorm, planner, debug, audit, fieldtest, docwriter) and the AILang reference agents now resolve correctly via `../<skill>/...` relative paths post-flatten.
259 lines
13 KiB
Markdown
259 lines
13 KiB
Markdown
---
|
||
name: implement
|
||
description: Use when an implementation plan exists under paths.plan_dir and is ready to execute, OR when a debug RED-test is handed off for a bugfix. Dispatches the implement-orchestrator agent, which runs the entire per-task loop (implementer phase → spec-compliance check → quality check, as sequential role-switches in its own context) directly in the working tree without creating commits, writes a stats file (and on BLOCKED/PARTIAL also `BLOCKED.md`), and returns a compressed end-report. The orchestrator reads the end-report, inspects the working tree, decides commit shape, and performs all commits.
|
||
---
|
||
|
||
# implement — plan execution via a dedicated orchestrator-agent
|
||
|
||
> **Violating the letter of these rules is violating the spirit.**
|
||
|
||
## Overview
|
||
|
||
Plan execution is fully delegated. The orchestrator dispatches
|
||
ONE subagent (`implement-orchestrator`), which runs the entire
|
||
per-task loop in its own context: implementer phase → spec-
|
||
compliance check → quality check, per task, as sequential
|
||
role-switches inside the orchestrator-agent itself (Claude
|
||
Code does not permit nested subagent dispatch — see
|
||
Cross-references). All work lives in the working tree: code
|
||
edits and the stats file (and `BLOCKED.md` if the outcome is
|
||
PARTIAL/BLOCKED). The orchestrator-agent does NOT commit.
|
||
The orchestrator sees one ≤500-token end-report and an
|
||
unstaged working tree, then decides commit shape — the
|
||
end-report carries the per-task summary the orchestrator
|
||
uses to write the commit body.
|
||
|
||
This skill body is intentionally short. The procedural
|
||
details of the per-task loop live in
|
||
`agents/implement-orchestrator.md`. The **canonical
|
||
discipline** (Iron Law, sub-status table, common
|
||
rationalisations) lives in this file and is read by the
|
||
orchestrator-agent every dispatch.
|
||
|
||
## When to Use / Skipping
|
||
|
||
Triggers:
|
||
|
||
- A plan exists under `paths.plan_dir` (standard mode).
|
||
- A `debug` skill has produced a RED test + cause and is
|
||
handing off for the GREEN side (mini mode).
|
||
|
||
**Never skipped** when there is code to ship. Trivial
|
||
mechanical edits (one-line typo fix, schema rename across N
|
||
files) MAY be handled inline by the orchestrator without
|
||
dispatch, per the project's CLAUDE.md "trivial mechanical
|
||
edits" carve-out — but no review-and-commit discipline is
|
||
shed.
|
||
|
||
## The Iron Law
|
||
|
||
```
|
||
THE IMPLEMENTER NEVER COMMITS. CODE EDITS AND THE STATS FILE LIVE IN THE WORKING TREE AS UNSTAGED CHANGES UNTIL THE ORCHESTRATOR COMMITS THEM.
|
||
MAIN HEAD IS SACROSANCT — NO RESET, NO REVERT, BY ANY ACTOR. MAIN MOVES FORWARD ONLY VIA ORCHESTRATOR COMMITS.
|
||
PER-TASK PHASES RUN SEQUENTIALLY IN THE ORCHESTRATOR-AGENT'S OWN CONTEXT — implementer phase, then spec-compliance check, then quality check. Each phase is a deliberate role-switch, NOT a fresh subagent (nested-subagent dispatch is forbidden by Claude Code).
|
||
TWO-STAGE CHECK PER TASK: SPEC COMPLIANCE FIRST, CODE QUALITY SECOND.
|
||
NEVER START THE QUALITY CHECK BEFORE THE SPEC-COMPLIANCE CHECK IS GREEN.
|
||
NEVER PUSH PAST `BLOCKED` BY HAND.
|
||
ON `PARTIAL` OR `BLOCKED`, THE ORCHESTRATOR-AGENT WRITES `BLOCKED.md` AT THE REPO ROOT BEFORE RETURNING — UNCOMMITTED BY CONVENTION. ON `DONE`, NO SEPARATE FILE.
|
||
```
|
||
|
||
## Per-task sub-status mechanics
|
||
|
||
The orchestrator-agent reads and follows this table verbatim
|
||
every dispatch. Sub-status values are *internal* to the
|
||
orchestrator-agent — they describe the state of an inline
|
||
role-phase, not the status of a separate subagent. The
|
||
vocabulary is preserved because it maps 1:1 to the phase
|
||
reference files (`implementer.md` / `spec-reviewer.md` /
|
||
`quality-reviewer.md`) the orchestrator-agent consults at
|
||
each role-switch.
|
||
|
||
| Sub-status | Action |
|
||
|------------|--------|
|
||
| `DONE` | next phase / next task |
|
||
| `DONE_WITH_CONCERNS` | accumulate concern, next phase |
|
||
| `NEEDS_CONTEXT` (1st–2nd) | re-attempt the phase with expanded context |
|
||
| `NEEDS_CONTEXT` (3rd) | stop → `BLOCKED` to orchestrator, reason `context-exhausted` |
|
||
| `non_compliant` / `changes_requested` (1st–2nd) | switch back to implementer mindset, repair with the check's report as repair brief, then re-run the check phase |
|
||
| `non_compliant` / `changes_requested` (3rd) | stop → `BLOCKED` to orchestrator, reason `review-loop-exhausted` |
|
||
| `BLOCKED` (implementer phase) | stop → `BLOCKED` to orchestrator, reason verbatim |
|
||
| `unclear` (spec-compliance phase) | stop → `BLOCKED` to orchestrator, reason `spec-ambiguous` |
|
||
| Tool / infra error | stop → `BLOCKED` to orchestrator, reason `infra` + raw error |
|
||
|
||
Re-loop limit: 2 retries per failure-mode per task. The 3rd
|
||
is `BLOCKED` to the orchestrator. `skip task K, continue` is
|
||
intentionally NOT a mode — tasks have implicit ordering
|
||
dependencies and the orchestrator-agent does not know the
|
||
dependency graph.
|
||
|
||
## The Process — orchestrator side
|
||
|
||
### Step 1 — Dispatch the orchestrator-agent
|
||
|
||
For a standard iteration:
|
||
|
||
```
|
||
Agent("implement-orchestrator", {
|
||
mode: "standard",
|
||
iter_id: "<iter_id>", // e.g. "ct.2.3", "or.1", "23.4"
|
||
plan_path: "<path under paths.plan_dir>",
|
||
task_range: [3, 8] // optional
|
||
})
|
||
```
|
||
|
||
For a debug-handoff (mini mode):
|
||
|
||
```
|
||
Agent("implement-orchestrator", {
|
||
mode: "mini",
|
||
iter_id: "bugfix-<short-symptom>",
|
||
red_test_path: "<absolute path>",
|
||
cause_summary: "<1-2 sentences from debugger>",
|
||
constraint: "minimal fix, no surrounding cleanup"
|
||
})
|
||
```
|
||
|
||
Before dispatch: ensure the working tree is clean
|
||
(`git status --porcelain` empty). The orchestrator-agent's
|
||
Phase 0 will refuse to start on a dirty tree.
|
||
|
||
### Step 2 — Read the end-report
|
||
|
||
The orchestrator-agent returns a ≤500-token plain-text
|
||
report (see the agent's "Output format — end-report" section
|
||
for the fixed structure). Read it. The end-report is the
|
||
only thing that costs the orchestrator-context tokens;
|
||
per-task chatter has stayed inside the orchestrator-agent.
|
||
|
||
### Step 3 — Orchestrator inspect + commit step (on DONE)
|
||
|
||
The orchestrator-agent returns with code edits and the stats
|
||
file sitting in the working tree as unstaged changes.
|
||
Nothing is committed yet, and there is no `BLOCKED.md` (DONE
|
||
never writes one).
|
||
|
||
1. Inspect: `git status` and `git diff` — confirm the
|
||
changes match what the end-report claims. The end-report
|
||
is the per-task summary; use it as the basis for the
|
||
commit body.
|
||
2. Decide commit shape — by default one cohesive commit for
|
||
the whole iter; split into a few logical commits only if
|
||
the diff genuinely covers multiple unrelated changes.
|
||
Per-task commit splitting is NOT a goal; the iter is the
|
||
unit of consistency the orchestrator is committing to.
|
||
3. Write the commit body. It carries everything a future
|
||
reader needs that the diff itself does not: the *why*,
|
||
the alternatives that were considered and rejected, the
|
||
verification steps run, and any concerns that remain.
|
||
Detail-fill comes from the end-report — the per-task
|
||
chatter that stayed inside the orchestrator-agent does
|
||
not come back, by design.
|
||
4. Stage + commit the code edits and the stats file.
|
||
5. If trigger is done-state and the user is away, run the
|
||
project's configured notification command per
|
||
`../boss/SKILL.md` "Done-state notifications" subsection.
|
||
|
||
### Step 4 — Orchestrator handling (on PARTIAL or BLOCKED)
|
||
|
||
The orchestrator-agent returns with whatever work-in-progress
|
||
it managed plus `BLOCKED.md` at the repo root carrying the
|
||
diagnostic. Nothing is committed. The orchestrator decides
|
||
what to do with the dirty working tree:
|
||
|
||
1. Read `BLOCKED.md` — `## What did not` names the failure
|
||
mode and the worker's verbatim reason. Read `git diff`
|
||
to see what was attempted.
|
||
2. Decide:
|
||
- **Repair:** keep the working-tree changes in place (or
|
||
stash them with `git stash` if a clarifying read of
|
||
clean main is needed first). Adjust plan or extend
|
||
context; **delete `BLOCKED.md`** (`rm BLOCKED.md`)
|
||
before re-dispatch — the orchestrator-agent's Phase 0
|
||
clean-tree check counts it as dirt. Either stash
|
||
everything and re-dispatch on a clean tree, or commit
|
||
the known-good subset, then `rm BLOCKED.md`, then
|
||
re-dispatch.
|
||
- **Discard:** `git checkout -- .` to drop unstaged file
|
||
changes; `git clean -fd BLOCKED.md` (or `rm BLOCKED.md`)
|
||
plus anything else new. main HEAD does NOT move.
|
||
- **Escalate:** ask the user via the configured
|
||
notification command. `BLOCKED.md` sits in the working
|
||
tree until the conversation resumes.
|
||
|
||
Under no circumstance does the orchestrator `git reset` or
|
||
`git revert` on main: there is nothing on main to undo (the
|
||
orchestrator-agent did not commit), and the policy forbids
|
||
history rewinding on main even if there were.
|
||
|
||
## Handoff Contract
|
||
|
||
`implement` consumes:
|
||
|
||
| Source | Carrier |
|
||
|--------|---------|
|
||
| from `planner` | path to plan under `paths.plan_dir` (+ optional `task_range`) |
|
||
| from `debug` | RED-test path + cause summary + minimal-fix constraint |
|
||
|
||
`implement` produces: an unstaged working tree containing the
|
||
code edits and the stats file; on PARTIAL/BLOCKED, also
|
||
`BLOCKED.md` at the repo root. The orchestrator inspects,
|
||
commits the code + stats (DONE) or repairs/discards
|
||
(PARTIAL/BLOCKED). No further hand-off — `audit` runs
|
||
independently at cycle close.
|
||
|
||
## Common Rationalisations
|
||
|
||
| Excuse | Reality |
|
||
|--------|---------|
|
||
| "Single task, dispatch overhead exceeds the work" | The orchestrator-agent IS the discipline. A single dispatch is cheap; the per-task phase loop and the working-tree isolation are the value. |
|
||
| "Let me have the orchestrator-agent commit the per-task work, it's cleaner" | The orchestrator-agent never commits. Orchestrator-only commit is a project-wide rule: only the orchestrator decides when a state is consistent enough to enter main history. |
|
||
| "Per-task commits would help bisection later" | The orchestrator-agent's per-task phases are review gates, not bisection points. Iter-level commits are the bisection unit — and they only exist if the whole iter passes the orchestrator's review. |
|
||
| "BLOCKED end-report, let me dig into BLOCKED.md and continue myself" | Read the `## What did not` section first. The orchestrator-agent stopped at the re-loop limit for a reason. Continuing by hand undoes the discipline. |
|
||
| "End-report says PARTIAL with 4/5 tasks DONE — close enough, commit them" | The 5th task may carry an invariant the earlier 4 silently depend on. Either re-dispatch for the missing task or `git checkout -- .` and re-plan. |
|
||
| "BLOCKED.md feels redundant — the end-report already has the blocked detail" | The end-report dies when the chat scrolls; `BLOCKED.md` sits in the working tree across pauses, mode-switches, and orchestrator-inspection rounds. It is the durable handoff. |
|
||
| "The per-task phases run inline anyway, just have the orchestrator dispatch the reviewer-agents instead and skip the orchestrator-agent" | That gives back fresh-per-phase context but loses the orchestrator-context offload — the per-task chatter goes back through the orchestrator. The orchestrator-agent exists precisely for the offload. If you want fresh-per-phase context AND offload, you want a capability Claude Code does not provide. |
|
||
| "BLOCKED iter with a bad commit on main — let me `git revert` it" | There is no bad commit on main: the orchestrator-agent did not commit. Bad work stays in the working tree where it is still discardable. main HEAD is sacrosanct. |
|
||
| "Re-dispatch refuses because `BLOCKED.md` is still in the tree — let me just commit it to clear the check" | No. `BLOCKED.md` is never committed. `rm BLOCKED.md` (or stash) before re-dispatch — the file's whole purpose is to live in the working tree, not on main. |
|
||
|
||
## Red Flags — STOP
|
||
|
||
- Orchestrator dispatching `implementer` directly (bypassing
|
||
the orchestrator-agent).
|
||
- Orchestrator running `git reset` or `git revert` on main.
|
||
- Orchestrator-agent running `git commit` (anywhere, ever).
|
||
- Two `/implement` runs overlapping on the same working tree.
|
||
- `BLOCKED.md` staged or committed by anyone.
|
||
- End-report longer than ~500 tokens.
|
||
|
||
## Cross-references
|
||
|
||
- **Agent dispatched:** `agents/implement-orchestrator.md` —
|
||
carries the per-task loop inline; each phase is a
|
||
role-switch in the orchestrator-agent's own context. The
|
||
role-files below are *phase references* (the
|
||
orchestrator-agent reads them at each role-switch to
|
||
inhale the discipline) — they are NOT separately
|
||
dispatched subagents:
|
||
- `agents/implementer.md` — Phase 2.1 reference
|
||
(implementer mindset, TDD discipline)
|
||
- `agents/spec-reviewer.md` — Phase 2.2 reference
|
||
(spec-compliance mindset)
|
||
- `agents/quality-reviewer.md` — Phase 2.3 reference
|
||
(quality-review mindset)
|
||
- `agents/tester.md` — Phase 3 reference (E2E coverage
|
||
mindset)
|
||
- **Why inline phases, not nested subagents.** Claude Code
|
||
does not permit a subagent to spawn other subagents. The
|
||
orchestrator-agent cannot dispatch the role-agents above;
|
||
it adopts each role as a sequential phase in its own
|
||
context. This was a known platform constraint at the time
|
||
the role was designed.
|
||
- **Input sources:**
|
||
- `../planner/SKILL.md` — produces the plan files this
|
||
skill consumes
|
||
- `../debug/SKILL.md` — produces the RED-test handoff for
|
||
mini-mode
|
||
- **Output target:** orchestrator reads the end-report,
|
||
inspects the working tree, and commits; `../audit` runs
|
||
at cycle close.
|