skills/implement-feature/SKILL.md
Implement approved OpenSpec proposal with tiered execution (coordinated / local-parallel / sequential)
npx skillsauth add jankneumann/agentic-coding-tools implement-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.
Implement an approved OpenSpec proposal. Automatically selects execution tier based on coordinator availability and existing artifacts. Ends when PR is created and awaiting review.
$ARGUMENTS - OpenSpec change-id (required)
openspec/changes/<change-id>//plan-feature first if no proposal existsWhen this skill delegates work packages, treat the provider-neutral dispatch adapter
as the canonical cross-provider path. Claude Code, Codex, and
Gemini/Jules are first-class providers when configured; Claude-style Task(...)
or Agent(...) snippets are provider-specific examples, 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 commandsRun 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 work-packages.yaml exists at openspec/changes/<change-id>/:
TIER = "local-parallel"
Else if tasks.md has 3+ independent tasks with non-overlapping file scopes:
TIER = "local-parallel"
Else:
TIER = "sequential"
Emit tier notification:
Tier: <tier> -- <rationale>
If CAN_HANDOFF=true, read recent handoff context.
Per D11 of add-coordinator-task-status-renderer: at the very start of
/implement-feature, query the coordinator for any issues bearing
change:<change-id>. If the list is empty AND the coordinator is reachable,
the seeder was either skipped at Gate 2 or its earlier run failed — invoke it
now before claiming any work:
# Pseudocode — drop in coordination_bridge.try_issue_list to inspect.
if coordinator_reachable and try_issue_list(labels=["change:<change-id>"]) is empty:
skills/.venv/bin/python skills/coordinator-task-status-renderer/scripts/seed_tasks_from_md.py <change-id>
This "seeding retry" path makes Gate 2 robust to transient coordinator outages:
empty change-ids are auto-repaired at the first implementation step. The
seeder is idempotent on (change:<id>, task:<key>), so re-running is safe.
Skip this step when the coordinator is genuinely unreachable; the renderer's
stale-marker fallback still works and /implement-feature proceeds.
openspec show <change-id>
cat openspec/changes/<change-id>/tasks.md
Confirm the proposal is approved before proceeding.
AGENT_FLAG=""
if [[ -n "${AGENT_ID:-}" ]]; then
AGENT_FLAG="--agent-id ${AGENT_ID}"
fi
eval "$(python3 "<skill-base-dir>/../worktree/scripts/worktree.py" setup "<change-id>" ${AGENT_FLAG})"
cd "$WORKTREE_PATH"
# Two distinct branches matter here:
#
# WORKTREE_BRANCH — this worktree's branch, which for parallel work-package
# agents is <parent>--<agent-id>. Used for commits inside
# this worktree and for local branch verification.
# FEATURE_BRANCH — the PARENT feature branch that agent branches merge into
# and that gets pushed as the PR head. In the single-agent
# case it equals WORKTREE_BRANCH. In the parallel case it
# is the operator/default branch without the agent suffix.
#
# The parent branch is what plan-feature pushed and what the PR is opened
# against. Resolve it explicitly so the final push/PR target is stable.
eval "$(python3 "<skill-base-dir>/../worktree/scripts/worktree.py" resolve-branch "<change-id>" --parent)"
FEATURE_BRANCH="$BRANCH"
Operator branch override: If OPENSPEC_BRANCH_OVERRIDE was set at plan time, it MUST be set at implement time too — otherwise plan-feature and implement-feature will disagree on the branch and commits will diverge. The safest pattern is for the operator to set the env var for the entire session.
Parallel disambiguation: When AGENT_ID is set (parallel work-package agents), each agent gets <FEATURE_BRANCH>--<agent-id> as its WORKTREE_BRANCH so parallel agents don't clobber each other. The wp-integration package (or merge_worktrees.py) merges those sub-branches back into $FEATURE_BRANCH before the final push.
CURRENT_BRANCH="$(git branch --show-current)"
# In single-agent mode, WORKTREE_BRANCH == FEATURE_BRANCH.
# In parallel mode, WORKTREE_BRANCH is <FEATURE_BRANCH>--<agent-id>.
if [[ "$CURRENT_BRANCH" != "$WORKTREE_BRANCH" ]]; then
echo "ERROR: worktree is on '$CURRENT_BRANCH' but expected '$WORKTREE_BRANCH'" >&2
echo "Hint: if OPENSPEC_BRANCH_OVERRIDE is set, ensure it matches what plan-feature used" >&2
exit 1
fi
These rules govern every line of code written under this skill. They apply to all tiers and to every sub-agent dispatched in Step 3b. When in doubt, re-read this section.
write_allow requires. Do not opportunistically clean up adjacent code, refactor unrelated imports, or add features that weren't asked for. When you spot something genuinely broken outside scope, log it with the Scope discipline template below — do not silently fix it.feat(auth): add login AND fix unrelated typo is two commits pretending to be one.When a sub-agent (or you) notices an issue outside the current work package's scope, do NOT fix it. Log it with this exact template at the bottom of the work-package result and file a follow-up:
NOTICED BUT NOT TOUCHING:
- <file or area>: <what's wrong> — out of scope for this work package, file follow-up.
This template is mandatory for any out-of-scope observation. It surfaces the issue (so it isn't lost) without polluting the current diff.
Before any reviewer/validator dispatch happens later in phase C3, record this worker's
vendor in the change-scoped dispatch-state file. The vendor_diversity policy in
agent-coordinator/agents.yaml (worker_vs_validator) excludes the worker's vendor
from validator selection — see parallel-infrastructure/scripts/review_dispatcher.py
(record_worker_vendor, select_validator_vendor).
# AGENT_TYPE is set by the harness (e.g., "claude_code", "codex", "gemini").
# Map agent type to vendor short-name; default to the type itself if unmapped.
case "${AGENT_TYPE:-claude_code}" in
claude_code) WORKER_VENDOR="claude" ;;
codex) WORKER_VENDOR="codex" ;;
gemini) WORKER_VENDOR="gemini" ;;
*) WORKER_VENDOR="${AGENT_TYPE}" ;;
esac
python3 - <<PY
import sys
from pathlib import Path
sys.path.insert(0, "<skill-base-dir>/../parallel-infrastructure/scripts")
from review_dispatcher import record_worker_vendor
record_worker_vendor("<change-id>", "${WORKER_VENDOR}")
PY
This is idempotent (safe to call multiple times) and a no-op if the dispatcher
script isn't on the path (degrade gracefully). Validator selection in C3 reads
this state and excludes ${WORKER_VENDOR} from candidate validators when the
policy is enforced.
Before implementing, create the traceability skeleton and write failing tests:
openspec/changes/<change-id>/specs/. For each SHALL/MUST clause, create a row in the Requirement Traceability Matrix.contracts/ exists and contains machine-readable artifacts (not just README.md): map the requirement to the contract file it validates (e.g., contracts/openapi/v1.yaml#/paths/~1users, contracts/events/coordinator.schema.json). Use --- if no contract applies to this specific requirement.contracts/ exists but contains only README.md (no applicable interfaces): use --- for all contract refs.contracts/ does not exist (legacy change predating universal artifacts): log a warning that contract-based validation was skipped. Use --- for all contract refs.--- for affected contract refs. Do not block implementation on parse failures.design.md (e.g., D3) that this requirement validates. Use --- if none applies. If design.md exists, also populate the Design Decision Trace section.Use template from openspec/schemas/feature-workflow/templates/change-context.md. Write to openspec/changes/<change-id>/change-context.md.
Implementation strategy depends on the selected tier:
Work through tasks sequentially from tasks.md. Use the runtime-native apply workflow or CLI fallback:
openspec instructions apply --change "<change-id>" --json
openspec status --change "<change-id>"
Before dispatching implementation agents, resolve the archetype model. This enables complexity-based escalation from Sonnet to Opus for large work packages:
from src.agents_config import load_archetypes_config, resolve_model, compose_prompt
archetypes = load_archetypes_config() # cached singleton — no repeated file I/O
implementer = archetypes.get("implementer")
runner = archetypes.get("runner")
# For each package, resolve implementer model based on complexity signals
package_metadata = {
"write_allow": <from work-packages.yaml scope.write_allow>,
"dependencies": <from work-packages.yaml depends_on>,
"loc_estimate": <from work-packages.yaml metadata.loc_estimate>,
"complexity": <from work-packages.yaml metadata.complexity or None>,
}
impl_model = resolve_model(implementer, package_metadata) if implementer else "sonnet"
runner_model = resolve_model(runner, {}) if runner else "haiku"
Thresholds are configurable in agent-coordinator/archetypes.yaml — no code changes needed.
When tasks.md contains 3+ independent tasks (no shared files), implement concurrently:
Task(
subagent_type="general-purpose",
model=impl_model, # archetype: implementer (sonnet, or opus if escalated)
description="Implement task N: <brief>",
prompt="You are implementing OpenSpec <change-id>, Task N.
**Your Task**
<TASK_DESCRIPTION>
**File Scope (CRITICAL)**
You MAY modify: <list specific files>
You must NOT modify any other files.
**Context**
- Read openspec/changes/<change-id>/proposal.md
- Read openspec/changes/<change-id>/design.md
Do NOT commit - the orchestrator will handle commits.",
run_in_background=true
)
When to parallelize: 3+ independent tasks with no file overlap. When NOT to: Tasks that share files/state or have logical dependencies.
Uses work-packages.yaml for structured DAG execution within a single feature worktree.
A. Parse and validate work-packages.yaml:
skills/.venv/bin/python "<skill-base-dir>/../parallel-infrastructure/scripts/dag_scheduler.py" \
--validate openspec/changes/<change-id>/work-packages.yaml
Compute topological order from packages[].depends_on.
B. Execute root packages sequentially:
For each root package (depends_on == []), implement within the feature worktree.
C. Dispatch independent packages in parallel:
For each package whose dependencies are satisfied, dispatch via Agent tool:
Task(
subagent_type="general-purpose",
model=impl_model, # archetype: implementer (sonnet, or opus if escalated)
description="Implement <package-id>",
prompt="You are implementing work package <package-id> for OpenSpec <change-id>.
**File Scope (CRITICAL)**
write_allow: <from work-packages.yaml>
read_allow: <from work-packages.yaml>
deny: <from work-packages.yaml>
**Context**
<context slice from Context Slicing table below>
**Verification**
After implementation, run:
<verification steps from work-packages.yaml>
**Scope Discipline**
Follow Implementation Rules 0–5 (see `skills/implement-feature/SKILL.md`).
If you notice issues outside this package's `write_allow`, do NOT fix them.
Append to your result using the literal `NOTICED BUT NOT TOUCHING:` template
documented in the parent skill, so they're filed as follow-ups instead of
silently widening this PR.
Do NOT commit - the orchestrator will handle commits.",
run_in_background=true
)
D. Collect results and verify scope:
skills/.venv/bin/python "<skill-base-dir>/../parallel-infrastructure/scripts/scope_checker.py" \
--packages openspec/changes/<change-id>/work-packages.yaml \
--diff <git diff output>
E. Update change-context.md:
git diff --name-only main..HEADFull multi-agent DAG execution with coordinator integration. Each work package runs in its own worktree with explicit lock claims.
A1. Parse and validate work-packages.yaml against schema
A2. Validate contracts exist
A3. Compute DAG order (topological sort, cycle detection)
A3.5. Generate Change Context with relevant rows per package
A4. Create or reuse feature branch
A5. Implement root packages (sequentially, each in own worktree)
A6. Setup worktrees for parallel packages (branch from feature branch)
A7. Dispatch parallel agents with WORKTREE_PATH, BRANCH, CHANGE_ID, PACKAGE_ID
A8. Begin monitoring loop (discover_agents, get_task polling)
Each worker agent follows steps B1-B11: session registration, pause-lock check, deadlock-safe lock acquisition (lexicographic order), code generation within scope, deterministic scope check via git diff, verification steps, structured result publication.
Workers MUST call heartbeat every 30 minutes:
python3 "<skill-base-dir>/../worktree/scripts/worktree.py" heartbeat "${CHANGE_ID}" --agent-id "${PACKAGE_ID}"
C1. Result validation against work-queue-result.schema.json
C2. Escalation processing
C3. Per-package multi-vendor review (via /parallel-review-implementation)
- Self-review + vendor dispatch via parallel-infrastructure/scripts/review_dispatcher.py
- Consensus synthesis via parallel-infrastructure/scripts/consensus_synthesizer.py
C4. Integration gate (consensus-aware)
C5. Integration merge (wp-integration package, merge_worktrees.py)
C5.5. Finalize Change Context (Files Changed, Design Decision Trace, Review Findings Summary)
C6. Execution summary generation
Teardown (after PR creation or on failure):
python3 "<skill-base-dir>/../worktree/scripts/worktree.py" unpin "<change-id>"
for pkg in <package-ids> integrator; do
python3 "<skill-base-dir>/../worktree/scripts/worktree.py" teardown "<change-id>" --agent-id "$pkg"
done
python3 "<skill-base-dir>/../worktree/scripts/worktree.py" gc
Use TodoWrite for in-session state tracking. Additionally, tasks.md is the canonical post-session record of what's done — keep it in sync commit-by-commit, not batched at the end.
Per-task checkbox discipline (REQUIRED):
For each task you complete, flip its - [ ] to - [x] in openspec/changes/<change-id>/tasks.md in the same commit that implements the task. Do NOT defer checkbox updates into a trailing "mark tasks complete" commit.
tasks.md, then commit togetherfeat(<scope>): <task summary> (<change-id> task N.N)Why this discipline matters: When PRs auto-merge via review-queue automation, a trailing "mark tasks complete" commit is often skipped, lost during rebase, or bundled into an unrelated squash. Coupling the checkbox flip to the implementation commit means the bookkeeping travels with the code, and archive-time drift (tasks.md showing 0/N while implementation is 100% landed) becomes structurally impossible. Past incident: specialized-workflow-agents (archived 2026-04-22) shipped all 29 tasks of code to main with 0/29 checkboxes flipped, requiring retroactive reconciliation via /openspec-verify-change before archive.
This is a last-line-of-defense check after per-task discipline. If Step 4 was followed, this should pass trivially.
grep -E "^\s*- \[ \]" openspec/changes/<change-id>/tasks.md
# Should return nothing (all boxes checked)
If it returns any lines, STOP and reconcile before proceeding:
chore(openspec): reconcile task N.N checkbox) — do NOT amend implementation commits already on mainopenspec/changes/<change-id>/deferred-tasks.md with a short rationale, and remove it from tasks.mdDo NOT run quality checks (Step 6) or /validate-feature (Step 6.5) while tasks.md has unchecked boxes — the spec-compliance phase will fail the task-drift gate.
Run all environment-safe checks. These must pass in both cloud and local environments:
Task(subagent_type="Bash", model=runner_model, prompt="Run pytest and report pass/fail", run_in_background=true)
Task(subagent_type="Bash", model=runner_model, prompt="Run mypy src/ and report type errors", run_in_background=true)
Task(subagent_type="Bash", model=runner_model, prompt="Run ruff check . and report linting issues", run_in_background=true)
Task(subagent_type="Bash", model=runner_model, prompt="Run openspec validate <change-id> --strict", run_in_background=true)
Task(subagent_type="Bash", model=runner_model, prompt="Run validate_flows.py --diff main...HEAD", run_in_background=true)
Fix all failures before proceeding.
Run live service smoke tests if a test environment is available:
python3 skills/validate-feature/scripts/phase_deploy.py --env docker --timeout 120
python3 skills/validate-feature/scripts/phase_smoke.py
python3 skills/validate-feature/scripts/stack_launcher.py teardown
If Docker/Neon is unavailable, log a WARNING and continue with smoke status "skipped" in validation-report.md. This is a soft gate — implementation proceeds regardless.
Skip if TIER is "sequential".
Delegate to /validate-feature for environment-safe validation phases:
/validate-feature <change-id> --phase spec,evidence
This runs the canonical validation skill targeting:
spec phase): Audits change-context.md Requirement Traceability Matrix — verifies no --- entries in Files Changed, updates Coverage Summary counts, and checks each requirement against the implementation.evidence phase): Validates work-package results against work-queue-result.schema.json, checks revision consistency, scope compliance, and cross-package consistency. Populates the Evidence column in change-context.md.These phases are environment-safe and run in both cloud and local. Docker-dependent phases (deploy, smoke, security, E2E) are deferred to the merge-time validation gate in /cleanup-feature or /merge-pull-requests.
Document patterns, gotchas, and design changes in CLAUDE.md and AGENTS.md.
Construct a PhaseRecord for the Implementation phase and call write_both(). The structured fields (Decisions, Alternatives, Trade-offs, Completed Work, In Progress, Next Steps, Relevant Files) flow into both the session-log markdown and the coordinator handoff_documents — wp-integration and any downstream phase can hydrate the next phase's context from read_handoff() rather than re-parsing markdown.
Capture from this implementation:
validate-feature should pick up first.Persist via PhaseRecord.write_both():
This step MUST run BEFORE the git add . in Step 8 so the session-log entry is included in the implementation commit.
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="Implementation",
agent_type="<agent-type>",
summary="<2-3 sentences: what was implemented, deviations from plan>",
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 for validation>"],
completed_work=["<deliverable>"],
next_steps=["<what validation should check first>"],
relevant_files=[FileRef(path="<path>", description="<why it matters>")],
)
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: append rendered markdown → sanitize in-place → coordinator handoff (or local fallback at openspec/changes/<change-id>/handoffs/implementation-<N>.json). Each step logs warnings on failure but does not raise. The session-log.md is included in git add . in Step 8.
Commit quality matters: OpenSpec PRs use rebase-merge by default, so every commit appears individually on main. Structure commits as logical, self-contained units:
feat(scope):, fix(scope):, test(scope):, docs(scope):git add .
git commit -m "$(cat <<'EOF'
feat(<scope>): <description>
Implements OpenSpec: <change-id>
Co-Authored-By: Claude <[email protected]>
EOF
)"
# Push to the resolved feature branch (honors OPENSPEC_BRANCH_OVERRIDE)
git push -u origin "$FEATURE_BRANCH"
gh pr create --title "feat(<scope>): <title>" --body "..."
If CAN_HANDOFF=true, write a completion handoff.
STOP HERE -- Wait for PR approval before proceeding to cleanup.
When dispatching 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 |
$FEATURE_BRANCH (default openspec/<change-id>, or whatever OPENSPEC_BRANCH_OVERRIDE resolved to)After PR is approved:
/cleanup-feature <change-id>
| Rationalization | Why it's wrong |
|---|---|
| "While I'm in this file I'll fix the unrelated bug too" | Violates Rule 0.5 (Scope Discipline). The fix may pass review on its own merit but it bloats the diff, hides the real change, and couples your PR's fate to an unrelated risk. Use the NOTICED BUT NOT TOUCHING: template instead. |
| "This commit is broken but the next one fixes it — squash will hide it" | Violates Rule 2. Rebase-merge means every commit lands on main individually; a broken middle commit breaks git bisect for the next person to chase a regression. |
| "Adding the new flag and flipping the default in one go is cleaner" | Violates Rule 4 (Safe Defaults). Default-flip changes behavior for every existing caller silently. Land the flag OFF, ship it, then change the default in a separate, revertable commit. |
| "I'll skip the per-task checkbox flip and batch them at the end" | The trailing "mark tasks complete" commit is routinely lost in rebase/squash. Past incident: 0/29 checkboxes flipped while 100% of code was on main. Couple the bookkeeping to the implementation commit. |
write_allow without a recorded NOTICED BUT NOT TOUCHING: justification (Rule 0.5 violation).tasks.md shows unchecked boxes after Step 5 (per-task checkbox discipline violation).FEATURE_X_ENABLED, default OFF").git log --oneline main..HEAD followed by spot-checking ≥1 mid-branch commit.write_allow from work-packages.yaml, OR every such touch is documented under NOTICED BUT NOT TOUCHING:.grep -E "^\s*- \[ \]" openspec/changes/<change-id>/tasks.md returns nothing (per-task checkbox discipline applied).development
Open the artifacts relevant to a review (OpenSpec proposal, branch changes, or explicit paths) in VS Code, in a curated read-order, in the right worktree.
tools
Render and seed coordinator-owned task status block in OpenSpec tasks.md
testing
User-invocable skill that omits the tail block
tools
Missing several required keys