harness-plan — Epic Planning for the Harness Control Loop
Fills the gap between harness-init (environment setup) and harness-loop
(autonomous sprints). Runs once per epic. Re-runs continue the same
epic draft from wherever it was interrupted.
The skill orchestrates the Planner sub-agent through three artifacts:
product-spec.md— What / Why / Out of Scope / Constraints (interactive)roadmap.md— sprint decomposition withbundling: split|bundled- One tracker Issue per sprint (when
_config.yml.tracker != none)
After this skill finishes, the project is ready for /harness-loop.
Required Reading — Open BEFORE doing the step
Claude Code tends to skim SKILL.md. For each Planner dispatch below you MUST open and read the listed prompt template + reference file(s) before invoking the sub-agent. Planner is dispatched as fresh invocations per phase — never a single long session.
| Step | Planner phase | Required file(s) to open |
|---|---|---|
| Step 3.5 | Foundation readiness (no sub-agent) | references/foundation-sprint-guide.md, ../harness-init/references/scripts.md §foundation-readiness.sh |
| Step 4 | interview |
references/prompt-templates/planner-interview.md, references/product-spec-guide.md |
| Step 5 | roadmap |
references/prompt-templates/planner-roadmap.md, references/roadmap-guide.md (foundation-sprint-guide.md when sprint-0 is inserted) |
| Step 7 | contract-draft × N sprint (parallel-safe) |
references/prompt-templates/planner-contract.md, ../harness-init/references/rubric-presets.md (foundation-sprint-checklist.md for type: foundation sprint-0) |
| Step 8 | Tracker Issue creation | references/issue-create.md |
.ja.md variants exist for Japanese projects; pick language-matched pair.
Language Rules
Resolve narrative language: explicit override (in English, 日本語で) >
project mandate in CLAUDE.md / AGENTS.md > current user prompt >
fallback skill source language (English).
Never infer from machine text (git log, progress.md, JSON keys, state
enums, file paths, commands). Keep such tokens unchanged. AskUserQuestion
body uses resolved language; option labels/descriptions stay bilingual
(English / 日本語).
Reference files exist as <name>.md (English) and <name>.ja.md (Japanese).
Pick the pair matching the resolved language for narrative guidance; YAML
schemas and templates are language-agnostic.
Prerequisites
Before any generation step, check:
- Harness initialised —
.harness/_config.ymland.harness/templates/product-spec.mdmust exist. If not, instruct the user to run/harness-initfirst and stop. - Git repo —
git rev-parse --is-inside-work-treemust succeed. jqavailable —command -v jq. Required for_state.jsonreads/writes (all state IO uses jq for JSON parsing).- Tracker pre-flight — if
_config.yml.tracker == github, verifygh auth statusnow to fail fast. See issue-create.md §Pre-flight. - Fresh agent registry after
/harness-init— ifTask(subagent_type="generator"|"evaluator"|"planner")is missing or falls back to a general-purpose agent,/clearis insufficient. Fully exit Claude Code, relaunch the repo withclaude --resume, then retry/harness-plan.
If any check fails, stop with a clear error. Do not partially generate.
Boot Sequence
Always execute before any write:
git log --oneline -20tail -30 .harness/progress.md(if it exists)cat .harness/_state.json(if it exists)
If _state.json.phase ∈ {product-spec-draft, roadmap-draft, roadmap-approved, issues-pending}, the skill offers resume vs
restart via AskUserQuestion. harness-plan runs prior to
harness-loop so mode is not yet decided — the Boot Sequence here
always behaves interactively. If the user invoked with
--auto-approve-roadmap, resume is chosen automatically; otherwise the
user confirms.
Execution Flow (10 steps)
Step 1: Detect Existing Epic
if .harness/<any-epic>/product-spec.md exists:
AskUserQuestion:
question: "Existing epic(s) detected. What to do?" /
"既存の epic を検出しました。"
options:
- "Continue the most recent epic / 最新 epic を継続"
- "Start a new epic / 新規 epic を開始"
- "Cancel / キャンセル"
"Continue" picks the epic named in _state.json.current_epic, or the
most recently modified .harness/<epic>/ directory if state is silent.
"Start new" prompts for epic name (Step 2). "Cancel" exits cleanly.
With --auto-approve-roadmap, the skill always continues when state is
populated, else starts new with a derived epic name (kebab-case from
the first 3 non-stopword tokens of the user prompt).
Step 2: Epic Name
AskUserQuestion:
question: "Epic name (kebab-case)?" / "Epic 名(kebab-case)?"
options:
- "<suggested from prompt, e.g., auth-suite> (Recommended)"
- "Let me type it / 手入力"
Validation:
- Kebab-case regex
^[a-z][a-z0-9-]{2,40}$ - Not already present under
.harness/ - If invalid, re-ask once with the regex in the message
Create .harness/<epic>/ and switch _state.json.current_epic to this
name.
Step 3: Copy product-spec Template
Copy .harness/templates/product-spec.md →
.harness/<epic>/product-spec.md if the target does not exist. If it
exists from a previous run, keep it — Step 4 resumes in place.
Step 3.5: Foundation Readiness Check
Run .harness/scripts/foundation-readiness.sh --epic <epic> before any
Planner dispatch. It writes .harness/<epic>/foundation-readiness.md,
emits a JSON summary on stdout, and may set
_state.json.foundation_readiness / foundation_sprint_needed.
Use references/foundation-sprint-guide.md
§Foundation readiness check for the exact JSON schema, severity matrix,
RED-path AskUserQuestion options, --auto-approve-roadmap behavior,
and state-write timing. Re-runs and --replan use the same flow.
Step 4: Interactive product-spec Drafting (Planner phase=interview)
This is the only conversational Planner phase — a single long session dedicated to the interview. All subsequent phases (roadmap generation, contract drafting, ruling) are dispatched as separate fresh Planner invocations to avoid context bloat.
Invoke the Planner sub-agent with the
planner-interview
prompt template (substitute {{EPIC_NAME}}, {{USER_REQUEST}},
{{PROJECT_TYPE}}). Also reference
product-spec-guide.md for section
structure.
The Planner walks the five sections in order — Why, What, Out of Scope,
Constraints, Success Signals — asking section-specific
AskUserQuestion rounds and writing answers into the matching section
of .harness/<epic>/product-spec.md.
Compact resilience (per Planner role contract): the Planner appends
each user response to .harness/progress.md as it collects them, so
even if context compaction fires mid-interview, a resume can reconstruct
the conversation from progress.md tail + existing product-spec.md draft.
Key enforcement (from the guide):
- Reject "How" leakage (framework / library / schema picks) and redirect to Constraints only if externally mandated
- Bullet count target for What: 3–7
- Success Signals may be empty; mark
success_signals: unspecifiedin frontmatter if so
Set _state.json.phase = "product-spec-draft" at step start. Keep it at
"product-spec-draft" until the Planner declares the spec complete via
the cross-check checklist; the transition out happens when Step 5 begins
(phase is advanced to "roadmap-draft" there).
Before moving to Step 5, the Planner runs the cross-check checklist
from the guide. Any "no" answer re-opens the relevant section via
AskUserQuestion. If the skill was invoked with --auto-approve-roadmap
(interview was pre-filled or resumed without user intervention), emit a
TODO(product-spec): line to progress.md instead of re-opening — the
user must resolve before harness-loop starts.
Commit: git add .harness/<epic>/product-spec.md && git commit -m "harness-plan: product-spec for <epic>".
Step 5: Planner Generates roadmap.md (fresh Planner, phase=roadmap)
Invoke a new fresh Planner sub-agent (not a continuation of the
interview session from Step 4 — that session has already exited). Use
the planner-roadmap
prompt template (substitute {{EPIC_NAME}}).
Inputs (the fresh Planner reads from disk):
.harness/<epic>/product-spec.md(finalized in Step 4)- roadmap-guide.md — decomposition / bundling doctrine
Output: .harness/<epic>/roadmap.md with YAML frontmatter listing sprints
and bundling flags. See the guide §roadmap.md Output Format for the
canonical schema.
The Planner must:
- Emit
splitby default; bundle only with a writtenbundling_reasonciting one of the four coupling axes (schema, auth, UI, contract) - Enforce reciprocal
bundled_withreferences - Cap sprints at 6 per epic; if more, pause and advise the user to split
the epic. With
--auto-approve-roadmap, truncate with aTODO(epic-split)note inprogress.mdfor post-hoc resolution - Cap bundle size at 3 sprints
- For each sprint, decide
generator_backendper the rubric and AskUserQuestion flow in roadmap-guide.md §Backend Recommendation and planner-roadmap.md prompt template. The Planner asks the user viaAskUserQuestion(interactive mode only) per sprint — options are<rubric primary> (Recommended) + <_config.yml.generator_backend> (epic default) + remaining enum (deduplicated). Incontinuous/autonomous-ralph/scheduledmode, the rubric primary is auto-confirmed without prompting (Pre-flight Gates forbid AskUserQuestion). With--auto-approve-roadmap, backend is auto-confirmed regardless of mode (still respects the rubric). Bundle peers share the primary peer's choice — one question per bundle, not per peer. When_config.yml.sprint_level_generator_override == false(legacy compat), skip rubric + AskUserQuestion entirely and writegenerator_backend: nullfor every sprint
Set _state.json.phase = "roadmap-draft" at step start.
Step 6: Roadmap Approval
The roadmap approval gate is always interactive. The mode value
(interactive / continuous / autonomous-ralph / scheduled) is
selected at harness-loop startup, not at harness-init, so
harness-plan has no basis for implicit acceptance. The only
exception is explicit user override via the --auto-approve-roadmap
flag (see §Usage).
Default path (no flag):
AskUserQuestion:
question: "Roadmap: <N> sprints, <M> bundle groups. Approve?" /
"Roadmap: <N> sprints, <M> bundle。承認?"
(Show Sprint Summary table from roadmap.md as description)
options:
- "Approve / 承認"
- "Request changes / 変更を要求"
- "Cancel / キャンセル"
- Approve → proceed to Step 7
- Request changes → collect free-form change request via a follow-up
AskUserQuestion; Planner regenerates roadmap.md with the feedback. Loop at most 3 times — after that, abort toCancelwith a note inprogress.md - Cancel → write
progress.mdline, leave roadmap.md as draft, exit
With --auto-approve-roadmap flag: skip the prompt and proceed to
Step 7 directly. Append one progress line recording auto-approval
([<ts>] auto-approved via --auto-approve-roadmap). The user takes
responsibility for pre-reviewing roadmap.md before invoking this mode.
Set _state.json.phase = "roadmap-approved" on approval (either path).
Commit: git add .harness/<epic>/roadmap.md && git commit -m "harness-plan: roadmap for <epic>".
Step 7: Draft Sprint Contracts (fresh Planner × N, phase=contract-draft)
For each sprint in roadmap.md.sprints, dispatch one fresh Planner
sub-agent using the
planner-contract
prompt template. Substitute {{EPIC_NAME}}, {{SPRINT_NUMBER}},
{{SPRINT_FEATURE}}, {{SPRINT_BUNDLING}}, {{SPRINT_BUNDLED_WITH}},
{{SPRINT_GOAL}}, {{RUBRIC_PRESET}}.
Each invocation is independent — no shared context between sprints, each Planner reads only product-spec + roadmap + its own sprint metadata. This is the file-mediated peer-processes discipline the harness series follows throughout.
Parallel execution: Sprints are independent, so dispatch them in parallel if the Task tool supports it. For N sprints the total wall time approaches the slowest single contract-draft time rather than N×. If parallel dispatch fails, fall back to sequential — correctness is identical either way.
Preparation (before dispatching):
- Create directory
.harness/<epic>/sprints/sprint-<n>-<feature>/for each sprint - Copy
.harness/templates/shared_state.mdinto each sprint directory - Create empty
feedback/andevidence/subdirectories in each sprint directory
Each fresh Planner then writes contract.md into its own sprint
directory, following its role contract. Draft fields:
sprint,feature,bundling,bundled_with(from roadmap)goal,acceptance_scenarios(elaborated per sprint)rubricwith axes selected fromrubric-presets.mdbased on_config.yml.rubric_preset— butthresholdleft as?placeholdermax_iterationsleft as?placeholderstatus: pending-negotiation
The ? placeholders are filled by the Negotiation phase inside
harness-loop (Generator ⇄ Evaluator, with Planner ruling as
tiebreaker). harness-plan must NOT set threshold / max_iterations
values itself.
Step 8: Create Tracker Issues
Set _state.json.phase = "issues-pending" at step start so resume after
a mid-loop failure can locate the correct entry point. Dispatch on
_config.yml.tracker. Full detail in
issue-create.md:
github→gh issue createper sprint, with duplicate detection and epic-link formatting. On every successful create, append to_state.json.sprint_issues[<n>]atomically so resume can skip already-created sprintsgitlab→ record pending payloads to.harness/<epic>/pending-issues.md(an epic-level ledger file owned by harness-plan).shared_state.mdis sprint-scoped and does not exist yet at this phase — never write there. No CLI call in v1none→ skip; emit one progress line noting tracker-free mode
gh CLI absence: if tracker == github and gh is missing, abort
the skill. Do not silently fall back to gitlab / none — the user's
tracker choice is load-bearing for the audit trail.
On failure mid-loop, _state.json.phase stays at "issues-pending" and
partial sprint_issues is preserved. Resume re-enters Step 8 and the
duplicate-detection path in issue-create.md skips the already-created
sprints.
Step 9: Finalize Handoff Cursor in _state.json
Step 8 already transitioned phase to "ready-for-loop" and built up
sprint_issues incrementally. Step 9 finalizes the remaining cursor
fields that harness-loop reads on its Boot Sequence:
{
"current_epic": "<epic>",
"current_sprint": 1,
"phase": "ready-for-loop",
"iteration": 0,
"last_agent": "planner",
"next_action": "harness-loop:negotiate-sprint-1",
"completed": false,
"pending_human": false,
"aborted_reason": null
}
Preserve all other fields written by harness-init (max_iterations,
max_wall_time_sec, max_cost_usd, allowed_mcp_servers, etc.). The
mode field is not set here — it is written by harness-loop on
startup. Use a merge, not a replace, via jq '.foo = "bar"' on the
existing file.
Step 10: Summary Report
Emit to the user:
- Epic directory path:
.harness/<epic>/ - Product-spec path
- Roadmap path, with sprint count and bundle group summary
- Tracker issues created (count and URLs if GitHub)
- Recommended next action:
/harness-loopto start sprint 1
Also append one progress line:
[<ts>] harness-plan: epic=<name> sprints=<N> bundles=<M> tracker=<github|gitlab|none>
Error Handling
| Situation | Response |
|---|---|
.harness/_config.yml missing |
Error: "Run /harness-init first." |
jq not found |
Error: "Install jq — all harness tooling requires it." |
| Epic name collision | Re-ask by default; append -N suffix with --auto-approve-roadmap |
| Planner exceeds 6 sprints | Pause by default; truncate with TODO note with --auto-approve-roadmap |
| Bundle size > 3 | Hard-split by Planner; log decision to progress.md |
Reciprocal bundled_with mismatch |
Planner regenerates once; fail if still broken |
gh CLI missing when tracker=github |
Abort per issue-create.md. Do not fall back to gitlab / none |
| Roadmap approval cancelled | Leave draft roadmap.md, exit. Re-run continues |
| Write failure mid-flow | Partial state preserved; progress.md records failure line; resume-safe |
Usage
Read references/usage-and-approval.md
completely (.ja.md for Japanese) before parsing invocation flags. It defines
resume, replan, and the single-source semantics of --auto-approve-roadmap.
What harness-plan does NOT do
- Does not run any sprint — that is
harness-loop's job - Does not negotiate the sprint contract rubric — that happens inside
harness-loop's Negotiation phase - Does not create PRs — PRs are a
harness-loopoutput - Does not re-configure hooks or scripts — re-run
/harness-initfor that - Does not pick the Generator backend, evaluator tools, or hook level —
those are
_config.ymlvalues owned byharness-init
References
- product-spec-guide.md — section-by- section interview prompts, anti-patterns, cross-check list
- roadmap-guide.md — decomposition rules, bundling judgement, roadmap.md output schema
- issue-create.md — tracker dispatch, duplicate detection, epic link syntax
- prompt-templates/ — fresh-Planner
prompt files for
interview/roadmap/contract-draftphases (EN + JA) - ../harness-init/references/resilience-schema.md
—
_state.jsonschema this skill updates - ../harness-init/references/agent-templates/planner.md — Planner role contract (Boot Sequence, phase types, write permissions)