Imported from 0xjgv/harness (
go/AGENTS.md). Install upstream withnpx skills add 0xjgv/harness --skill go. Copyright stays with the author.
CLAUDE
Commands
- After edits:
go run harness.go check— fix, format, lint, test, suppression ratchet - Pre-commit:
go run harness.go pre-commit— arch config guard warns first, even on an arch-config-only commit with no other staged Go files; then fix/format over the staged packages (auto via git hook). A stagedCLAUDE.mdis copied toAGENTS.mdand staged with it; a hand edit toAGENTS.mdalone fails. Arch config changes warn here, they do not fail. Tests run at pre-push. - Pre-push:
go run harness.go pre-push— branch guard runs first and short-circuits (refuses pushes to main/master unlessHARNESS_ALLOW_PROTECTED_PUSH=1, printing only the refusal and exiting before anything else runs); then the test suite (without git'sGIT_*hook variables, since tests create temp git repos; a failure stops the push); then a read-only push gate over the whole tree: lint (golangci-lint covers format), acceptance, arch run in parallel, then agents-md drift as a separate hard check after that batch (the offline checks pre-commit and stop-hook skip). Auto via git pre-push hook. - CI:
go run harness.go ci— read-only gates (lint, audit, complexity, acceptance, arch) run in parallel — captured, printed in submission order, run to completion — then agents-md drift as a separate hard check, then test-cov (streams) + crap. CRAP is advisory (warns only — pass--enforceto hard-fail). Requiresuvxon PATH. - Complexity:
go run harness.go complexity— lizard@1.22.2 CC gate (CCN≤15, args≤8, length≤100) over the module - Deadcode: no separate target — golangci-lint's
unusedlinter (run bylint/ci, and bystop-hookon changed lines) already flags unreachable functions, vars, and types, andgo mod tidyprunes unused dependencies. (x/tools/cmd/deadcodeneeds amainpackage; this template is a library.) - Audit:
go run harness.go audit— audit dependencies for known vulnerabilities (via govulncheck) - Acceptance:
go run harness.go acceptance— run godog againstfeatures/ - Coverage:
go run harness.go coverage(alias:test-cov) — tests with race detector +coverage.out; default threshold comes from.harness-baselinecoverage.min - Mutation (advisory):
go run harness.go mutation— gremlins kill-rate on./suppressions - CRAP (advisory):
go run harness.go crap --max=30— complexity × coverage gate. Add--enforceto exit 1 on offenders (default exits 0 with warning). - Suppressions:
go run harness.go suppressions— full suppression breakdown;--update-baselinerequires human sign-off and updates.harness-baseline - Arch:
go run harness.go arch— go-arch-lint against.go-arch-lint.yml - Branch guard:
go run harness.go branch-guard— refuses pushes to (or deletions of)main/master; readsHARNESS_PRE_PUSH_REFS, else git pre-push stdin (1s deadline; partial input fails), else the current branch;HARNESS_ALLOW_PROTECTED_PUSH=1overrides - Arch config guard:
go run harness.go arch-config-guard— unreviewed.go-arch-lint.ymlchanges warn in check/pre-commit, block pre-push/CI; useHARNESS_ALLOW_ARCH_CONFIG=1after review - Agents drift:
go run harness.go agents-md-drift— fail if AGENTS.md differs from CLAUDE.md - Sync:
go run harness.go sync-agents-md— overwrite AGENTS.md from CLAUDE.md - Setup:
go run harness.go setup-hooksinstalls git pre-commit + pre-push hooks (path resolved viagit rev-parse, worktree-safe) and idempotently installs the Claude/Codex Stop wiring; the Claude PostToolUse wiring ships in.claude/settings.json, andcheckwarns when either is missing - Stop hook:
go run harness.go stop-hook— post-edit, then lint on changed lines and lizard limits on the functions the change touches; silent on success, exit 2 with findings on stderr (at most 20 lines). Changed lines =git diffagainst the merge-base with the base branch (HARNESS_ARCH_BASE,GITHUB_BASE_REF, origin/HEAD, origin/main, origin/master, main, master; never fetched) plus untracked files. Touching an over-limit function blocks, so leave what you touch better; untouched debt never blocks. Compile errors always block. Exit 1: a tool could not run, or this stop already blocked once (stop_hook_active). The hooks rungo build -o harness harness.go && ./harness stop-hook, becausego runturns exit 2 into 1. An uncommittedCLAUDE.mdedit is copied toAGENTS.md. - Post-edit:
go run harness.go post-edit—golangci-lint fmton Go files with uncommitted changes, thengolangci-lint run --fix --new-from-rev=HEADover their packages only.--hook(Claude PostToolUse) does this for the edited file and, if it changed, asks the agent to re-read it; it never blocks.
Definition of done
go run harness.go checkpasses clean — never stop with check failing.- Behavior worth specifying → a
.featurescenario exists and acceptance passes; other behavior changes have unit tests. - No new suppressions: additions above
.harness-baselinefail check; suppress only with the human's sign-off, stating why. - Arch config changes are integration-blocked:
check/pre-commitwarn, andpre-push/cifail unlessHARNESS_ALLOW_ARCH_CONFIG=1is set after review. pre-push/cimust pass on your branch before you open or update a PR. Merge is the human's.- Never spend a turn on what a tool checks: formatting, lint, types, dead code, drift, and complexity come back as
check/stop-hookoutput. Read the output, fix the code, never the gate.
Behavior contract
- The human is the engineer. They own design, API shape, and merge authority. You propose on a branch, they merge.
- Commit and push on a feature branch as you go. Never commit to
main/master, never force-push, never merge.pre-pushrefuses direct pushes tomain/masterunless a human setsHARNESS_ALLOW_PROTECTED_PUSH=1; that guard stops accidents, not--no-verify, so merge ownership is a rule you follow, not one the tool can enforce.