@tanagram/harness
v0.1.4
Published
Full feature lifecycle for Claude Code — worktrees, dev stack, real testing, PRs.
Readme
tanagram-harness
A Claude Code plugin that gives you the full feature lifecycle in one command — isolated worktrees, dev stack orchestration, real testing, and PR creation.
/harness start fix-auth-flow
/harness test
/harness pr
/harness cleanupInspired by OpenAI's Harness Engineering — the idea that every feature should be developed in an isolated, bootable environment with mechanical enforcement and real validation.
Install
/plugin install ./tanagram-harness --scope userOr from the marketplace:
/plugin marketplace add tanagram/harness
/plugin install tanagram-harnessQuick Start
Generate a
harness.jsonfor your project:npx @tanagram/harness initThis detects your project structure and walks you through setup interactively. (Optional — works without one for simple single-service projects.)
Run
/harness start my-featureDevelop your feature in the isolated worktree
Run
/harness testto verify against real running servicesRun
/harness prto create a pull requestRun
/harness cleanupto remove the worktree and free ports
harness.json Reference
{
"baseBranch": "origin/main",
"envFiles": ["**/.env"],
"services": [
{
"name": "api",
"directory": "backend",
"install": "poetry install --with dev",
"start": "poetry run uvicorn main:app --port ${PORT}",
"port": 8000,
"health": "/health",
"test": "poetry run pytest -x",
"dependsOn": []
},
{
"name": "web",
"directory": "frontend",
"install": "pnpm install",
"start": "PORT=${PORT} pnpm dev",
"port": 3000,
"health": "/",
"test": "pnpm test && pnpm typecheck",
"dependsOn": ["api"],
"env": {
"VITE_API_BASE_URL": "http://localhost:${ports.api}"
}
}
],
"portOffset": 10,
"browser": { "entry": "web" }
}Top-Level Fields
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| baseBranch | string | "origin/main" | Branch to create worktrees from |
| envFiles | string[] | ["**/.env", "**/.env.local"] | Glob patterns for env files to copy into worktrees |
| services | Service[] | auto-detected | Services to start |
| portOffset | number | 10 | Port offset multiplier per worktree slot |
| browser.entry | string | first service | Which service to open in browser for verification |
Service Fields
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| name | string | yes | Service identifier |
| directory | string | yes | Subdirectory relative to project root |
| install | string | no | Dependency install command |
| start | string | yes | Start command (${PORT} is substituted with the allocated port) |
| port | number | yes | Base port number |
| health | string | no | Health check endpoint path (e.g. "/health") |
| test | string | no | Test command |
| dependsOn | string[] | no | Services that must start before this one |
| env | object | no | Env vars to set when starting. Values support ${ports.SERVICE} to reference another service's allocated port |
Without harness.json
For simple single-service projects, the plugin auto-detects:
- Node.js (
package.json):npm install→npm run devon port 3000 - Python (
pyproject.toml):poetry install→poetry run uvicornon port 8000
No config needed.
Commands
/harness start [feature-name]
Creates an isolated git worktree, copies env files, installs dependencies, starts all services with auto-allocated ports, and enters plan mode to begin development.
/harness test [feature-name]
Runs service tests per harness.json, verifies in-browser via Chrome DevTools MCP, and checks stack logs for errors. All tests run against real services — no mocks.
/harness pr [feature-name]
Stages changes, commits, pushes, and creates a GitHub PR with summary and test plan.
/harness cleanup [feature-name]
Stops all services, frees ports, removes the worktree, and optionally deletes the remote branch.
/harness status
Lists active worktrees, running stacks, and port allocations across all features.
Port Allocation
Each concurrent worktree gets a slot. Ports are offset by slot * portOffset:
| Service | Base | Slot 1 | Slot 2 | Slot 3 | |---------|------|--------|--------|--------| | api | 8000 | 8010 | 8020 | 8030 | | web | 3000 | 3010 | 3020 | 3030 |
Port assignments are tracked in ~/.claude/stack-registry.json.
Example Configs
Next.js App
{
"services": [
{
"name": "web",
"directory": ".",
"install": "npm install",
"start": "PORT=${PORT} npm run dev",
"port": 3000,
"health": "/",
"test": "npm test"
}
]
}Django + React
{
"baseBranch": "origin/main",
"services": [
{
"name": "api",
"directory": "api",
"install": "pip install -r requirements.txt",
"start": "python manage.py runserver 0.0.0.0:${PORT}",
"port": 8000,
"health": "/api/health/",
"test": "python manage.py test"
},
{
"name": "web",
"directory": "web",
"install": "npm install",
"start": "REACT_APP_API_URL=http://localhost:8010 PORT=${PORT} npm start",
"port": 3000,
"health": "/",
"test": "npm test",
"dependsOn": ["api"]
}
],
"browser": { "entry": "web" }
}Rails + Sidekiq
{
"services": [
{
"name": "web",
"directory": ".",
"install": "bundle install",
"start": "PORT=${PORT} bin/rails server",
"port": 3000,
"health": "/up",
"test": "bin/rails test"
},
{
"name": "worker",
"directory": ".",
"start": "bundle exec sidekiq",
"port": 7433,
"dependsOn": ["web"]
}
]
}How It Works
- Worktree isolation — Each feature gets its own git worktree branched from your base branch. The main repo stays clean.
- Port allocation — A registry at
~/.claude/stack-registry.jsontracks which ports are in use across all active features. Each worktree gets a unique slot so services never collide. - Config-driven services —
harness.jsondeclares your services, their start commands, health checks, and test commands. The plugin handles dependency ordering, parallel installs, and health check polling. - Real testing — The skill explicitly instructs Claude to test against real running services, never mocks. Browser verification uses Chrome DevTools MCP.
- State tracking — Each worktree gets a
.feature-meta.jsonand.stack/directory for PIDs, logs, and port assignments.
License
MIT
