| name | harness-continue |
| description | Continue working on a harness-managed project (vv-harness plugin). Orients to current state, picks single-session or Agent Teams mode, and guides implementation with TDD, quality gate hooks, and compaction-aware context management. Use at the start of any session on a harness project. |
Harness Continue
Step 1: Orient Yourself
The vv-harness plugin's SessionStart hook auto-injects orientation at session start:
feature summary, next claimable feature, last handoff, Active Context, a git identity
warning on mismatch, and any SESSION_INCOMPLETE gaps from the previous session. Use
that injected "## Harness orientation" block instead of re-reading the harness files.
Resolve any SESSION_INCOMPLETE gaps it surfaces before starting new work.
This skill covers what the hook does not: mode choice, the smoke test, and team
planning.
Check for untracked files and inherited task quality:
git status -s
If you see untracked files you didn't create (e.g., notes.md, scratch files), surface them to the user immediately: "I see [file] untracked — should I delete it, gitignore it, or leave it?" This takes 5 seconds and prevents orphaned file accumulation.
If inheriting tasks from a previous session, verify they have required metadata fields (feature_id at minimum) via TaskList. Tasks without feature_id can't be correlated by hooks or retrospectives. Update them with TaskUpdate now if they're missing it.
Step 2: Verify Git Identity
The SessionStart hook already compared git config user.email against
.harness/harness.json and warned on mismatch (non-blocking). If the orientation
block shows an identity warning, fix it before proceeding. Also verify the SSH
identity, which the hook does not check:
ssh -T git@github.com 2>&1 || true
Do not skip this.
Step 2.5: Smoke Test
Run the project's build/test smoke test:
./.harness/init.sh
This is a gate, not a diagnostic. Its purpose is to confirm the environment is in a known-good state BEFORE any changes. If it fails, you know the problem is pre-existing, not something you introduced. Run it within the first 5 actions of every session. No exceptions. The 15-second cost prevents 15-minute debugging sessions later.
Step 3: Set Effort Level
Set effort based on the current phase:
- Architecture decisions, debugging failing tests, reviewing teammate work:
/effort high
- Feature implementation (TDD loop), file refactoring:
/effort medium (default)
- Formatting, linting fixes, boilerplate generation:
/effort low
Adjust as you transition between phases during the session.
Step 4: Decide Mode
Choose Single-Session if:
- One feature is next and it touches fewer than 5 files
- The feature is sequential (can't be parallelized)
harness.json team_structure is null
- User explicitly asks for focused work
When choosing single-session, explicitly declare it: "Running in single-session mode — I'm both lead and implementer." This makes the decision conscious and documented, preventing ambiguity between "I forgot plan mode" and "plan mode doesn't apply here."
Choose Agent Teams if:
- Multiple independent features are ready
- The next feature has clearly independent components
harness.json has a team_structure defined
- User explicitly asks for parallel work
Graceful degradation — Agent Teams unavailable:
Agent Teams is gated by CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1; the implicit team,
SendMessage, and the TaskCompleted/TeammateIdle coordination hooks are active only
when it is set. If the variable is unset or team coordination is unavailable, do NOT
abort parallel work. Fall back to direct subagents spawned via the Agent tool using the
same vv-harness agent types
(vv-harness:feature-implementer, vv-harness:layer-implementer,
vv-harness:researcher, vv-harness:reviewer), passing isolation: "worktree" at
spawn time for independent feature scopes — worktree isolation is documented platform
behavior for subagents. The lead merges the worktree branches at synthesis (Phase 4).
This is the supported, non-experimental path. Team-only machinery does not apply in
this mode: no SendMessage interface negotiation, no TeammateIdle reassignment —
sequencing falls back to the lead, which spawns dependent work only after its
prerequisites are merged.
Ask the user if it's ambiguous:
I see [N] features ready. I can either:
1. Work on F00X in a focused single session
2. Spawn a team to work on F00X and F00Y in parallel
Which do you prefer?
Step 5a: Single-Session Workflow
Setup
- Select highest-priority incomplete feature
- Update
features.json: set status to "in-progress", set assigned_to to "single-session"
- Create a structured task list using TaskCreate (these survive compaction):
TaskCreate({ subject: "F001: Read existing code in [scope directories]", description: "Understand patterns before implementing", activeForm: "Reading existing code", metadata: { feature_id: "F001" } })
TaskCreate({ subject: "F001: Write failing test for [feature]", description: "[feature description] — TDD red phase", activeForm: "Writing failing test", metadata: { feature_id: "F001" } })
TaskCreate({ subject: "F001: Implement minimum code to pass", description: "TDD green phase", activeForm: "Implementing feature", metadata: { feature_id: "F001" } })
TaskCreate({ subject: "F001: Run full test suite", description: "Verify no regressions", metadata: { feature_id: "F001" } })
TaskCreate({ subject: "F001: Verify coverage >= 95% on touched code", description: "Coverage gate", metadata: { feature_id: "F001" } })
TaskCreate({ subject: "F001: Update features.json", description: "Set status to passing, populate test_file and coverage", metadata: { feature_id: "F001" } })
TaskCreate({ subject: "F001: Update context_summary.md with learnings", description: "Persist decisions and patterns", metadata: { feature_id: "F001" } })
Use TaskUpdate to mark each task in_progress when starting and completed when done. Task updates must happen at the moment of state change, not in batch. The rule: when you finish something, the NEXT action is TaskUpdate — before responding to the user, before starting the next task. If planned tasks no longer match reality (scope changed, new work appeared), update or delete stale tasks immediately. A stale task list is worse than no task list because it creates false confidence about state.
- Run smoke test:
./.harness/init.sh
Implement with TDD
- Write failing test that defines "done" for this feature
- TaskUpdate: mark test task
in_progress
- Confirm it fails (proves test is valid)
- Implement minimum code to pass
- TaskUpdate: mark implementation task
in_progress
- Confirm test passes
- TaskUpdate: mark test task
completed
- Refactor if needed
- Repeat until feature is complete
- Run full suite; coverage >= 95% on touched code
No exceptions unless tooling is broken.
Context Updates During Work
Treat context_summary.md updates as part of the task, not after the task. Specifically: after every bug fix that reveals a non-obvious root cause, write the gotcha to context_summary.md BEFORE moving to the next request. The cost is 30 seconds; the value is permanent. A future session will benefit from knowing the root cause without re-discovering it.
For the context_summary.md structure and section-by-section update rules, read ${CLAUDE_PLUGIN_ROOT}/rules/context-summary.md.
When Feature Passes
- Update
.harness/features.json: set status to "passing", add test_file and coverage, clear assigned_to. Also populate approaches_tried with a brief note on what worked (even for single-session work — this feeds the retrospective).
- Append architectural decisions and discovered patterns to
.harness/context_summary.md
- If you discovered a need for a new feature while implementing this one, add it to
features.json with discovered_via pointing to this feature's ID.
Compaction Strategy
If approaching context limit, compact at a clean breakpoint:
- After tests pass for a subtask
- After a clear phase completes
Before compacting, ensure:
- Task list has your current state (should already be current if you're updating after every step)
context_summary.md has any important context that must survive
Use /compact with a focus instruction, e.g.:
/compact Focus on: current feature F003 state, TDD progress, decisions made about auth architecture
After compaction, the plugin's SessionStart hook (matcher compact) automatically
injects a recovery block plus fresh orientation: re-read .harness/context_summary.md
Active Context and the task list. Follow it — it's your recovery path.
Session End
- Run full test suite one final time
- Pre-commit features.json audit: Diff
features.json against the actual work done this session. If any code was changed that relates to a tracked feature, that feature's metadata must be updated (status, test_file, coverage). If work was done that doesn't map to any existing feature, create a new feature entry with discovered_via pointing to the trigger. This check is a gate before git commit, not an afterthought.
- Retrospective (mandatory): Run the retrospective regardless of session type. For single-session work, it can be shorter (3-5 bullets), but it must exist. Minimum viable retrospective: (1) what was the session's actual scope vs planned scope? (2) what was discovered that wasn't anticipated? (3) what pattern or gotcha should transfer to future sessions? Write to
context_summary.md under ## Meta-Session [DATE] before the final commit. Skip only if this is the project's very first session.
- Write handoff to
claude-progress.txt:
## Session [N] - [DATE]
- Feature: F00X - [description]
- Status: [complete | in-progress | blocked]
- Tests: [N passing, M failing]
- Coverage: [X%] on touched code
- Decisions: [brief list, details in context_summary.md]
- Next: [what the next session should do]
- Blockers: [any blockers]
- Git commit (see Commit Hygiene rules — separate harness metadata from code commits)
Before declaring the session complete, work through the full checklist in ${CLAUDE_PLUGIN_ROOT}/rules/task-completion.md (base checklist plus the harness-specific additions).
Step 5b: Agent Teams Workflow
Before any team coordination, Read the Agent Teams protocol at
${CLAUDE_PLUGIN_ROOT}/rules/agent-teams-protocol.md. Agent Teams is experimental and
gated by CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1; the team forms implicitly when the
first teammate is spawned (no setup step) and is cleaned up automatically when the
session ends. This workflow uses Claude Code's native primitives: the Agent tool for
spawning, TaskCreate, TaskUpdate, TaskList, and SendMessage.
Phase 1: Plan (cheap, read-only)
Before spending tokens on teammates, produce a decomposition plan:
- Analyze the pending features in
.harness/features.json
- Use
scope and depends_on from each feature to identify parallelism opportunities and dependency chains
- Review historical operational metrics from past features to calibrate the team:
- Features with
correction_cycles >= 3 in the same scope directories → upgrade implementer to Opus
- Features with
scope_expansions >= 3 → assign a broader initial scope to reduce mid-work expansion overhead
- Features with
discovered_via depth > 1 → consider folding them into the parent feature's scope
- Scopes that needed frequent expansion in past sessions → note them as "expansion-prone" when scoping this team
- Design the team:
- Which teammates, what scope (from features.json
scope field), what model (Sonnet default; Opus if historical metrics suggest high difficulty). The plugin agent definitions already default the model per role (implementers and researcher: Sonnet; reviewer: Opus); a spawn-time model parameter overrides the definition's frontmatter, so an Opus upgrade needs only the Agent tool call's model param.
- Which tasks depend on which (from features.json
depends_on field, mapped to TaskUpdate addBlockedBy calls after task creation)
- Whether any teammate needs
require_plan_approval: true
- Present the plan to the user:
I propose this team structure:
Lead (Opus, plan mode): coordination, synthesis, final review
Teammate "api" (Sonnet): F001 - owns src/api/ and tests/api/
Teammate "ui" (Sonnet): F002 - owns src/components/ and tests/components/
→ blocked by "api" (F002 depends_on F001)
Teammate "reviewer" (Opus): reviews both after completion
Dependencies (from features.json):
Task 1 (F001 API) → unblocks Task 2 (F002 UI)
Tasks 1+2 → unblock Task 3 (review)
Plan approval required: No (scopes are straightforward)
Estimated: 3 teammates × Sonnet + 1 reviewer × Opus
Note: Opus lead runs for the full session; total cost depends on session length, not just implementer tokens.
Approve this plan?
Wait for user approval before proceeding to Phase 2. That approval is durable: it covers
execution through to the approved goal's completion. Do not stop for further go-aheads at
phase transitions; return to the user only when the goal is accomplished, the work is
blocked, or the approved plan itself must change.
Phase 2: Execute
-
Activate plan mode (Shift+Tab) to restrict yourself to coordination-only tools. Do not edit code directly.
-
Update features.json: set assigned_to for each feature being worked on.
-
Confirm CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 is set. There is no team-creation
step: the implicit team forms when the first teammate is spawned (Step 5) and is
cleaned up automatically when the session ends.
-
Create tasks with feature metadata, then set dependency chains (derived from features.json depends_on):
# Create all tasks first (they start as pending by default)
# Always include metadata.feature_id — hooks and TaskList use it for correlation
TaskCreate({ subject: "F001: Build API endpoint", description: "[detailed spec]", activeForm: "Building API endpoint", metadata: { feature_id: "F001", scope: "src/api/", model: "sonnet" } })
# → task id "1"
TaskCreate({ subject: "F002: Build UI consuming API", description: "[detailed spec]", activeForm: "Building UI layer", metadata: { feature_id: "F002", scope: "src/ui/", model: "sonnet" } })
# → task id "2"
TaskCreate({ subject: "Review F001 + F002", description: "[review criteria]", activeForm: "Reviewing implementation", metadata: { feature_id: "F001,F002", scope: "*", model: "opus" } })
# → task id "3"
# Then set dependencies via TaskUpdate
TaskUpdate({ taskId: "2", addBlockedBy: ["1"] })
TaskUpdate({ taskId: "3", addBlockedBy: ["1", "2"] })
-
Spawn teammates as the vv-harness plugin agent types. Each definition bakes in the
role's reusable guardrails (TDD discipline, tool allowlist, scope rules, completion
protocol), so the spawn prompt carries only per-feature specifics — use the templates
from team-spawn-prompts.md in this skill's directory:
Agent({
description: "Implement F001",
subagent_type: "vv-harness:feature-implementer",
name: "api",
model: "sonnet",
prompt: "[per-feature specifics: feature ID, scope from features.json, deliverable, git identity, plan-approval flag, task ID]"
})
The name makes the teammate addressable via SendMessage; the team it joins is
implicit, so there is no team_name to pass (the parameter is accepted but ignored).
Agent types: vv-harness:feature-implementer, vv-harness:layer-implementer,
vv-harness:researcher, vv-harness:reviewer. The spawn-time model parameter
overrides the definition's frontmatter model, so the Phase 1 Opus-upgrade heuristic
applies unchanged. Include git identity from harness.json in each spawn prompt.
Do not re-paste guardrail prose into spawn prompts — it lives in the agent definitions.
The spawn tool is exposed as Agent (older CLIs called it Task); adapt to what your
CLI exposes.
-
At team start, confirm plan-approval messaging uses type "message" (the
plan_approval_response delivery-bug workaround) — one SendMessage round-trip with a
teammate is the check; if it fails on a newer CLI, fall back to the worktree-subagent
mode (Step 4, graceful degradation).
Phase 3: Monitor
- Check
TaskList for progress
- Respond to incoming
SendMessage messages:
- Task complete message: review the work, verify tests passed (TaskCompleted hook handles mechanical check)
- Blocked message: unblock or reassign
- Scope expansion request: approve or deny, update scope in features.json
- Plan approval request: review plan, approve or reject with a direct
SendMessage (type "message", not "plan_approval_response" which has a delivery bug)
- Resolve conflicts if teammates need overlapping files
- After 3 check-ins with no progress from a teammate, take over that scope or spawn a replacement
The TeammateIdle hook prompts idle teammates to pick up remaining features, so you don't need to manually reassign after each task completes.
Phase 4: Synthesize
When all teammates complete:
- Exit plan mode if needed for hands-on review
- Run the full test suite
- If integration issues arise, follow the Integration Failure Recovery protocol in the Agent Teams rules:
- Identify conflicting changes via
git diff
- Revert cleanly rather than attempting broken merges
- Record conflict resolution in
context_summary.md
- Update
.harness/features.json for each completed feature (status, test_file, coverage, clear assigned_to)
- Append decisions and patterns to
.harness/context_summary.md
Phase 5.5: Retrospective (run before teardown when all features complete)
When all features reach status: "passing", run a metacognitive retrospective before teardown. This is the mechanism by which the harness improves its own coordination — not just the domain code.
Review the operational metrics across all features completed this session:
- Scope accuracy: Which features had
scope_expansions > 0? What does that reveal about how to scope similar work next time? (e.g., "auth/ and user/ are coupled — scope them together")
- Model calibration: Which features had
correction_cycles >= 3? Were they on Sonnet? If yes, note that similar-scope features should use Opus.
- Discovery lineage: Which features have
discovered_via set? Does the discovery pattern suggest the initial feature decomposition missed something systematic?
- Approach patterns: What patterns in
approaches_tried worked repeatedly? What failed repeatedly?
- Plan approval value: Did
require_plan_approval prevent rework, or was it overhead? Note which feature types benefited.
Write findings to .harness/context_summary.md under a new ## Meta-Session [DATE] section:
## Meta-Session 2026-03-23
- Scope accuracy: [findings — which scopes needed expansion and what that means]
- Model calibration: [which features burned correction cycles on Sonnet; upgrade recommendation]
- Discovery lineage: [which features were discovered mid-work; what to probe for at init time]
- Approach patterns: [what worked, what failed]
- Plan approval: [was it worth the overhead for which feature types]
When to skip: If this is the first session (no historical data in features.json operational metrics), skip the retrospective — there's nothing to analyze yet. Write a note: ## Meta-Session [DATE] — first session, no retrospective data yet.
Write findings to ## Meta-Patterns for insights that generalize beyond this session:
## Meta-Patterns
- [Insight that applies to future sessions, not just this domain]
Do NOT write domain-specific decisions here — those go in the Domain sections. Meta-Patterns are coordination insights: when to use Opus, how to scope, when to require plan approval.
Phase 5: Teardown
- Send
shutdown_request to all teammates via SendMessage
- Wait for
shutdown_response from each
- Write handoff to
claude-progress.txt:
## Session [N] - [DATE] (Agent Teams: [N] teammates)
- Teammates: [name (model): scope] for each
- Tasks: [N completed, M blocked, P pending]
- Features completed: [list]
- Features in-progress: [list]
- Dependencies resolved: [any chains that unblocked]
- Integration issues: [any conflicts resolved, details in context_summary.md]
- Tests: [N passing, M failing]
- Cost note: [models used, if relevant]
- Next: [what the next session should do]
- Git commit
Edge Cases
All high-priority features are complete:
Report to user. Ask if there are new features to add or if the project is done.
Feature is blocked:
Document the blocker in claude-progress.txt and context_summary.md. Move to the next available feature.
Tests are failing from a previous session:
Fix them before starting new work. This is priority zero.
Context is getting heavy mid-session:
Compact at the next clean breakpoint. Task list should already be current (you're updating after every step). Ensure context_summary.md has any important context, then /compact.
Teammate crashes or stalls:
The 5-minute heartbeat timeout will notify the lead. Spawn a replacement teammate for the stalled scope, or take over the scope directly (exit plan mode). Update assigned_to in features.json.
Lead session interrupted:
In-process teammates are lost if the lead dies. teammateMode defaults to "in-process", so set it explicitly (tmux or auto) for long-running team sessions that might be interrupted. On restart, read claude-progress.txt, features.json (check assigned_to fields), and context_summary.md to reconstruct state. Features with assigned_to set but status still in-progress were likely interrupted mid-work.
Integration failure between teammates:
Follow the Integration Failure Recovery protocol in agent-teams-protocol.md. Prioritize getting back to green tests over preserving partial work.