skills/plan-feature/SKILL.md
Create OpenSpec proposal with tiered execution (coordinated / local-parallel / sequential)
npx skillsauth add jankneumann/agentic-coding-tools plan-featureInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Create an OpenSpec proposal for a new feature. Automatically selects execution tier based on coordinator availability and feature complexity. Uses interactive discovery questions and two-gate approval to ensure the plan reflects user intent before detailed artifacts are generated.
$ARGUMENTS - Feature description (e.g., "add user authentication")
Optional flags:
--explore -- Deep-dive mode: more discovery questions (5-8 vs 2-5), more approaches (3-5 vs 2-3), web search for prior art when available--interview -- Confidence-gated discovery: replaces the fixed question budget with an adaptive loop that keeps asking (in batches of 2-4) until self-assessed confidence reaches ≥ 0.95 on a five-dimension rubric or the user asks to move on. Prioritizes latent intent ("what you actually want") over surface request ("what you think you should want"). Auto-enabled when $ARGUMENTS is short/vague (≤ 3 words or no verb)When this skill delegates context gathering or review work, treat the
provider-neutral dispatch adapter as the canonical cross-provider path. Claude
Code, Codex, and Gemini/Jules are first-class providers when configured; any
Claude harness Agent(...) usage is a provider-specific adapter internal or
example, with inline execution as the fallback.
Use OpenSpec-generated runtime assets first, then CLI fallback:
.claude/commands/opsx/*.md or .claude/skills/openspec-*/SKILL.md.codex/skills/openspec-*/SKILL.md.gemini/commands/opsx/*.toml or .gemini/skills/openspec-*/SKILL.mdopenspec CLI commandsThis skill uses AskUserQuestion to gather user input at discovery and approval gates. If AskUserQuestion is unavailable in the current runtime, present questions as a numbered list in regular output and instruct the user to respond inline.
Planning gates:
Run the coordinator detection script:
python3 "<skill-base-dir>/../coordination-bridge/scripts/check_coordinator.py" --json
Parse JSON output and set capability flags. Then select tier:
If COORDINATOR_AVAILABLE and CAN_DISCOVER and CAN_QUEUE_WORK and CAN_LOCK:
TIER = "coordinated"
Else if user invoked via "parallel plan" trigger OR feature touches 2+ architectural boundaries:
TIER = "local-parallel"
Else:
TIER = "sequential"
Parse optional flags from $ARGUMENTS:
EXPLORE_MODE=false
INTERVIEW_MODE=false
if [[ "$ARGUMENTS" == *"--explore"* ]]; then
EXPLORE_MODE=true
fi
if [[ "$ARGUMENTS" == *"--interview"* ]]; then
INTERVIEW_MODE=true
fi
# Auto-enable interview mode when the request is short/vague.
# Heuristic: ≤ 3 words remaining after stripping flags, OR no action verb.
# A short request without a verb ("role based access matrix") is just as
# vague as a single-word one — the user named a noun phrase but didn't say
# what to DO with it.
STRIPPED=$(echo "$ARGUMENTS" | sed -E 's/--(explore|interview)//g' | xargs)
WORD_COUNT=$(echo "$STRIPPED" | wc -w | tr -d ' ')
if echo "$STRIPPED" | grep -iqE '\b(add|create|build|make|implement|refactor|fix|update|remove|delete|change|migrate|extract|replace|rename|move|convert|improve|enhance|support|enable|disable|allow|prevent|expose|hide|introduce|ship|merge|split|consolidate|wire|validate|verify|check|test|document|explain|clarify|restructure|rewrite|cleanup|clean|audit|review|rebuild|resolve|investigate|explore|analyze|optimize|tune|polish|harden|stabilize|deprecate)\b'; then
HAS_VERB=true
else
HAS_VERB=false
fi
if [[ "$WORD_COUNT" -le 3 ]] || [[ "$HAS_VERB" == "false" ]]; then
INTERVIEW_MODE=true
fi
# Discovery question bounds
if [[ "$EXPLORE_MODE" == "true" ]]; then
MIN_QUESTIONS=5; MAX_QUESTIONS=8
MIN_APPROACHES=3; MAX_APPROACHES=5
else
MIN_QUESTIONS=2; MAX_QUESTIONS=5
MIN_APPROACHES=2; MAX_APPROACHES=3
fi
# Interview mode treats MAX_QUESTIONS as a soft ceiling, not a hard cap.
# Confidence threshold for exiting the discovery loop:
CONFIDENCE_THRESHOLD=0.95
Emit tier notification:
Tier: <tier> -- <rationale>
Mode: <standard | explore>[, interview]
If CAN_HANDOFF=true, read recent handoff context. If CAN_MEMORY=true, recall relevant memories.
The shared checkout is read-only -- never commit or modify files there. All planning work happens in a feature-level worktree.
# plan-feature always runs single-agent, so WORKTREE_BRANCH == FEATURE_BRANCH here.
eval "$(python3 "<skill-base-dir>/../worktree/scripts/worktree.py" setup "<change-id>")"
cd "$WORKTREE_PATH"
FEATURE_BRANCH="$WORKTREE_BRANCH"
git rev-parse --show-toplevel # Should match WORKTREE_PATH
git branch --show-current # Should match $FEATURE_BRANCH
If the worktree already exists (e.g., from a previous session), reuse it. All subsequent steps happen inside the worktree.
Operator branch override: When OPENSPEC_BRANCH_OVERRIDE is set (e.g. by the Claude cloud harness with claude/fix-branch-mismatch-9P9o1), worktree.py uses that branch instead of openspec/<change-id>. Downstream push/PR steps must reference $FEATURE_BRANCH rather than hardcoding the openspec prefix. If implement-feature later dispatches parallel work-package agents, they will each branch off $FEATURE_BRANCH with --<agent-id> suffixes (e.g. claude/fix-branch-mismatch-9P9o1--wp-backend) and merge back into $FEATURE_BRANCH at integration time.
Gather context from multiple sources concurrently using Task(Explore) agents.
Resolve the analyst archetype before dispatching:
from src.agents_config import load_archetypes_config, resolve_model
archetypes = load_archetypes_config()
analyst = archetypes.get("analyst")
analyst_model = resolve_model(analyst, {}) if analyst else "sonnet"
Task(subagent_type="Explore", model=analyst_model, prompt="Read openspec/project.md and summarize the project purpose, tech stack, and conventions", run_in_background=true)
Task(subagent_type="Explore", model=analyst_model, prompt="Run 'openspec list --specs' and summarize existing specifications", run_in_background=true)
Task(subagent_type="Explore", model=analyst_model, prompt="Run 'openspec list' and identify in-progress changes that might conflict with: $ARGUMENTS", run_in_background=true)
Task(subagent_type="Explore", model=analyst_model, prompt="Search the codebase for existing implementations related to: $ARGUMENTS", run_in_background=true)
Task(subagent_type="Explore", model=analyst_model, prompt="Read docs/architecture-analysis/architecture.summary.json and parallel_zones.json for component inventory and safe parallel zones", run_in_background=true)
Wait for all results and synthesize into unified context summary.
Before creating artifacts, ensure architecture artifacts are current:
if [ ! -f docs/architecture-analysis/architecture.summary.json ] || \
[ "$(git log -1 --format=%ct main)" -gt "$(stat -f %m docs/architecture-analysis/architecture.summary.json 2>/dev/null || echo 0)" ]; then
make architecture
fi
This step ensures the user has visibility into what was discovered and shapes the plan before any artifacts are generated.
Format the Explore agent results from Step 2 as a structured summary and present it to the user via regular message output:
## What I Found
### Related Specs
- <spec-name>: <one-line summary of relevance>
### Related Code
- <file-path>: <what it does and how it relates to this feature>
### Potential Conflicts
- <in-progress change-id>: <what it touches that overlaps with this feature>
(or "None found" if no conflicts)
### Architectural Constraints
- <constraint from architecture analysis or parallel_zones.json>
### Prior Art (--explore mode only)
- <pattern, library, or approach found via web search>
(Skip this section if EXPLORE_MODE=false or web search is unavailable)
This gives the user the same information you have, enabling better answers to the questions that follow.
Ask clarifying questions using the AskUserQuestion tool. Draw from these six categories, selecting the most relevant ones based on the discovered context:
Motivation / latent intent -- Use AskUserQuestion without preset options (open-ended). Ask FIRST when INTERVIEW_MODE=true.
Goal: separate the user's surface request from the underlying need. A user who asks for "a microservice" may actually want "deployment isolation" -- surfacing that opens better approaches.
Examples: "What made you reach for this idea today -- what recent moment or pain triggered it?" / "If this feature existed and worked perfectly, what would you stop having to do?" / "What's the closest thing to this that already exists, and why isn't it enough?"
Scope boundaries -- Use AskUserQuestion with preset options. Examples: "Should <related capability X> be included in scope?" Options: "Yes, include it" / "No, out of scope" / "Defer to a follow-up proposal"
Trade-off preferences -- Use AskUserQuestion with preset options presenting 2-3 positions. Examples: "I see a trade-off between <simplicity vs flexibility / speed vs correctness / etc>. Which direction?" Options describe each position.
Constraint discovery -- Use AskUserQuestion without preset options (open-ended). Examples: "Are there timeline, compatibility, or performance constraints I should know about?" / "Are there any rejected approaches or past attempts I should avoid?"
Existing decisions -- Use AskUserQuestion with preset options when specific decisions are discoverable from context. Examples: "The codebase currently uses <pattern X> for similar features. Should we follow this pattern or introduce a new one?" Options: "Follow existing pattern" / "New approach because <reason>"
Success criteria -- Use AskUserQuestion without preset options (open-ended). Examples: "What does success look like for this feature?" / "How will you know this feature is working correctly?"
Rules for question generation:
$ARGUMENTS (but in INTERVIEW_MODE, never skip category 1 -- latent intent)EXPLORE_MODE=true, add prior-art questions: "I found <pattern/library X> is commonly used for this. Should we adopt it, adapt it, or build custom?"Ask MIN_QUESTIONS to MAX_QUESTIONS clarifying questions in one or two batches, then proceed to Step 4.
STOP -- Wait for the user to answer all discovery questions before proceeding to Step 4. Do NOT generate any artifacts until all answers are received.
Replaces the fixed question budget with an adaptive loop. Keeps asking -- in batches of 2-4 -- until self-assessed confidence reaches CONFIDENCE_THRESHOLD (default 0.95) on all five dimensions of the rubric, or the user explicitly asks to move on.
Confidence rubric. After each answer batch, score each dimension from 0.0 to 1.0:
| Dimension | What it means | Raises score | Lowers score |
|-----------|---------------|--------------|--------------|
| problem_clarity | I understand the real problem, not just the stated request | User articulated a concrete pain and "what they'd stop doing" | Request is solution-shaped with no underlying problem named |
| success_criteria | I know how we'll verify this worked | User gave measurable/observable outcomes | Only vague adjectives ("better", "faster") |
| scope_edges | I know what's in vs. out | User confirmed or excluded related capabilities | Adjacent capabilities remain ambiguous |
| hidden_constraints | I know the non-obvious restrictions | User surfaced timeline, compat, rejected approaches | User gave none and my probing didn't surface any |
| why_now | I understand the triggering context | User named a recent event or deadline | "It just seemed useful" |
Loop:
questions_asked = 0
batch = generate_opening_batch(category=1 first, then 2-4 relevant categories)
while True:
ask(batch) via AskUserQuestion
wait for answers
questions_asked += len(batch)
scores = self_score_confidence(answers_so_far, rubric)
min_score = min(scores.values())
log("Confidence: " + format_scores(scores))
# Exit conditions (checked in order)
if min_score >= CONFIDENCE_THRESHOLD and questions_asked >= MIN_QUESTIONS:
break
if user_said_move_on(answers):
break
if questions_asked >= MAX_QUESTIONS:
# Soft ceiling -- surface confidence and ask permission to continue
ask_user_whether_to_continue(scores)
if user declines: break
# else: continue loop
# Contradiction check: compare new answers against Step 3a discoveries
# and prior answers. A contradiction always spawns a follow-up.
contradictions = detect_contradictions(answers, context_summary)
# Generate next batch targeted at the weakest dimension(s) or contradictions.
batch = generate_followup_batch(
weakest_dimensions=[d for d,s in scores.items() if s < CONFIDENCE_THRESHOLD],
contradictions=contradictions,
size=min(4, max(2, num_remaining_gaps)),
)
Surfacing contradictions. When a user answer conflicts with a Step 3a discovery (e.g., user says "we have no auth today" but the explore agent found an existing auth spec), do NOT paper over it. The next batch includes a direct question: "I found <discovery> which seems to conflict with your answer that <answer>. Can you reconcile these for me?"
Confidence report. When the loop exits, print a one-line summary: Interview complete: <N> questions asked, confidence {problem: 0.95, success: 0.97, scope: 0.92, constraints: 1.0, why_now: 0.95}. If any dimension is below threshold at exit (because the user moved on), flag it as an explicit assumption in Step 4's proposal.
STOP -- Do NOT generate any artifacts until the loop exits.
Preferred path: Use runtime-native fast-forward/new workflow.
CLI fallback path:
openspec new change "<change-id>"
openspec instructions proposal --change "<change-id>"
Generate ONLY proposal.md at this stage. Incorporate user answers from Step 3b into the Why and What Changes sections.
Mandatory: Approaches Considered section. Generate MIN_APPROACHES to MAX_APPROACHES genuinely distinct approaches. For each approach, include:
Mark one approach as Recommended with a rationale that references specific pros/cons.
If EXPLORE_MODE=true, reference prior art discoveries in approach descriptions where relevant.
Expected artifact (this step only):
openspec/changes/<change-id>/proposal.mdPresent proposal.md to the user and ask them to select an approach.
Latent-intent check (INTERVIEW_MODE=true only). Before presenting the approach-selection question, surface the trade-off explicitly against the motivation captured in Step 3b category 1:
"Approach N optimizes for
<X>and accepts<trade-off Y>. Earlier you said the underlying need was<latent goal Z>. Does this approach actually get you Z, or are we optimizing for the surface request instead?"
Ask this as a short open-ended AskUserQuestion before the selection question. If the user's answer reveals a mismatch, loop back to Step 4 with the corrected objective rather than letting them pick an approach that misses their real goal.
Use AskUserQuestion with these options:
STOP -- Wait for the user to select an approach.
After selection:
proposal.md with a ### Selected Approach subsection recording the choice and any modifications the user requested. Demote unselected approaches to brief entries under the Recommended subsection.Use the table below when generating tasks.md (Step 6) and work-packages.yaml (Step 8). Sizing is about agent attention budget, not raw effort — a task should fit inside one focused implementation session.
| Size | Time budget | Typical scope | Action | |---|---|---|---| | XS | ≤ 30 min | One-line edit, doc tweak, single test | Ship as-is. | | S | 30 min – 2 hr | Single function/method change, narrow refactor | Ship as-is. | | M | 2 hr – 1 day | Multi-file change in one module, new test suite | Ship as-is; checkpoint after. | | L | 1 – 3 days | Cross-module change, new component, schema migration | CONSIDER SPLITTING. Try to decompose into 2–3 M-sized tasks. If splitting doesn't reduce risk, keep but flag. | | XL | > 3 days | Cross-system, multiple subsystems, new bounded context | MUST SPLIT. Do not generate a tasks.md entry at XL — go back to Step 6 and decompose. |
If a task title contains the word "and" OR describes two distinct outcomes, split it. The conjunction is almost always a sign that two tasks have been collapsed into one.
| Original title | Decision | Result | |---|---|---| | "Add caching and metrics" | Split — two outcomes | "Add caching" + "Add metrics" | | "Wire EventBus and retire polling" | Split — two outcomes | "Wire EventBus" + "Retire polling fallback" | | "Refactor user auth" | Keep — single outcome | (no change) | | "Investigate flaky test and propose fix" | Split — investigation and fix have different completion criteria | "Investigate flaky test" + "Apply fix from investigation" | | "Stand up Postgres and Redis" | Split — two independent dependencies | "Stand up Postgres" + "Stand up Redis" |
The heuristic is mechanical on purpose: it catches almost all hidden multi-tasks without requiring deep context.
Every 2–3 tasks, the implementing agent should pause for a self-check:
git diff main...HEAD) and confirm every change maps to a completed task.write_allow.tasks.md checkboxes for completed tasks (per /implement-feature Step 4 discipline).This cadence is recorded in tasks.md as explicit - [ ] Checkpoint: run tests, review diff, verify scope markers between groups of 2–3 implementation tasks. The checkpoint isn't decorative — it's the integration point where Rules 0.5 (scope) and 2 (compilable) get verified.
Now that the direction is confirmed, generate the remaining planning artifacts.
CLI fallback path:
openspec instructions specs --change "<change-id>"
openspec instructions tasks --change "<change-id>"
openspec instructions design --change "<change-id>" # When complexity warrants it
Critical: The selected approach from Gate 1 MUST drive all artifact content. Tasks must implement the selected approach specifically, not a generic solution. Specs must reflect the chosen approach's behavior.
Spec format — strict delta headers: The openspec validate CI check will reject specs that don't follow this exact format. Every spec file MUST use:
## ADDED Requirements (or MODIFIED/REMOVED/RENAMED) as the top-level section — NOT ## Requirements### Requirement: <Name> for each requirement block — NOT ### REQ-ID: or other heading styles#### Scenario: <name> with WHEN/THEN/AND structure under each requirement — at least one per requirementSHALL or MUST language for normative statementsVerify after generating: openspec validate <change-id>. If it fails, fix the spec before proceeding.
Task ordering — TDD test-first: Within each phase of tasks.md, list test
tasks before the implementation tasks they verify. Each implementation task
should declare a dependency on its corresponding test task. This ensures
/implement-feature writes tests (RED) before writing code to make them pass
(GREEN).
Test tasks must reference the artifacts they validate:
agent-coordinator.3) it encodes. Every SHALL/MUST scenario in specs must be covered by at least one test task.design.md exists, test tasks reference the decision IDs (e.g., D3) they verify. This catches cases where the implementation accidentally uses an approach that was explicitly rejected.Example:
- [ ] 1.1 Write tests for EventBusService — callback dispatch, reconnection
**Spec scenarios**: agent-coordinator.1 (event delivery), agent-coordinator.2 (reconnection)
**Contracts**: contracts/events/coordinator.schema.json
**Design decisions**: D3 (pg_notify over polling)
**Dependencies**: None
- [ ] 1.2 Create event_bus.py — EventBusService with on_event() registration
**Dependencies**: 1.1
Expected artifacts:
openspec/changes/<change-id>/specs/<capability>/spec.mdopenspec/changes/<change-id>/tasks.mdopenspec/changes/<change-id>/design.mdFor sequential-tier plans, include only contract sub-types applicable to the feature:
If no contract sub-types are applicable (e.g., pure documentation or skill-definition changes), create contracts/README.md with a stub documenting which sub-types were evaluated and why none apply. Consuming skills treat a contracts/ directory containing only README.md as "no contracts applicable".
Produce machine-readable interface definitions in contracts/. Contracts become the coordination boundary between parallel agents.
For API features, generate from openspec/schemas/feature-workflow/templates/openapi-stub.yaml:
contracts/openapi/v1.yaml # OpenAPI 3.1.0 spec with paths, schemas, examples
Requirements: every endpoint has request/response schemas with example fields, discriminator fields for polymorphic responses, error response schemas following RFC 7807.
contracts/db/schema.sql # CREATE TABLE / ALTER TABLE statements
contracts/db/seed.sql # Test fixture data
contracts/events/user.created.schema.json # JSON Schema for event payload
contracts/generated/models.py # Pydantic models from OpenAPI schemas
contracts/generated/types.ts # TypeScript interfaces from OpenAPI schemas
For sequential-tier plans, generate a single wp-main package encompassing the full feature scope:
packages:
- id: wp-main
name: "<feature-name> — full scope"
description: "<feature description>"
tasks: [all task IDs from tasks.md]
priority: 1
dependencies: []
scope:
write_allow: ["**"]
read_allow: ["**"]
verification: tier_b
This provides a uniform artifact format across all tiers. The wp-main package can later be split into parallel packages if the feature is upgraded to local-parallel tier.
For local-parallel and coordinated tiers, decompose tasks into agent-scoped work packages as described below.
Decompose tasks into agent-scoped work packages in work-packages.yaml. Follow the schema at openspec/schemas/work-packages.schema.json.
Group tasks by architectural boundary:
wp-contracts -- Generate/validate contracts (always first, priority 1)wp-<backend-module> -- Backend implementation per bounded contextwp-<frontend-module> -- Frontend implementation per component groupwp-integration -- Merge worktrees and run full test suite (always last)For each package, declare explicit file scope:
scope:
write_allow:
- "src/api/**"
read_allow:
- "src/**"
- "contracts/**"
deny:
- "src/frontend/**"
Rule: Parallel packages MUST have non-overlapping write_allow scopes.
locks:
files:
- "src/api/users.py"
keys:
- "api:GET /v1/users"
- "db:schema:users"
- "event:user.created"
ttl_minutes: 120
reason: "Backend API implementation"
Follow canonicalization rules from docs/lock-key-namespaces.md.
wp-contracts has no dependencies (root)wp-contractswp-integration depends on all implementation packagesAssign verification tier per package: Tier A (full), Tier B (CI), Tier C (static).
All tiers:
openspec validate <change-id> --strict
Local-parallel+ tiers (additionally):
skills/.venv/bin/python "<skill-base-dir>/../validate-packages/scripts/validate_work_packages.py" \
openspec/changes/<change-id>/work-packages.yaml
skills/.venv/bin/python "<skill-base-dir>/../refresh-architecture/scripts/parallel_zones.py" \
--validate-packages openspec/changes/<change-id>/work-packages.yaml --json
Fix any validation errors before proceeding.
Skip unless TIER is "coordinated" and CAN_LOCK=true.
Pre-register resource claims with the coordinator:
For each package in work-packages.yaml:
For each lock key in package.locks.keys:
acquire_lock(file_path=key, reason="planned: <feature-id>/<package-id>", ttl_minutes=0)
Use ttl_minutes=0 for planning claims -- they signal intent without expiring.
git add openspec/changes/<change-id>/
git commit -m "plan: <change-id> -- proposal, design, specs, tasks, contracts, work-packages"
# Push to the branch resolved by worktree.py setup (honors OPENSPEC_BRANCH_OVERRIDE)
git push -u origin "$FEATURE_BRANCH"
python3 "<skill-base-dir>/../worktree/scripts/worktree.py" pin "<change-id>"
Construct a PhaseRecord for the Plan phase and call write_both(). This persists the session-log markdown AND the coordinator handoff from a single in-memory record, so the structured fields (Decisions, Alternatives, Trade-offs, Open Questions) flow into both the human-readable log and the next phase's incoming handoff.
Capture from this planning session:
capability="<kebab-case>" so the per-capability decision index picks them up.proposal.md, design.md, etc.).Persist via PhaseRecord.write_both():
This step MUST run BEFORE the git add in Step 11 so the session-log entry is included in that commit. If you already committed in Step 11, amend with git add openspec/changes/<change-id>/ && git commit --amend --no-edit and re-push.
python3 - <<'EOF'
import sys
sys.path.insert(0, "skills/session-log/scripts")
from phase_record import PhaseRecord, Decision, Alternative, TradeOff, FileRef
record = PhaseRecord(
change_id="<change-id>",
phase_name="Plan",
agent_type="<agent-type>",
summary="<2-3 sentences on planning goal + decisions>",
decisions=[
Decision(title="<title>", rationale="<rationale>", capability="<kebab-case-capability>"),
],
alternatives=[Alternative(alternative="<approach>", reason="<rejection reason>")],
trade_offs=[TradeOff(accepted="<X>", over="<Y>", reason="<reason>")],
open_questions=["<question>"],
next_steps=["<what implement-feature should tackle first>"],
relevant_files=[FileRef(path="openspec/changes/<change-id>/proposal.md", description="approved proposal")],
)
result = record.write_both()
print(f"markdown_path={result.markdown_path}")
print(f"sanitized={result.sanitized}")
print(f"handoff_id={result.handoff_id or '(local fallback)'}")
print(f"handoff_local_path={result.handoff_local_path}")
for w in result.warnings:
print(f"WARN: {w}", file=sys.stderr)
EOF
write_both() runs three best-effort steps internally:
openspec/changes/<change-id>/session-log.mdsanitize_session_log.pytry_handoff_write — falls back to openspec/changes/<change-id>/handoffs/plan-<N>.json on failureEach step logs a warning if it fails but does not raise, so the workflow continues even if the coordinator is unreachable. Verify the rendered session-log.md: all populated sections present, no incorrect [REDACTED:*] markers, markdown intact. If over-redacted, fix the offending content in your PhaseRecord construction and re-run — write_both() appends a new entry rather than rewriting in place.
Present the complete plan to the user:
proposal.md -- What, why, and selected approachdesign.md -- How (if applicable)tasks.md -- Implementation planAll tiers (including sequential):
contracts/ -- Machine-readable interfaces (or README stub if no interfaces apply)work-packages.yaml -- Execution plan (single wp-main for sequential, DAG for parallel)Highlight any assumptions made during artifact generation that were not explicitly confirmed by the user.
Use AskUserQuestion to request final approval with these options:
On Approve -- seed coordinator issues (D3):
After the user selects "Approve -- proceed to implementation", invoke the
seeder to create coordinator issues for every hand-authored task in tasks.md:
skills/.venv/bin/python skills/coordinator-task-status-renderer/scripts/seed_tasks_from_md.py <change-id>
The seeder is idempotent on the (change:<id>, task:<key>) label pair
(per D3 / D7): re-runs after partial seeding only POST new tasks and skip any
that already carry the matching task:<key> label. If the coordinator is
unreachable, the seeder logs a warning and exits 0 — Gate 2 still completes,
and /implement-feature retries seeding on its first invocation per D11.
If CAN_HANDOFF=true, write completion handoff.
STOP HERE -- Wait for approval before proceeding to implementation.
openspec/changes/<change-id>/proposal.mdopenspec/changes/<change-id>/design.mdopenspec/changes/<change-id>/tasks.mdopenspec/changes/<change-id>/specs/**/spec.mdopenspec/changes/<change-id>/contracts/openspec/changes/<change-id>/work-packages.yamlWhen /implement-feature dispatches work packages, each agent receives only the context it needs:
| Package Type | Context Slice |
|-------------|---------------|
| wp-contracts | proposal.md + spec deltas + contract templates |
| Backend packages | design.md (backend section) + contracts/openapi/ + package scope |
| Frontend packages | design.md (frontend section) + contracts/generated/types.ts + package scope |
| wp-integration | Full work-packages.yaml + all contract artifacts |
| wp-main (sequential) | proposal.md + design.md (if exists) + contracts/ + full task list |
After approval:
/implement-feature <change-id>
| Rationalization | Why it's wrong |
|---|---|
| "I know what the user wants — I can skip discovery" | The fastest way to redo a plan is to skip the gates that prevent rework. Steps 3 and 5 are cheap insurance against generating tasks.md against the wrong target. |
| "An L-sized task is fine — splitting it is overhead" | L tasks routinely become XL once implementation starts; the split costs less now (in plan) than mid-implementation (where it forces work-package re-decomposition and lock re-acquisition). |
| "The title says 'and' but they're tightly coupled — keep as one task" | Tightly coupled work usually deserves a shared dependency between two tasks, not a single fused task. Fusing hides the second outcome from the checkpoint cadence. |
| "I'll skip the contracts step — this is a small feature" | Contracts are the coordination boundary between parallel agents AND the artifact that lets /validate-feature distinguish implementation from spec. Even a contracts/README.md stub documents that the question was asked. |
| "Approaches Considered is busywork — I already know the right approach" | The Approaches section forces you to articulate at least one alternative; if you can't, the "right" approach is probably untested. Reviewers (and Gate 1) need this to push back. |
tasks.md whose title contains the word "and" (almost always a hidden two-task; see "And splitting heuristic").design.md.work-packages.yaml declares parallel packages with overlapping write_allow scopes (violates the parallel-package rule in Step 8b).## Requirements instead of ## ADDED Requirements / ## MODIFIED Requirements — openspec validate will reject it.proposal.md lacks an "Approaches Considered" section, or has only one approach listed.tasks.md between groups of 2–3 implementation tasks.tasks.md and confirm none are XL and ≤ 1 are L (per Task Sizing Reference).grep -i ' and ' openspec/changes/<change-id>/tasks.md | grep -E '^\s*- \[' and confirm any matches are intentional (and noted in design.md).tasks.md contains at least one Checkpoint: marker per 3 implementation tasks.openspec validate <change-id> --strict passes (Step 9).proposal.md lists ≥ MIN_APPROACHES distinct approaches and marks one as Recommended (Step 4).testing
Create and edit Obsidian Flavored Markdown with wikilinks, embeds, callouts, properties, and other Obsidian-specific syntax. Use when working with .md files in Obsidian, or when the user mentions wikilinks, callouts, frontmatter, tags, embeds, or Obsidian notes.
tools
Interact with Obsidian vaults using the Obsidian CLI to read, create, search, and manage notes, tasks, properties, and more. Also supports plugin and theme development with commands to reload plugins, run JavaScript, capture errors, take screenshots, and inspect the DOM. Use when the user asks to interact with their Obsidian vault, manage notes, search vault content, perform vault operations from the command line, or develop and debug Obsidian plugins and themes.
data-ai
Create and edit Obsidian Bases (.base files) with views, filters, formulas, and summaries. Use when working with .base files, creating database-like views of notes, or when the user mentions Bases, table views, card views, filters, or formulas in Obsidian.
tools
Create and edit JSON Canvas files (.canvas) with nodes, edges, groups, and connections. Use when working with .canvas files, creating visual canvases, mind maps, flowcharts, or when the user mentions Canvas files in Obsidian.