PlanForge — Speedrift-Native Planning
Turns a problem into a Workgraph task graph ready for Speedrift execution.
Use this as the planning entry point. planforge owns discovery, model-mediated planning, critic review, spec anchoring, Speedrift module selection, model assignment, and graph seeding. After the graph exists, hand off to speedrift for execution, drift checks, fix loops, and ongoing task work.
V2 Architecture:
- Planner persona: Loads
prompts/planforge-v2-persona.mdand decides the plan semantically. - Schema contract: Emits
schemas/planforge-plan-v2.schema.json; code validates shape, not meaning. - Critic pass: Independent review for missing UX/integration/dead-code/upstream/model-route/fix-loop coverage.
- Spec: Lightweight drift anchor written from the accepted plan. Not a deliverable — exists so
specdrifthas something to measure against. - Output: Seeded Workgraph with
wg-contractblocks, Speedrift lane fences, cheapest-sufficient model route assignments, tests, evals, and fix-loop policy.
Announce at start: "I'm using PlanForge V2 to compile the goal into a model-mediated Speedrift Workgraph."
Invariants
- Model judgment owns semantic decisions: module choice, cheapest-sufficient model assignment, risk, test posture, UX relevance, dead-code relevance, and replan triggers.
- Code owns evidence gathering, schema validation, tool execution, policy gates, budgets, persistence, and audit.
- Do not hardcode provider defaults, model IDs, API URLs, or credential env vars. Use central route names; default execution route is Pi (a multi-model harness — each Pi-routed node also names its model as a provider/id pattern
pi -p --modelresolves). Codex/Codexd and Claude are explicit opt-ins, never hidden defaults. - Ask only blocking questions. Otherwise recommend defaults, state assumptions, and proceed.
- Plan artifacts are written to
.workgraph/planforge/<session>/. - Spec is written AFTER the plan has converged. It reflects what was decided, not what was hoped.
- The task graph is the deliverable. The spec is the drift anchor.
- Human gates are for destructive actions, production-like changes, material cost, model-route policy violations, and genuinely ambiguous end states.
V2 Reference Files
- Persona prompt:
prompts/planforge-v2-persona.md - Plan schema:
schemas/planforge-plan-v2.schema.json - Operating flow:
references/planforge-v2-flow.md - Runner/materializer:
scripts/planforge_v2.py
Read those files before running PlanForge V2. Keep the old phase-debate protocol below as a legacy/manual fallback for situations where the user explicitly wants multi-agent debate before graph creation.
V2 Quick Start
Use the runner unless you are manually prototyping the flow:
PLANFORGE_V2=<workspace-root>/claude-agent-toolkit/skills/planforge/scripts/planforge_v2.py
"$PLANFORGE_V2" run \
--repo "$PWD" \
--goal "<goal>" \
--planner-command "$PLANFORGE_PLANNER_CMD" \
--critic-command "$PLANFORGE_CRITIC_CMD" \
--materialize
For dry-run materialization from an existing plan:
"$PLANFORGE_V2" materialize \
--repo "$PWD" \
--plan .workgraph/planforge/<session>/plan.final.json
Use --apply only when ready to run wg add commands.
Manual setup:
SESSION=$(date +%Y%m%d-%H%M%S)
mkdir -p .workgraph/planforge/$SESSION
echo $SESSION > .workgraph/planforge/current-session
wg init 2>/dev/null || true
Collect evidence:
git status --short
tmux-monitor status --all 2>/dev/null || true
find .. -maxdepth 2 -name AGENTS.md -o -name CLAUDE.md -o -name README.md -o -name NORTH_STAR.md
wg status 2>/dev/null || true
Planner pass:
- Load
prompts/planforge-v2-persona.md. - Provide the user goal, repo evidence, Workgraph state, Speedrift module inventory, model-route evidence, and autonomy policy.
- Require output matching
schemas/planforge-plan-v2.schema.json. - Persist the candidate plan to
.workgraph/planforge/$SESSION/plan.candidate.json. - Validate schema. If invalid, ask the model to repair. Do not rewrite semantic content in code.
Critic pass:
- Ask an independent critic to review the candidate plan for missing integration tests, UX evals, drift gates, dead-code cleanup, upstream-pin checks, model-route policy violations, unclear end state, overly broad tasks, and missing fix loops.
- Persist critic output to
.workgraph/planforge/$SESSION/critic.json. - Ask the planner to repair the plan using critic findings.
- Persist final output to
.workgraph/planforge/$SESSION/plan.final.json.
Materialize:
- Write a lightweight spec anchor from the final plan.
- Create the root Workgraph task.
- Create leaf tasks with
wg-contractblocks, Speedrift fences, dependencies, model-fit routing, verification, and acceptance criteria. - Add drift and fix-loop tasks as first-class graph nodes.
- Arm
speedriftdonly when execution is authorized.
V2 Workgraph Node Pattern
wg add --id "<node-id>" "<title>" \
--model "<selected-route>" \
--description "
\`\`\`wg-contract
schema = 1
mode = "core"
objective = "<node title>"
touch = ["<files or directories>"]
acceptance = ["<observable acceptance criterion>"]
verify = ["<focused command>"]
model_role = "<semantic role>"
model_route = "<central-registry-route>"
model_tier = "<local|cheap|standard|premium>"
model_fit = "risk=<risk>, complexity=<blast_radius>, context=<context_load>, verification=<verification_strength>"
model_escalation_route = "<stronger-route>"
handoff_detail = "high"
small_model_ready = "yes"
\`\`\`
\`\`\`specdrift
schema = 1
spec = ["<spec path>"]
check = "does this task remain consistent with the end-state contract?"
\`\`\`
\`\`\`speedrift
modules = ["coredrift", "<selected lane>"]
pre_task = "./.workgraph/drifts check --task <task_id> --write-log --create-followups"
post_task = "./.workgraph/drifts check --task <task_id> --write-log --create-followups"
\`\`\`
\`\`\`agencydrift
profile = "<agency profile>"
preferred_runtime = "agency"
fallback_runtime = "codexd"
\`\`\`
<task description and acceptance criteria>
" --after <dependencies>
Legacy Phase-Debate Protocol
Use this only when the user explicitly wants the older gated debate flow.
Step 1: Setup
SESSION=$(date +%Y%m%d-%H%M%S)
mkdir -p .workgraph/planforge/$SESSION
echo $SESSION > .workgraph/planforge/current-session
Bootstrap workgraph if not already running:
wg init 2>/dev/null || true
PlanForge expects the repo's Workgraph coordinator or speedriftd supervisor to already be active before Phase 1 debate tasks are dispatched. If wg add warns that no service is running, bring the repo under supervision before continuing.
Step 2: Discovery Conversation (Orchestrator-led)
Run exactly 5 turns with the user. One question per turn. Document responses.
Turn 1 — Problem: "What are we trying to solve? Give me the raw version — not polished."
Turn 2 — Stakes: "Who hits this problem daily, and what does it cost them when nothing changes?"
Turn 3 — Prior attempts: "What's been tried before, and what specifically didn't work?"
Turn 4 — Constraints: "What are the hard constraints — tech, time, team, YAGNI? What are we explicitly NOT doing?"
Turn 5 — Success: "What does done look like? Specific, observable, measurable."
Write discovery output:
cat > .workgraph/planforge/$SESSION/discovery.json << 'EOF'
{
"problem": "<2-3 sentence synthesis>",
"stakeholders": "<who and how affected>",
"prior_attempts": "<what failed and why>",
"constraints": ["<constraint 1>", "<constraint 2>"],
"out_of_scope": ["<explicit exclusion>"],
"success_criteria": ["<measurable outcome>"]
}
EOF
Step 3: Dispatch Phase 1 Debate Agents
Dispatch all three in parallel. Each gets the discovery JSON as context.
Synthesis agent — validates the problem statement:
DISCOVERY=$(cat .workgraph/planforge/$SESSION/discovery.json)
wg add "planforge-p1-synthesis: validate problem statement and surface gaps" \
--description "
You are the Synthesis agent in a PlanForge planning session.
Your job: Read the discovery context and validate whether the problem is well-defined.
Find gaps, ambiguities, and hidden assumptions. Do NOT propose solutions.
Discovery context:
$DISCOVERY
Output: Write JSON to .workgraph/planforge/$SESSION/p1-synthesis.json
Schema: {\"problem_valid\": bool, \"gaps\": [str], \"hidden_assumptions\": [str], \"refined_problem\": str, \"confidence\": 0-1}
" --no-place
Constraint/YAGNI agent — challenges scope:
wg add "planforge-p1-yagni: challenge scope and identify what NOT to build" \
--description "
You are the Constraints agent in a PlanForge planning session.
Your job: Given the discovery context, aggressively identify what should be cut, deferred, or explicitly excluded.
Apply YAGNI. Challenge every assumption. What is the minimum viable scope?
Discovery context:
$DISCOVERY
Output: Write JSON to .workgraph/planforge/$SESSION/p1-yagni.json
Schema: {\"cut_now\": [str], \"defer\": [str], \"watch\": [str], \"minimum_scope\": str, \"rationale\": str}
" --no-place
Analogy/Inversion agent — finds non-obvious angles:
wg add "planforge-p1-analogy: find parallel problems and invert assumptions" \
--description "
You are the Analogy agent in a PlanForge planning session.
Your job: (1) Find 2-3 parallel problems from other domains that were solved well — what did those solutions have in common?
(2) Invert the problem: what would make this problem WORSE? What does that tell us about what matters?
Discovery context:
$DISCOVERY
Output: Write JSON to .workgraph/planforge/$SESSION/p1-analogy.json
Schema: {\"analogies\": [{\"domain\": str, \"solution\": str, \"transferable_insight\": str}], \"inversion\": str, \"key_insight\": str}
" --no-place
Wait for all three to complete:
wg watch --filter planforge-p1 --until-done
Step 4: Phase 1 Gate
Read all three outputs:
cat .workgraph/planforge/$SESSION/p1-synthesis.json
cat .workgraph/planforge/$SESSION/p1-yagni.json
cat .workgraph/planforge/$SESSION/p1-analogy.json
Synthesize and surface to the user:
- Where do agents agree? This is the solid ground.
- Where do they disagree? Surface the specific tension.
- What did the inversion reveal that wasn't in the original discovery?
Optional visualization — if the problem space has structural complexity worth showing (dependencies, stakeholder relationships, data flows), offer Jesse's visual companion here:
"The agents found [X]. Some of this is easier to show than describe — want me to diagram the problem space before we move to solution design?"
Confirm with the user: "Does this capture the problem correctly? Any corrections before we design a solution?"
Do not proceed to Phase 2 until confirmed.
Step 5: Dispatch Phase 2 Debate Agents
Embed Phase 1 synthesis in context for all agents. Dispatch in parallel.
P1_CONTEXT=$(cat .workgraph/planforge/$SESSION/p1-synthesis.json .workgraph/planforge/$SESSION/p1-yagni.json .workgraph/planforge/$SESSION/p1-analogy.json)
Ideation agent — proposes solution approaches:
wg add "planforge-p2-ideation: propose 2-3 solution approaches with tradeoffs" \
--description "
You are the Ideation agent in a PlanForge planning session.
Your job: Propose exactly 2-3 distinct solution approaches. Each must be a real option with genuine tradeoffs — not variations of the same idea.
For each: what is it, what does it do well, what does it sacrifice, and what is the implementation shape?
Context:
$DISCOVERY
Phase 1 analysis:
$P1_CONTEXT
Output: Write JSON to .workgraph/planforge/$SESSION/p2-ideation.json
Schema: {\"approaches\": [{\"name\": str, \"description\": str, \"strengths\": [str], \"weaknesses\": [str], \"implementation_shape\": str}], \"recommended\": str, \"recommendation_rationale\": str}
" --no-place
Technical agent — evaluates feasibility:
wg add "planforge-p2-technical: evaluate technical feasibility of each approach" \
--description "
You are the Technical agent in a PlanForge planning session.
Your job: Wait for p2-ideation.json to appear, then evaluate each proposed approach for technical feasibility.
Consider: complexity, risk, reversibility, dependencies, and fit with the existing system.
Read: .workgraph/planforge/$SESSION/p2-ideation.json when available.
Context:
$DISCOVERY
Phase 1 analysis:
$P1_CONTEXT
Output: Write JSON to .workgraph/planforge/$SESSION/p2-technical.json
Schema: {\"evaluations\": [{\"approach\": str, \"feasibility\": \"high|medium|low\", \"complexity\": \"low|medium|high\", \"risks\": [str], \"fit_score\": 0-10}], \"preferred\": str, \"rationale\": str}
" --blocked-by planforge-p2-ideation --no-place
Validation agent — challenges each approach:
wg add "planforge-p2-validation: identify failure modes and edge cases per approach" \
--description "
You are the Validation agent in a PlanForge planning session.
Your job: For each proposed solution approach, identify the realistic ways it fails. What are the edge cases? What assumptions does each approach make that might be wrong?
Be specific — \"it might not scale\" is not useful. \"It breaks when X because Y\" is.
Read: .workgraph/planforge/$SESSION/p2-ideation.json when available.
Context:
$DISCOVERY
Phase 1 analysis:
$P1_CONTEXT
Output: Write JSON to .workgraph/planforge/$SESSION/p2-validation.json
Schema: {\"challenges\": [{\"approach\": str, \"failure_modes\": [str], \"key_assumptions\": [str], \"mitigations\": [str]}], \"show_stoppers\": [str]}
" --blocked-by planforge-p2-ideation --no-place
Scoring agent — synthesizes and scores:
wg add "planforge-p2-scoring: score approaches and produce final recommendation" \
--description "
You are the Scoring agent in a PlanForge planning session.
Your job: Read all Phase 2 agent outputs and produce a final scored recommendation.
Score each approach across: problem fit, simplicity, technical risk, YAGNI alignment, reversibility.
Produce a clear recommendation with rationale.
Read:
- .workgraph/planforge/$SESSION/p2-ideation.json
- .workgraph/planforge/$SESSION/p2-technical.json
- .workgraph/planforge/$SESSION/p2-validation.json
Context:
$DISCOVERY
Phase 1 analysis:
$P1_CONTEXT
Output: Write JSON to .workgraph/planforge/$SESSION/p2-scoring.json
Schema: {\"scores\": [{\"approach\": str, \"problem_fit\": 0-10, \"simplicity\": 0-10, \"tech_risk\": 0-10, \"yagni\": 0-10, \"reversibility\": 0-10, \"total\": 0-50}], \"winner\": str, \"rationale\": str, \"dissenting_concerns\": [str]}
" --blocked-by planforge-p2-technical planforge-p2-validation --no-place
Wait:
wg watch --filter planforge-p2 --until-done
Step 6: Phase 2 Gate
Read all Phase 2 outputs. Synthesize for the user:
- Winner and score
- Dissenting concerns (don't hide them — surface them explicitly)
- Any show-stoppers from validation
Visualization — this is the right moment. Offer to show:
- The winning approach's architecture or workflow diagram
- The proposed task graph structure before it gets created
"Here's what the agents settled on: [winner] scored [X/50]. The main concern was [dissent]. Want me to diagram the solution architecture and task breakdown before we commit it to workgraph?"
Confirm with the user: "Does this solution direction feel right? Any adjustments before I write the spec and seed the graph?"
Step 7: Write Lightweight Spec (Drift Anchor)
This is not a human document. It exists so specdrift has something to measure implementation against.
SPEC_DATE=$(date +%Y-%m-%d)
SPEC_SLUG="<topic-slug>"
SPEC_PATH="docs/superpowers/specs/${SPEC_DATE}-${SPEC_SLUG}-spec.md"
mkdir -p docs/superpowers/specs
# <Topic> Spec — Drift Anchor
*Generated by PlanForge on $SPEC_DATE. Not a deliverable — specdrift reference only.*
## Problem
<refined_problem from p1-synthesis>
## Solution
<winner from p2-scoring, 2-3 sentences>
## Out of Scope
<cut_now and explicit exclusions from p1-yagni and discovery constraints>
## Success Criteria
<measurable outcomes from discovery>
## Key Constraints
<hard constraints from discovery>
## Dissenting Concerns
<dissenting_concerns from p2-scoring — recorded so specdrift can flag if implementation ignores them>
Step 8: Seed the wg Task Graph
Decompose the winning solution into leaf tasks. Each task must have:
- A
wg-contractblock (touch-set + verify command) - A
specdriftfence block referencing the spec path --blocked-bydependencies where sequencing matters
Pattern:
wg add "implement-<component>" \
--description "
\`\`\`wg-contract
schema = 1
mode = "core"
objective = "implement <component>"
touch = ["<files this task touches>"]
verify = ["<test command>"]
\`\`\`
\`\`\`specdrift
schema = 1
spec = ["$SPEC_PATH"]
check = "does this task's output remain consistent with the spec?"
\`\`\`
<task description — what to build and why, referencing spec section>
" --blocked-by <deps>
Root task first (captures the session and links to spec):
wg add "planforge-root: <topic>" \
--description "PlanForge session: $SESSION. Spec: $SPEC_PATH. Goal: <one sentence>."
Step 9: Arm for Execution
# Show the graph
wg viz
# Arm via speedriftd (do not use wg service start directly)
driftdriver --dir "$PWD" speedriftd status \
--set-mode supervise \
--lease-owner planforge \
--reason "planforge session $SESSION: <topic>"
Report to the user: task graph seeded, spec written to $SPEC_PATH, graph armed. Ready.
Quick Reference
| Phase | Who runs | What it produces |
|-------|----------|-----------------|
| Discovery | Orchestrator + the user | discovery.json |
| Phase 1 (parallel) | wg agents | problem validated, constraints, analogies |
| Phase 1 Gate | Orchestrator | the user confirms problem |
| Phase 2 (parallel) | wg agents | ideation, technical eval, validation, scoring |
| Phase 2 Gate | Orchestrator | the user confirms solution |
| Spec | Orchestrator | drift anchor .md |
| Task graph | Orchestrator | seeded wg graph with contracts |
Red Flags
Never:
- Skip a phase gate
- Proceed with unresolved show-stoppers from validation agent
- Write the spec before the user confirms the solution
- Use
wg service startto arm — always go throughspeedriftd - Let the debate agents talk to the user directly
Always:
- Surface dissenting concerns, not just the winner
- Record
out_of_scopeexplicitly in the spec (specdrift needs it) - Embed spec path in every task's specdrift fence