agentleFS
oeftimieoeftimie/vv-claude-harness/skills/harness-init/SKILL.md

harness-init

Skill20 starsChanged 3 months agoMITView on GitHub

Initialize a new project with the Long-Running Agent Harness (vv-harness plugin). Sets up feature tracking, git identity capture, context summary, build hooks, quality gate hooks, and an optional workflow size guideline. Use when starting a new multi-session project.

  • Reads credentials
  • Commits and pushes

12 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use handover.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • anujdutt9Skill

    handover

    Also in 3 projects that use this

The file

Show its rules and text

We split this skill into the rules it gives an agent

16 rules. 0 are common, 10 are distinctive, and 6 are very specific to this project.

  • 0

    Common

    Most of the 6 edited versions we read keep these.

  • 10

    Distinctive

    This author's own choices. Worth a look.

  • 6

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Follow these steps in order.

    line 8
  2. Distinctive:

    Ask the user (if not already provided):

    line 12
  3. Distinctive:

    If the user provided this information in their initial message, proceed without asking.

    line 17
  4. Very specific:

    Never hand-transcribe the framework-fixed files below into a project -- run ${CLAUDE_PLUGIN_ROOT}/scripts/stamp.sh, which emits every one …

    line 42
  5. Very specific:

    First, confirm the build hook: If the detected stack is one of typescript, swift, python, go, or rust, show the user the exact PostToolUse …

    line 47
  6. Distinctive:

    Write the answers file:

    line 54
  7. Distinctive:

    Run the stamp from the project root:

    line 68
  8. Distinctive:

    If it aborts (mode=new found an existing file), stop and show the user exactly what it reported.

    line 74
  9. Distinctive:

    When configuring for the project's stack, ensure all three targets work correctly.

    line 242
  10. Very specific:

    Do NOT wire a per-project PostCompact hook.

    line 267
  11. Distinctive:

    After installing hooks, verify they execute correctly:

    line 273
  12. Distinctive:

    If the script fails to execute (permission denied, syntax error, missing dependency), fix the issue before proceeding.

    line 283
  13. Distinctive:

    If the project already has a CLAUDE.md, append the harness reference.

    line 305
  14. Very specific:

    Wait for confirmation of the feature list.

    line 354
  15. Very specific:

    PASS: write features.json. For each feature, populate spec with {"hash": sha256(description), "verdict": "PASS", "sv_version": "1.0", …

    line 374
  16. Very specific:

    If the user explicitly waives the gate ("skip verification"), write the features with "spec": null and note the waiver in …

    line 384

“Common” is measured: kept by at least 6 in 10 of the 6 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Harness Initializer

Follow these steps in order. Do not skip steps. Ask the user when indicated.

Step 1: Gather Requirements

Ask the user (if not already provided):

  • What are you building? (brief description)
  • What's the tech stack? (language, framework, build tool)
  • Any existing code to preserve?

If the user provided this information in their initial message, proceed without asking.

Step 2: Capture Git Identity

git config user.name
git config user.email
ssh -T git@github.com 2>&1 || true
cat ~/.ssh/config 2>/dev/null | head -30

Record the active identity. Ask the user to confirm:

I detected:
- Git user: [name] <[email]>
- SSH identity: [key file or host alias]

Is this correct for this project? If you use multiple GitHub accounts, tell me which one this project belongs to.

Store the confirmed identity in .harness/harness.json.

Step 3: Create .harness/ Directory

Never hand-transcribe the framework-fixed files below into a project -- run ${CLAUDE_PLUGIN_ROOT}/scripts/stamp.sh, which emits every one of them deterministically from an answers file. Adapted from Setlist's two-phase bootstrap doctrine (Alex Ciortan, CC BY 4.0): "Never hand-write what a stamp can emit; never stamp what a decision shapes."

First, confirm the build hook. If the detected stack is one of typescript, swift, python, go, or rust, show the user the exact PostToolUse hook the stamp is about to wire in (the content of skills/harness-init/templates/posttooluse-<stack>.json -- it catches type/build errors after edits without blocking the agent, since hooks run async) and wait for confirmation before continuing. Any other stack: say plainly that no PostToolUse hook is available for it, and proceed.

Write the answers file:

mkdir -p /tmp/vv-harness-stamp
cat > /tmp/vv-harness-stamp/answers.txt <<EOF
project_name=PROJECT_NAME
stack=DETECTED_OR_SPECIFIED_STACK
mode=new
EOF

mode=new is correct here; mode=upgrade exists in stamp.sh for re-stamping an existing project and is not used by this skill.

Run the stamp from the project root:

"${CLAUDE_PLUGIN_ROOT}/scripts/stamp.sh" /tmp/vv-harness-stamp/answers.txt .

If it aborts (mode=new found an existing file), stop and show the user exactly what it reported; do not work around the abort by deleting their files.

On success this writes, byte-verbatim or rendered from a template in skills/harness-init/templates/ -- never hand-transcribed:

  • .claude/settings.json: statusLine, permissions, and the full hook wiring (PreToolUse scope/git-identity/commit-gate, TaskCompleted), plus the stack-appropriate PostToolUse build-check block selected from templates/posttooluse-<stack>.json when stack is typescript, swift, python, go, or rust; any other stack gets no PostToolUse hook.
  • .claude/hooks/{verify-task-quality.sh, enforce-scope.sh, verify-git-identity.sh, commit-gate.sh, harness_state.py, statusline.sh}, all executable. harness_state.py is the shared, stdlib-only features.json read/write module that verify-task-quality.sh consumes (schema in ${CLAUDE_PLUGIN_ROOT}/schemas/feature.schema.json). commit-gate.sh is a PreToolUse Bash hook that fires only on git commit, denying compound stage-and-commit forms and staged secret-shaped content (see the template's own header for the full check list).
  • .harness/harness.json and .harness/features.json skeletons with project/stack/ created filled in, plus plugin_version (F068) when ${CLAUDE_PLUGIN_ROOT}/ .claude-plugin/plugin.json is readable -- purely mechanical, unlike the two fields below, so the stamp writes it directly rather than deferring it to a follow-up step; git_identity is left null here (this step is the decision that fills it), and workflow.size_guideline is absent until Step 6 decides whether to write it.
  • .gitignore gains .harness/SESSION_INCOMPLETE, .harness/features.json.lock, and .harness/last_gate.json (OVI-107), all three appended idempotently.

.harness/features.json's feature schema. Each feature's shape (the 16 fields, which are required vs. optional, the status enum) is defined once in ${CLAUDE_PLUGIN_ROOT}/schemas/feature.schema.json and illustrated with the one worked example in the Feature Schema section of ${CLAUDE_PLUGIN_ROOT}/rules/parallel-work.md. scripts/validate-features.py enforces it in the test suite.

The done-definition (passing / done / shipped) and the optional claim-matched-proof fields (qa_binding, proof, coverage_target, delivered, design_contract) are defined once, in the Feature Schema section of ${CLAUDE_PLUGIN_ROOT}/rules/parallel-work.md — see that section rather than this one for the current definition.

A feature may also carry a spec verification object; see the Feature Schema section of ${CLAUDE_PLUGIN_ROOT}/rules/parallel-work.md.

Then finish the pieces the stamp deliberately leaves to a decision:

1. Fill in git_identity with the identity confirmed in Step 2:

python3 - <<'PYEOF'
import json

with open(".harness/harness.json") as f:
    data = json.load(f)
data["git_identity"] = {
    "user_name": "DETECTED_NAME",
    "user_email": "DETECTED_EMAIL",
    "ssh_key": "<key file or host alias>",
    "ssh_host": "github.com OR ALIAS",
}
with open(".harness/harness.json", "w") as f:
    json.dump(data, f, indent=2)
PYEOF

2. Record the initial worker block (F016/OVI-57): probe claude --version the same defensive way harness-continue's Step 2.6 does -- unavailable or unparseable output -> skip silently, no worker key written, and epoch tracking simply starts the first time a later session records it:

python3 - <<'PYEOF'
import json
import re
import subprocess

try:
    out = subprocess.check_output(["claude", "--version"], stderr=subprocess.DEVNULL, text=True)
except (FileNotFoundError, subprocess.CalledProcessError):
    raise SystemExit(0)

match = re.search(r"(\d+\.\d+\.\d+)", out)
if not match:
    raise SystemExit(0)

with open(".harness/harness.json") as f:
    data = json.load(f)
data["worker"] = {
    "cli_version": match.group(1),
    "models": {"lead": "opus", "implementer": "sonnet", "reviewer": "opus"},
    "recorded_at": "<ISO8601 UTC>",
}
with open(".harness/harness.json", "w") as f:
    json.dump(data, f, indent=2)
PYEOF

The models values are the CURRENT row values from rules/parallel-work.md's Model Selection table (the single bindings table) at the time you run this -- if that table has since been requalified to different bindings, use those instead of the opus/sonnet/opus shown here. Schema: schemas/feature.schema.json's $defs/harness_worker_block.

plugin_version (F068) is NOT a follow-up step here, unlike git_identity and worker above -- unlike those two, it needs no user decision and no live subprocess probe, only a file already sitting next to scripts/stamp.sh on disk, so the stamp itself writes it directly (see scripts/stamp.sh's own comments). harness-doctor (F068) compares it against the currently installed plugin on later runs and offers to bootstrap or refresh it via --fix if it's ever missing or stale.

3. Write .harness/context_summary.md -- this carries real project judgment (domain, constraints, architecture), never zero-decision content, so it stays hand-authored:

# Context Summary

Persistent record of architectural decisions, discovered patterns, gotchas, and active context.
This file is referenced in CLAUDE.md and loaded every session.

## Active Context
- Currently working on: project initialization
- Next up: first feature implementation

## Cross-Cutting Concerns
- Stack: [stack]
- Architecture: [brief description]
- Key constraints: [any constraints mentioned by user]

## Domain: [Primary Domain]

### Decisions
- [Stack] chosen: [rationale] (ISO_DATE)

### Patterns
- (none yet)

### Gotchas
- (none yet)

## Meta-Patterns
<!-- Coordination insights that apply across features — NOT domain-specific.
     Populated by the retrospective step at session end.
     These transfer to new projects: harness-init can import them as starting context. -->
- (none yet — first retrospective will populate this)

4. Write .harness/claude-progress.txt:

# Claude Progress Log
# Project: PROJECT_NAME
# Created: ISO_DATE

## Session 1 - Initialization
- Created harness scaffolding
- Detected stack: [stack]
- Git identity: [user] <[email]>
- [List what you set up]

5. Configure .harness/init.sh for the detected stack -- the one genuinely decision-shaped file in this set, so the stamp does not touch it. Read the init.sh.template file in this skill's directory, copy it to .harness/init.sh, configure for the detected stack, and make it executable with chmod +x.

The script accepts an optional target argument: smoke_test, focused_test <test_file>, or full_test (default: full_test).

  • smoke_test — compile/syntax check only, completes in <15s. Used by the TaskCompleted hook as a fast first-pass gate.
  • focused_test <test_file> — run exactly one test file. The TaskCompleted hook passes the targeted feature's recorded test_file as the second stage of its gate; the hook detects support by grepping init.sh's non-comment lines for focused_test and stays smoke-only when absent, so older projects keep working unchanged. Exit-code contract: 0 strictly means the test executed and passed; 3 means the script skipped the stage ("skipped, no runner": no per-file runner for the stack, or the recorded test file does not exist), which the hook treats as not-run — accepted on smoke alone, no baseline recorded — never as a pass; any other exit is a real failure that rejects the completion. 3 is reserved for the script's own skip sites: a runner's own exit 3 must be remapped to a failure (the template's run_focused helper does this), since real runners use 3 for genuine failures (pytest INTERNALERROR, mocha's failing-test count).
  • full_test — complete test suite with coverage. Enforced when a feature's status flips to passing (the commit gate runs it whenever a staged features.json contains such a flip) and used by the lead at session end and synthesis phase. It does NOT run on every task completion.

When configuring for the project's stack, ensure all three targets work correctly.

Authoring rule — full_test must be satisfiable mid-project. full_test gates every passing-flip commit, so a check that cannot go green until the whole project is done jams every feature before it. It must also finish comfortably inside Claude Code's PreToolUse command-hook timeout (600s default): the commit gate runs it synchronously on a passing-flip commit, and a hook killed by the timeout allows the command — a too-slow suite silently converts the gate to fail-open. The concrete trap is workspace-aggregate metrics: a hardcoded "aggregate coverage >= 99%" makes feature A's completion depend on feature B's unwritten tests, and an unreachable gate teaches agents to route around gates. Put aggregate metrics in as ratchets — compare against a stored baseline (e.g. .harness/coverage-baseline.json) and fail only on regression, updating the baseline as it improves. Reserve fixed high thresholds (95%, 99%) for per-feature scope (the coverage_target gate already enforces that) or an explicit release feature's acceptance criteria.

Step 3.6: Quality Gate Hooks (via the Stamp)

The stamp run in Step 3 already wrote and chmod +x'd every quality gate hook (verify-task-quality.sh, enforce-scope.sh, verify-git-identity.sh, commit-gate.sh, harness_state.py, statusline.sh) and wired the full .claude/settings.json block (statusLine, permissions, and the PreToolUse/TaskCompleted hooks) -- there is nothing left to do here beyond the verification in Step 3.7.

Do NOT wire a per-project PostCompact hook. The plugin's SessionStart hook (which fires with a compact source after compaction) already injects post-compaction recovery directly into the model's context, so a separate PostCompact hook would be redundant.

Step 3.7: Verify Hooks

After installing hooks, verify they execute correctly:

echo '{}' | "$CLAUDE_PROJECT_DIR"/.claude/hooks/verify-task-quality.sh
echo "Exit code: $?"

Expected results:

  • verify-task-quality.sh: exit 0 if tests pass, exit 2 if tests fail

If the script fails to execute (permission denied, syntax error, missing dependency), fix the issue before proceeding. Silent hook failures mean quality gates don't enforce anything.

Tell the user:

I've set up four hooks plus a status line:
- PreToolUse (scope): blocks writes to lead-owned state files (features.json, context_summary.md). Armed automatically inside workflow-agent worktrees; unrestricted in the main checkout.
- PreToolUse (git identity): blocks git push/pull/clone if identity doesn't match .harness/harness.json.
- PreToolUse (commit gate): blocks git commit if it stages-and-commits in one step, or if staged content looks like a secret.
- TaskCompleted: runs tests when an agent marks work done. Rejects if tests fail.
- Status line: live feature progress (N/M passing, in-progress IDs, incomplete-session flag).

Session orientation and post-compaction recovery are injected by the vv-harness
plugin's SessionStart hook; no per-project PostCompact hook is needed.

Quality gate hooks verified: [pass/fail status for each].

These enforce TDD and context recovery mechanically instead of relying on instructions alone.

Step 4: Update Project CLAUDE.md

If the project already has a CLAUDE.md, append the harness reference. If not, create one:

# [PROJECT_NAME]

[Brief description from user]

## Tech Stack

[Stack details]

## Harness

This project uses the Long-Running Agent Harness (vv-harness plugin).

- Feature tracking: `.harness/features.json`
- Context and decisions: `.harness/context_summary.md` (READ THIS at session start)
- Progress handoff: `.harness/claude-progress.txt`
- Build/test: `.harness/init.sh`
- Quality gates: `.claude/hooks/` (TaskCompleted, scope, git identity, commit gate)

## Git Identity

This project uses: [user_name] <[user_email]> with SSH key [ssh_key].
Always verify identity before push/pull/clone operations.

Step 5: Propose Initial Features

Based on the project description, propose 3-5 initial features. Include scope for each:

Based on your description, here are the initial features I suggest:

F001: [Core feature 1] - Priority 1
  Scope: [directories]
  Depends on: (none)

F002: [Core feature 2] - Priority 2
  Scope: [directories]
  Depends on: (none)

F003: [Supporting feature] - Priority 3
  Scope: [directories]
  Depends on: F001

Should I add these to features.json?

Wait for confirmation of the feature list. Then, BEFORE writing anything to .harness/features.json, run the spec gate (Step 5.1).

Step 5.1: Verify the proposal (spec gate)

Spawn the spec-verification agent as a read-only subagent over the ENTIRE confirmed proposal in one call:

Agent({
  description: "Spec-verify proposed features",
  subagent_type: "vv-harness:spec-verification",
  model: "opus",
  prompt: "[the full proposal: every feature's id, description, scope, depends_on,
            plus the user's project description. Ask for a per-feature verdict line
            in the report.]"
})

Route on the report's VERDICT:

  • PASS: write features.json. For each feature, populate spec with {"hash": sha256(description), "verdict": "PASS", "sv_version": "1.0", "verified_at": ISO8601-UTC, "source": "conversation"} (canonical hash recipe: ${CLAUDE_PLUGIN_ROOT}/schemas/readiness-stamp.md).
  • ASK: relay the numbered OPEN QUESTIONS to the user verbatim; iterate the feature descriptions with their answers; re-run the gate on the amended proposal. Do not write features.json until the gate passes.
  • BLOCK: present the grounds; the user amends or drops the contradicted features; re-run.

If the user explicitly waives the gate ("skip verification"), write the features with "spec": null and note the waiver in claude-progress.txt. Never fill spec for a feature the gate did not pass.

Step 6: Assess Workflow Sizing

Parallel work runs as worktree-isolated agents dispatched by a workflow, sized per run rather than per project. Ask once, about expected parallelism, so later sessions have a stated ceiling to size against:

Parallel work here runs as worktree-isolated agents inside a workflow, sized per run.
What's the expected parallelism for this project?

- small: a handful of independent features at a time
- medium: a moderate parallel front
- large: no ceiling worth stating -- size each run on its own

Or skip this, and I'll size each run on its own with no standing advice.

Map the answer to workflow.size_guideline in .harness/harness.json:

Answerworkflow.size_guidelineWhat it advises
small"small"at most 5 agents per workflow
medium"medium"at most 15 agents per workflow
large"large"no cap
skippedkey not writtenno sizing advice

The key is optional: an absent key means no advice, which is exactly what a project that skipped this question wants. Write it only for an answer the user actually gave:

python3 - <<'PYEOF'
import json

with open(".harness/harness.json") as f:
    data = json.load(f)
data.setdefault("workflow", {})["size_guideline"] = "SMALL_MEDIUM_OR_LARGE"
with open(".harness/harness.json", "w") as f:
    json.dump(data, f, indent=2)
PYEOF

This is a guideline, not a gate. The lead sizes each workflow run on the work actually in front of it during /harness-continue.

Step 7: Commit and Report

git add .harness/ .claude/ CLAUDE.md .gitignore
git commit -m "chore: initialize vv-harness scaffolding"

Report:

Harness (vv-harness plugin) initialized:
- .harness/ created with [N] features (scope, dependencies, spec gate: [passed | waived])
- Git identity captured: [user] <[email]>
- Build hook: [installed | skipped] for [STACK]
- Quality gates: TaskCompleted + PreToolUse hooks installed and verified
- CLAUDE.md updated
- Workflow sizing: [small | medium | large | not set]

Next: run /harness-continue to start working.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.