Develop: Spec-Driven Development Feature Loop

Workflow

Spec-driven development loop for an existing feature spec: gathers context, then iterates a developer/evaluator loop whose independent evaluator re-runs the build/test gate, proves every requirement's test fails on the old code and passes on the new, and rejects tampered tests until it approves, then summarizes the change.

Usage

echo "<your request>" | octomind workflow develop

Reads your request from stdin. Add --dry-run to validate and print the plan without running any steps.

Pipeline

  1. 1 context Sequential developer:context

    Take the user spec and gather the most important context to begin development. <spec> {{input}} </spec> Locate the exact files, functions, and line ranges to touch and the existing patterns to reuse. Identify the projec…

  2. 2 upstream Sequential assistant:researcher

    The spec below may be a reported issue (bug report / feature request) against a project with a public home. If so, locate the upstream issue, its linked discussion, and any existing fix or merged change, and produce imp…

  3. 3 development Loop max 3×
    • developer developer:general continue

      We are working on the following spec: <spec> {{input}} </spec> Pinpoints and verification command from context: <context> {{context}} </context> Upstream contract notes — when present, mirror them exactly (names, signat…

    • brief developer:brief fresh

      Read the original spec and the current unstaged git changes, then produce a brief of what the diff actually does versus what the spec asked for. <spec> {{input}} </spec> Developer evidence (verification command + output…

    • evaluator developer:general fresh

      You are the independent evaluator, in a fresh session. Trust nothing you did not run yourself: the developer's evidence and the brief are leads, not proof. User spec: <spec> {{input}} </spec> Developer evidence (verific…

  4. 4 outcome Conditional
    • summary developer:brief fresh

      Read the user spec and the implementation in the current unstaged git changes, then produce a concise briefing of spec-versus-diff for the human reviewer. <spec> {{input}} </spec> Output only the briefing.

    • stalled developer:brief fresh

      The development loop ended WITHOUT evaluator approval — do not present this as success. Read the spec and the current unstaged changes, then report for a human decision: what was implemented and verified, and every gap …

Definition

# Title: Develop: Spec-Driven Development Feature Loop
#
# Public workflow: turn a feature spec into a finished, verified change through a
# developer/evaluator refine loop with a real build/test gate inside the loop.
# The evaluator trusts nothing it did not run: it re-runs the verification
# itself, runs the mapped tests against the pre-change code (each must fail
# there — fail-to-pass), scans the test diff for tampering, and checks the spec's
# Guardrails mechanically against the diff.
#
# Revert contract: the fail-to-pass check swaps changed source files back to
# HEAD in place, so the evaluator never uses git checkout/restore/reset/stash
# (the tree holds uncommitted work). It copies each file to a scratch directory
# first, restores from that copy, and compares sha256 hashes; a mismatch ends the
# loop with VERDICT: BLOCKED. The evaluator has no timeout and no retries on
# purpose: killing or re-running it mid-swap could leave old code behind.
#
# Tip: set `model` on the evaluator to a different provider than the developer
# — LLM judges favor output from their own model. Showcases the loop pattern.
# Public roles only.

name        = "develop"
description = "Spec-driven development loop for an existing feature spec: gathers context, then iterates a developer/evaluator loop whose independent evaluator re-runs the build/test gate, proves every requirement's test fails on the old code and passes on the new, and rejects tampered tests until it approves, then summarizes the change."

# ── 1. Spec → context ────────────────────────────────────────────────────────
[[steps]]
name    = "context"
role    = "developer:context"
session = "fresh"
retries = 1
prompt  = """
Take the user spec and gather the most important context to begin development.

<spec>
{{input}}
</spec>

Locate the exact files, functions, and line ranges to touch and the existing
patterns to reuse. Identify the project's verification command (test / build /
lint) so the developer can prove the change works. State what is out of scope.

Output only the refined task with its <context> pinpoints — no implementation plan.
"""

# ── 1b. Upstream research (reported issues) ──────────────────────────────────
[[steps]]
name    = "upstream"
role    = "assistant:researcher"
session = "fresh"
retries = 1
prompt  = """
The spec below may be a reported issue (bug report / feature request) against a
project with a public home. If so, locate the upstream issue, its linked
discussion, and any existing fix or merged change, and produce implementation
contract notes: the chosen approach; exact API names, signatures, parameter
names and call conventions; which layer owns the primitive; and EVERY file the
upstream change touches. Cite what you found. If the project is private or
nothing public exists, reply exactly: NO UPSTREAM FOUND.

<spec>
{{input}}
</spec>
"""

# ── 2. Developer/evaluator refine loop ───────────────────────────────────────
[[steps]]
name           = "development"
loop           = true
max_iterations = 3
exit_when      = { output = "evaluator", matches = '(?m)^VERDICT: (APPROVED|BLOCKED)' }

  [[steps.run]]
  name    = "developer"
  role    = "developer:general"
  session = "continue"
  retries = 1
  prompt  = """
We are working on the following spec:
<spec>
{{input}}
</spec>

Pinpoints and verification command from context:
<context>
{{context}}
</context>

Upstream contract notes — when present, mirror them exactly (names, signatures,
call conventions, owning layer, every touched surface):
<upstream>
{{upstream}}
</upstream>

Implement the change fully autonomously. Fix causes, not symptoms — no
workarounds, suppressed errors, or skipped tests unless the spec explicitly
sanctions one. Treat any Guardrails in the spec as hard constraints. Prove every
requirement with a test: when the spec numbers its requirements (FR-001…), each
FR and each Acceptance item maps to a test that exercises it. An independent
evaluator will run every mapped test against the pre-change code, where each
test for new or changed behavior must fail — so assert the behavior itself,
never the implementation's own output. Never skip, delete, or loosen a test to
get green. Then run the project's verification command (tests / build / lint /
typecheck) and iterate until it passes.

End your response with:
- a requirement map, one line per stated requirement: `FR-001 → <test name>`
  (or `manual: <check>` only where no command can prove it);
- the exact command you ran and its output as evidence the check passes.

Output only the work, the map, and that evidence — no preamble.
"""

  [[steps.run]]
  name    = "brief"
  role    = "developer:brief"
  session = "fresh"
  retries = 1
  prompt  = """
Read the original spec and the current unstaged git changes, then produce a
brief of what the diff actually does versus what the spec asked for.

<spec>
{{input}}
</spec>

Developer evidence (verification command + output):
<evidence>
{{developer}}
</evidence>

Output only the brief.
"""

  [[steps.run]]
  name    = "evaluator"
  role    = "developer:general"
  session = "fresh"
  prompt  = """
You are the independent evaluator, in a fresh session. Trust nothing you did not
run yourself: the developer's evidence and the brief are leads, not proof.

User spec:
<spec>
{{input}}
</spec>

Developer evidence (verification command + output):
<evidence>
{{developer}}
</evidence>

Independent brief of the diff:
<brief>
{{brief}}
</brief>

Run these checks in order, by requirement ID when the spec has IDs.

A. VERIFY — run the project's verification command yourself, in full. It must
   pass with no newly skipped or ignored tests. If it fails, report it and skip C.
B. MAP — every stated requirement and every Acceptance item (Scenario, Property,
   Check) maps to a test in the developer's map, and that test exists and
   exercises the stated behavior. `manual:` is acceptable only where no command
   can prove it.
C. FAIL-TO-PASS — prove the mapped tests have teeth against the pre-change code:
   1. Record `git status --porcelain` and the sha256 of every modified or added
      non-test file; copy each one to a scratch directory (`mktemp -d`).
   2. Swap in the pre-change code, leaving test files alone: overwrite each
      modified file with `git show HEAD:<path>`, and move each added non-test
      file into the scratch directory. Never use git checkout, restore, reset, or
      stash.
   3. Run only the mapped tests. Each test for new or changed behavior must fail
      — an assertion failure, or a compile error because the behavior is missing.
      Each test for behavior the spec preserves must still pass. Name every test
      that passes on the old code: it proves nothing.
   4. Restore every file from the scratch copy, then confirm the sha256 values
      and `git status --porcelain` equal step 1. If they do not, restore again;
      if they still do not, stop with `REVERT-FAILED: <path>` and VERDICT: BLOCKED.
D. TAMPERING — read the test-file diff. Fail on deleted or renamed-away tests;
   new skip, ignore, or only markers; assertions removed or loosened; the unit
   under test mocked out; expected values copied from the implementation's own
   output; and any source branch that recognizes a test environment or specific
   test inputs.
E. GUARDRAILS — compare `git status --porcelain` and `git diff --stat` against
   the spec: no file outside its scope, no new dependency in a manifest or
   lockfile when the spec forbids one, no protected surface changed.

Flag ONLY failures of A–E. Do not request style changes, speculative robustness,
or criteria the spec never stated. List each failing check with specifics — this
goes directly to the developer with all original context. If A–E all pass,
approve. A revert failure is BLOCKED, never REVISE.

End with exactly one line: `VERDICT: APPROVED`, `VERDICT: REVISE`, or
`VERDICT: BLOCKED`. Nothing after it.
"""

# ── 3. Outcome — honest branch on the loop's final verdict ───────────────────
[[steps]]
name        = "outcome"
conditional = true
condition   = { output = "evaluator", matches = '(?m)^VERDICT: APPROVED' }
on_match    = ["summary"]
on_no_match = ["stalled"]

  [[steps.run]]
  name    = "summary"
  role    = "developer:brief"
  session = "fresh"
  prompt  = """
Read the user spec and the implementation in the current unstaged git changes,
then produce a concise briefing of spec-versus-diff for the human reviewer.

<spec>
{{input}}
</spec>

Output only the briefing.
"""

  [[steps.run]]
  name    = "stalled"
  role    = "developer:brief"
  session = "fresh"
  prompt  = """
The development loop ended WITHOUT evaluator approval — do not present this as
success. Read the spec and the current unstaged changes, then report for a human
decision: what was implemented and verified, and every gap the evaluator still
flags.

<spec>
{{input}}
</spec>

<last_evaluation>
{{evaluator}}
</last_evaluation>

If the last evaluation ends with `VERDICT: BLOCKED`, start with exactly:
`BLOCKED — source files may not match the developer's last state; check git status before anything else.`
Otherwise start with exactly: `DID NOT CONVERGE — human review required.`
"""