diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index e95983f..6b3613a 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "forge", - "version": "1.1.1", + "version": "1.2.0", "description": "Idea-to-PR pipeline with a human gate at each seam: grill an idea into a spec, plan it adversarially into GitHub issues, then implement it against a negotiated contract and ship a PR.", "author": { "name": "Daniel Asirra", diff --git a/README.md b/README.md index cfdad83..c500004 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ The other two need: |---------|----------|-------------| | `/forge:interview [idea \| path/to/brief.md]` | PM | Relentless one-question-at-a-time grilling until you and Claude share an understanding of the idea, then synthesis into a PM-level spec. No code, no issues. | | `/forge:planning [path/to/spec.md \| description]` | PM | A planner drafts an epic with user stories, a critic attacks it in a separate context, they iterate up to 3 rounds. Files the result as a GitHub epic with native sub-issues for async human review. No technical content: no files, no schemas, no architecture. | -| `/forge:building <#issue ...> [--gate] [--max-rounds N] [--base ] [--surface ]` | DEV | A generator and evaluator negotiate a granular contract of "done" against the live codebase, a team builds in an isolated worktree, then the evaluator black-box tests the running artifact against that contract until it passes: driving a browser for a web app, calling the public API for a library, running argv and reading exit codes for a CLI. Opens a PR. | +| `/forge:building <#issue ...> [--no-gate] [--max-rounds N] [--base ] [--surface ]` | DEV | A generator and evaluator negotiate a granular contract of "done" against the live codebase, a team builds in an isolated worktree, then the evaluator black-box tests the running artifact against that contract until it passes: driving a browser for a web app, calling the public API for a library, running argv and reading exit codes for a CLI. Opens a PR. | ## Pipeline @@ -92,7 +92,8 @@ flowchart TD direction LR b0["0.5 · Preflight
gh + evaluation surface"] --> b1["1 · Isolated worktree"] b1 --> b2["2 · generator ⚔ evaluator
negotiate the contract
max 3 exchanges"] - b2 --> b4["4 · sonnet builders,
one per workstream"] + b2 --> b3{{"👤 3 · approve the contract
grounding + residual risks first
--no-gate skips"}} + b3 --> b4["4 · sonnet builders,
one per workstream"] b4 --> b5["5 · Static checks"] b5 --> b6["6 · evaluator black-box tests
the running artifact
max 5 rounds"] b6 -.->|"ROUND_FAILED
fresh fixer, sees only the critique"| b4 @@ -106,6 +107,10 @@ flowchart TD The contract negotiated in Phase 2 is the only plan `/forge:building` makes. There is no PLAN.md. Technical decisions belong to the builders, made against the code as they work, and Phase 6 judges the result against the contract rather than against the builders' account of it. +Facts are the exception, because a fact is not a decision. Before it writes a single criterion, the generator declares every store, path, env var, collection, and dependency its contract will name, each marked `EXISTS` with `file:line` evidence or `NEW`. The lead reproduces each `EXISTS` with a grep, and any `NEW` persistent substrate stops the run for one human question, gate or no gate. Deferring a decision keeps options open; deferring a fact just means somebody downstream invents it, and inventing and discovering look identical from inside a contract. + +For the same reason, `/forge:building` pauses on the negotiated contract by default, showing you the grounding block and the evaluator's residual risks before the criteria. The contract is the last artifact you can correct cheaply: after it, every criterion, every builder and every sibling issue inherits its premises. `--no-gate` runs straight through when you already trust them. + Every phase, agent, artifact, and loop is laid out in the [full pipeline reference](https://htmlpreview.github.io/?https://github.com/dasirra/cc-forge/blob/main/docs/pipeline.html), which also documents the evaluation surfaces. Source: [`docs/pipeline.html`](docs/pipeline.html). ## Design diff --git a/assets/pipeline.png b/assets/pipeline.png index b2c9628..8d57e91 100644 Binary files a/assets/pipeline.png and b/assets/pipeline.png differ diff --git a/commands/building.md b/commands/building.md index 8a01399..11338b2 100644 --- a/commands/building.md +++ b/commands/building.md @@ -1,6 +1,6 @@ --- description: Implement signed-off issues end to end with a team of agents in an isolated worktree. Before coding, a generator and an adversarial evaluator negotiate a granular contract of what "done" means; after coding, the evaluator black-box tests the running artifact against that contract until it passes. Ships as a PR. -argument-hint: <#issue | #issue #issue ... | "description of the work"> [--gate] [--max-rounds N] [--base ] +argument-hint: <#issue | #issue #issue ... | "description of the work"> [--no-gate] [--max-rounds N] [--base ] --- # /forge:building @@ -30,9 +30,11 @@ rubber-stamp evaluations. All shared state lives in `harness/` inside the worktree (gitignored): -- `harness/contract.json`: `{surface, criteria}`. `surface` is the evaluation - surface resolved in Phase 0.5, recorded once so a resumed run never - re-derives it. Each criterion is +- `harness/contract.json`: `{surface, grounding, criteria}`. `surface` is the + evaluation surface resolved in Phase 0.5, recorded once so a resumed run never + re-derives it. `grounding` is the array of substrate the contract stands on, + each entry `{name, status: EXISTS|NEW, evidence, human_ack}`; see Phase 2. + Each criterion is `{id, issue, criterion, verify_how, status: proposed|agreed|pass|fail}`. `issue` is the issue number the criterion belongs to, or `"integration"` for cross-issue behavior. Single-issue and free-form runs use one issue @@ -60,10 +62,11 @@ number does not resolve, stop and report it rather than guessing. If the request is free-form, restate it as a problem statement plus acceptance criteria before proceeding. -Flags: `--gate` pauses for human approval of the negotiated contract before -building (default is fully autonomous). `--max-rounds N` caps evaluation -rounds (default 5). `--base ` forces the base branch. -`--surface ` forces the evaluation surface. +Flags: the run pauses for human approval of the negotiated contract before +building. `--no-gate` skips that pause and runs autonomously, for work whose +premises you already trust. `--max-rounds N` caps evaluation rounds +(default 5). `--base ` forces the base branch. `--surface ` +forces the evaluation surface. ## Phase 0.5: Preflight @@ -125,7 +128,21 @@ granular, testable contract. Two subagents, separate contexts, artifacts only. 1. **Generator proposes** (opus): given the issue bodies and read access to - the codebase, write `harness/contract.json` with 10-20 granular criteria + the codebase, write `harness/contract.json`. + + Before any criterion, write the `grounding` block: every store, file path, + env var, collection, table, endpoint, package, or external system that any + criterion or fixture will name, each entry `{name, status: EXISTS|NEW, + evidence}`. EXISTS requires evidence: a `file:line` in the current worktree + that names the thing. NEW means this run creates it. Start from the issue's + Grounding block if it has one; contradicting that block is allowed only by + surfacing the contradiction, never by silently overriding it. Inventing a + substrate is sometimes right, and the generator cannot tell the difference + from the inside: an issue that needs a store the project lacks and an issue + whose store it simply failed to find look identical while writing criteria. + That is what `status` is for. Declare, do not decide. + + Then write 10-20 granular criteria PER ISSUE, each tagged with its `issue`, plus 3-8 `integration` criteria covering behavior that spans issues (only for multi-issue runs). Never dilute: three issues means roughly 40-60 criteria, not 30 split three @@ -139,11 +156,35 @@ only. "movement works", never "handles empty input gracefully". Cover the unhappy paths the issue's Proposed behavior section describes: empty states, errors, edge cases. +1.5 **Lead verifies grounding mechanically** (you, before relaying the + contract). This is a grep, not a judgment. For each EXISTS entry, run + `git grep -n ` (or `test -e` for paths) and confirm the cited + evidence. An EXISTS entry with no hit goes back to the generator: do not + relay a contract whose premises you could not reproduce. Then scan the + fixtures and every `verify_how` for substrate-shaped tokens (ALL_CAPS + identifiers, slash paths, collection and table names, URLs, package names) + and confirm each appears in `grounding`. A token with no entry blocks the + relay. + + Any NEW entry naming persistent substrate (a store, schema, collection, env + var, or external dependency) is escalated to the human with AskUserQuestion + before the evaluator sees the contract, **gate or no gate**: "this contract + invents ``; confirm nothing existing should serve instead." Record the + grep output and the human's answer in `harness/progress.json`, and set + `human_ack` on the entry. This is the run's one mandatory pause besides the + Phase 0.5 surface question, and it exists for the same reason: a wrong + answer here poisons everything downstream, and it costs a minute to ask. + 2. **Evaluator attacks** (opus, sees ONLY the issue body and the proposed contract): find missing edge cases, criteria too vague to verify, scope beyond the issue, criteria tagged to the wrong issue or integration - behavior missing entirely, and tests that would pass while the feature - is broken. + behavior missing entirely, tests that would pass while the feature + is broken, and **ungrounded substrate**: any store, path, env var, + collection, endpoint, or dependency named in a criterion or fixture that is + absent from the `grounding` block, or marked EXISTS without evidence, is a + BLOCKING objection. You cannot read the code, and you do not need to: the + grounding block's quoted evidence is an artifact, and a noun with no entry + is visible from where you sit. Write objections into the contract file. If sound, mark all criteria `agreed`. 3. Iterate: hand objections to the generator, revise, re-attack. Max 3 @@ -161,20 +202,37 @@ reason, evaluator must accept, the issue comment gets updated with an "Amended" note. Never silently edit a criterion because it turned out to be hard. -## Phase 3: Human gate on the contract (opt-in) +## Phase 3: Human gate on the contract (default) + +Default: pause. Show the user the agreed contract, in this order: the +grounding block (NEW entries first), the evaluator's residual risks, then the +criteria list and any disputes. Wait for approval or adjustments before +building. A human skims what he is shown first; show him the premises, not the +paperwork. + +The pause is the default because the contract is the last artifact a human can +correct cheaply. After it, every criterion, every builder, and every sibling +issue inherits its premises, and the amendment rule makes changing one an +event. A minute here is worth a rebuild there. -Default: no pause. The agreed contract is already posted to the issue -(Phase 2), so the human can inspect it asynchronously, and the run continues -autonomously into execution. +If `--no-gate` was passed: no pause. The agreed contract is already posted to +the issue (Phase 2), leading with the same grounding block and residual risks +above the criteria, so the human can inspect it asynchronously and the run +continues into execution. Use this when you already trust the premises, not to +save a minute. -If `--gate` was passed: show the user the agreed contract (criteria list -plus any disputes) and wait for approval or adjustments before building. +Either way, the NEW-substrate escalation in Phase 2 step 1.5 is not part of +this gate and fires regardless. It asks whether the contract may invent a +store; this gate asks whether the contract is right. ## Phase 4: Execution (sonnet team, straight from the contract) There is no technical planning phase and no PLAN.md: the contract is the plan, and technical decisions belong to the builders, made against the code -as they work. As lead, do the split inline before spawning anyone: +as they work. The `grounding` block is the one exception: which existing +system a criterion reads or extends is a verified fact, fixed in Phase 2, and +not a builder's to re-decide. As lead, do the split inline before spawning +anyone: - Group the contract criteria into workstreams (often just one for issue-sized work) and give each workstream a file territory, so parallel @@ -281,6 +339,12 @@ auto-fixable, link to the updated PR. - The evaluator never reads generator transcripts, and no agent other than the generator-evaluator pair (via the amendment rule) may modify agreed contract criteria. You do not weaken a criterion to make a round pass. +- **Never relay a contract whose grounding you have not reproduced.** An EXISTS + entry is a claim about the world; you check it with a command, not with + trust. A criterion can be re-attacked in a later round, but a false premise + is silently inherited by every criterion written on top of it, and by every + sibling issue that builds on the same substrate afterwards. A fact does not + go stale the way a design does; it becomes false and fails its grep. - **The evaluator never runs the builder's test suite and never reads the implementation.** Builder-written tests encode the builder's understanding, so a green suite certifies whatever misunderstanding produced the bug. That diff --git a/commands/interview.md b/commands/interview.md index 2817662..7ebd1b0 100644 --- a/commands/interview.md +++ b/commands/interview.md @@ -23,7 +23,10 @@ Before the first question: - If you are inside a codebase the idea touches, explore it first (use an Explore subagent if the repo is non-trivial) so your questions and - recommendations are grounded in what already exists. + recommendations are grounded in what already exists. Record what you + find: every existing system, store, or dataset the idea would consume + or extend goes into the spec's Grounding section as a fact, whether or + not any question depends on it. - Scope check: if the idea spans several independent features, say so and help the user split it. Interview one feature at a time. @@ -40,10 +43,12 @@ Interview rules: yourself and move on instead of asking. - **Stay at product altitude**: users and actors, behavior, empty/error/edge states, scope boundaries, success criteria, priorities, rollout. Do NOT ask - about schemas, file paths, libraries, or architecture; /forge:planning bans that - content and /forge:building negotiates it against the codebase later. If a - technical unknown genuinely blocks a product decision, record it as a - deferred question and continue. + the user to *decide* schemas, libraries, or architecture; /forge:planning bans + those decisions and /forge:building negotiates them against the codebase later. + Do ask, or better, go and read, where an existing system the feature will + consume already lives: that is a fact, not a decision, and it belongs in + Grounding. If a technical unknown genuinely blocks a product decision, record + it as a deferred question and continue. - When a decision has 2-3 genuinely different viable shapes, present them as options with trade-offs before asking, recommendation first. - The user can end the interview at any time ("wrap it up", "answer the rest @@ -81,6 +86,13 @@ error, and edge states> +## Grounding (facts, not decisions) + + ## Out of scope @@ -90,8 +102,11 @@ what gives /forge:planning a definition of done> /forge:planning critic and the /forge:building negotiation to pick up> ```` -No technical content beyond the deferred notes in Open questions: no file -paths, schemas, function names, or architecture anywhere else. +No technical decisions anywhere: no schemas, no architecture, no chosen +libraries. The Grounding section is the one exemption, and it may name +files, stores, and functions because it records what already exists, not +what to build. Outside Grounding and the deferred notes in Open questions, +no technical content at all. Self-review before saving, fix inline, no re-review: diff --git a/commands/planning.md b/commands/planning.md index 54f935d..14a8db2 100644 --- a/commands/planning.md +++ b/commands/planning.md @@ -18,11 +18,13 @@ $ARGUMENTS ## Operating principles - **PM altitude only.** Issues contain user stories, goals, human-readable - acceptance criteria, proposed behavior, scope boundaries, and dependencies. - NEVER file paths, schemas, function names, libraries, or architecture. - Granular testable contracts are negotiated adversarially at /forge:building time, - against the codebase as it exists then. Freezing them now would let them go - stale. + acceptance criteria, proposed behavior, scope boundaries, dependencies, and a + Grounding block. NEVER schemas, libraries, or architecture, and no file paths + or function names outside Grounding. Granular testable contracts are negotiated + adversarially at /forge:building time, against the codebase as it exists then. + Freezing them now would let them go stale. Grounding is different: it records + what already exists, and a fact does not go stale, it becomes false and fails + its check loudly. - **Issues must be self-sufficient for review.** A human reading only the GitHub issues must be able to understand the full proposed solution: what will be built, how it behaves, and why. Use prose plus mermaid diagrams of @@ -70,13 +72,18 @@ Read the repo's existing conventions so you mirror them: - If an existing epic is present, read its body (`gh issue view --json body`) and copy its structure. -## Phase 2: Light reality check (optional, bounded) +## Phase 2: Grounding and reality check (bounded; skip only if greenfield) Dispatch ONE Explore sub-agent with a narrow question: what does this product currently do in the area the feature touches, and what adjacent capabilities -already exist? This is for the critic's feasibility judgment and for sane -phase ordering ONLY. Its findings must never leak file paths or technical -detail into issue bodies. For a greenfield project, skip this phase. +already exist? This serves the critic's feasibility judgment, sane phase +ordering, and grounding. If the spec carries a Grounding section, verify each +entry still holds against the repo; either way, produce a grounding table: +every capability, store, or system the plan treats as already existing, +confirmed with a file or symbol reference, or explicitly marked NEW. Grounding +facts, including the reference that proves them, are the one kind of technical +content permitted into issue bodies, quoted in each child's Grounding block. No +other technical detail may leak. For a greenfield project, skip this phase. ## Phase 3: Planner drafts (subagent, fresh context) @@ -243,6 +250,12 @@ is trivially linear.> ## Out of scope - ... +## Grounding + + ## Dependencies **Blocked by** #<...>. **Blocks** #<...>. @@ -282,8 +295,10 @@ Startable first (no deps): #<...> ## Guardrails -- No technical content in any issue body. If the planner leaks it, strip it - before filing. +- No technical decisions in any issue body. The Grounding block is exempt: it + carries verified facts about existing systems, with their locations. If the + planner leaks a decision, strip it before filing; if it leaks a fact, move it + into Grounding instead of deleting it. - Diagrams and solution descriptions stay at product level: user flows, states, interactions. No component diagrams, no data models, no API shapes. If a diagram names a file, table, or endpoint, redraw it. diff --git a/docs/pipeline.html b/docs/pipeline.html index 693d0c5..4bbba37 100644 --- a/docs/pipeline.html +++ b/docs/pipeline.html @@ -224,7 +224,7 @@
- Pipeline reference · forge@cc-forge · 2026-07-09 + Pipeline reference · forge@cc-forge · 2026-07-10

/forge:interview + /forge:planning + /forge:building, as currently written

Every phase, agent, artifact, and loop in the three commands. Adversarial pairs never share context; they exchange files, relayed by the orchestrator. Source: github.com/dasirra/cc-forge.

@@ -258,7 +258,7 @@

/forge:interview + /forge:planning + /forge:building, as currently writtenhuman in the loop agents · async review human - agents · afk, unattended + agents · gated, then afk human

@@ -283,7 +283,7 @@

1/forge:interview

1

Interview 👤

-

Explore the codebase first; answer from it instead of asking. Scope check, then walk the decision tree at product altitude: behavior, edge states, scope, success criteria. Technical unknowns get parked, not asked.

+

Explore the codebase first; answer from it instead of asking. Scope check, then walk the decision tree at product altitude: behavior, edge states, scope, success criteria. Technical decisions get parked, not asked. What already exists gets written down: the spec's Grounding section records every system the feature consumes.

👤 you answerquestion + recommendation @@ -306,7 +306,7 @@

Synthesize

2/forge:planning

-

PM altitude only. User stories and observable behavior; never files, schemas, or architecture.

+

PM altitude only. User stories and observable behavior; never schemas or architecture. Grounding is the one exemption: facts about what already exists, with their references.

@@ -324,9 +324,9 @@

Preconditions

2 -

Light reality check · optional

-

One Explore subagent: what does the product do today in this area? Product-level findings only.

-
Explore
+

Grounding & reality check · greenfield only skips

+

One Explore subagent: what does the product do today in this area, and what does it already have? Findings become a grounding table, quoted into each issue's Grounding block. Facts carry their file reference; decisions still never leak.

+
Exploregrounding table
@@ -389,7 +389,7 @@

Base branch + worktree

2

Contract negotiation ⚔

-

What "done" means: 10-20 observable criteria per issue + 3-8 integration criteria, each carrying a verification method written in the surface's vocabulary. The evaluator sees only issue + proposed contract and attacks vagueness, wrong tagging, weak tests. Agreed criteria post per-issue to GitHub; amendments only through this channel.

+

First the grounding block: every store, path, env var, collection, endpoint and dependency the contract will name, each EXISTS with file:line evidence or NEW. The lead reproduces every EXISTS with a grep and relays nothing it cannot reproduce; any NEW substrate stops for one human question, gate or no gate. Then what "done" means: 10-20 observable criteria per issue + 3-8 integration criteria, each carrying a verification method written in the surface's vocabulary. The evaluator sees only issue + proposed contract and attacks vagueness, wrong tagging, weak tests, and ungrounded nouns. Agreed criteria post per-issue to GitHub; amendments only through this channel.

generator · opus contract.jsonobjections @@ -401,15 +401,15 @@

Contract negotiation ⚔

3 -

Human gate · only with --gate

-

Default is autonomous; the contract is already on the issue for async inspection.

-
👤 optional approval
+

Human gate · default, --no-gate skips

+

Default is a pause: the contract is the last artifact you can correct cheaply. Grounding and residual risks lead the view, above the criteria. --no-gate runs on and leaves the contract on the issue for async inspection. The NEW-substrate question in phase 2 is not part of this gate and fires either way.

+
👤 contract approval
4

Execution

-

No technical plan, no PLAN.md: the contract is the plan. The lead splits criteria into workstreams with file territories inline; one sonnet teammate per workstream makes its own technical decisions against live code.

+

No technical plan, no PLAN.md: the contract is the plan. The lead splits criteria into workstreams with file territories inline; one sonnet teammate per workstream makes its own technical decisions against live code. Grounding is the exception: which existing system a criterion reads is a verified fact, not a builder's to re-decide.

builders · sonnet × Nprogress.json
@@ -481,8 +481,9 @@

👤 Human touchpoints

  • /forge:interview · the alignment that can't be delegated
  • surface confirmation · one question in preflight
  • +
  • new substrate · one question when the contract invents a store, gate or no gate
  • issue review · edit + arbitrate on GitHub before /forge:building
  • -
  • --gate · optional contract approval
  • +
  • contract approval · the default pause; --no-gate skips it
  • PR review & merge · per phase, taste + QA