Autonomous architect→plan→code→test→review→security-review loop exposed as a local MCP server
Project description
SDD Harness v2
An autonomous coding loop exposed as an MCP server for Claude Code and Codex. The harness drives a full engineering workflow — from architecture discussion to security review — and requires no Anthropic API key when running through host sampling.
map → architect ──[discuss]──► plan → code → test ──pass──► review → security_review → awaiting_confirmation ──confirm──► done
↑──fail (retry < MAX_RETRIES)──┘ └─changes──► code
Every phase is driven by the active host agent (Claude or Codex). The harness manages state, prompts, artifacts, and tests. You stay in the loop at architecture and security milestones.
Install
Option A — zero install with uvx (recommended)
No setup needed. uvx downloads and runs the package on demand.
Add to your Claude Code MCP settings (~/.claude/settings.json or the project's .mcp.json):
{
"mcpServers": {
"sdd-harness": {
"command": "uvx",
"args": ["sdd-harness"],
"timeout": 300000
}
}
}
Verify Claude sees it:
claude mcp list
# sdd-harness stdio uvx sdd-harness
Option B — pip install
pip install sdd-harness
Then use sdd-harness as the command:
{
"mcpServers": {
"sdd-harness": {
"command": "sdd-harness",
"timeout": 300000
}
}
}
Option C — Codex
Clone this repo. Codex picks up .codex-plugin/plugin.json from the checkout automatically — no further configuration needed.
Quickstart
1. Map the target project (once per project)
map_codebase(project_dir="/path/to/your-service")
This parses every source file, builds a SQLite symbol index, and writes an AI architecture narrative to .sdd/codebase/map.md. Run it once per project, then again after large structural changes.
You can also say: "Map the codebase for this project." — the host agent calls the tool automatically.
2. Add project skills (optional but recommended)
Skills teach the harness your project's conventions and are injected into every prompt. Create a skills directory in your target project and add skill files:
/path/to/your-service/.sdd/skills/
api-conventions.md
testing-patterns.md
security-checklist.md
Starter skills are in docs/skills-examples/ — copy and customise the ones you want. See Project Skills for the format.
3. Run a ticket
harness_architect(
task="add JWT auth middleware",
service="api-gateway",
project_dir="/path/to/your-service"
)
Then follow the harness prompts through each step.
The Workflow
Each ticket moves through six phases. The host agent does the thinking; the harness manages state and runs tests.
Phase 1 — Architect
harness_architect(task, service, thread_id?, project_dir?)
Returns an architecture prompt. The host agent produces:
- Problem framing — what we're solving and the hard constraints
- Candidate approaches — 2–3 options with genuine tradeoffs
- Recommended approach — direct and opinionated
- API / interface design — concrete method signatures, endpoint shapes
- Implementation concerns — risks, edge cases, known unknowns
Discuss with the human. Once the approach is agreed, move on.
Set REQUIRE_ARCH_APPROVAL=true in your environment to make the harness pause and wait for explicit human sign-off before proceeding.
Phase 2 — Plan
harness_code(thread_id, plan, arch_feedback?, project_dir?)
Pass the implementation plan you produced. Use arch_feedback to record any architectural decisions made during the discussion (e.g. "chose token-bucket over leaky-bucket for burst tolerance"). The harness saves it alongside the plan artifact.
Returns a coding prompt.
Phase 3 — Code
Write the implementation using the coding prompt. Pass it to:
harness_test(thread_id, code, project_dir?)
Phase 4 — Test
The harness runs:
- Validator scripts —
*.shscripts inVALIDATORS_DIR - Unit tests — command from
.sdd/config.json(if configured) - Integration tests — command from
.sdd/config.json(if configured)
Returns either:
- A review prompt if all tests pass
- A fix prompt if tests failed (up to
MAX_RETRIESattempts) - A failure summary if retries are exhausted
Phase 5 — Review
Write a code review covering correctness, quality, test coverage, and concerns. Pass it to:
harness_review(thread_id, review, project_dir?)
The symbol DB auto-refreshes here (fast mtime scan). Returns a security review prompt.
Phase 6 — Security Review
Write the security review covering threats, OWASP scan, auth gaps, secrets handling, and risk rating. Pass it to:
harness_security(thread_id, security_report, project_dir?)
The harness stops at awaiting_confirmation.
Confirmation
harness_confirm(thread_id, confirmed, feedback?, project_dir?)
confirmed=true→ task is doneconfirmed=false, feedback="..."→ reopens coding; retries reset; feedback is included in the next prompt
Project Skills
Skills are reusable engineering patterns stored in the target project at:
<project_dir>/.sdd/skills/*.md
Each skill file has a YAML frontmatter block followed by the skill content:
---
name: rest-endpoint-pattern
description: How to add a new REST endpoint in this project
phases: [architect, plan, code]
priority: high
---
## REST Endpoint Pattern
When adding an endpoint always:
1. Add route in routes/
2. Add service method in services/
3. Add repository method
4. Write an integration test
Frontmatter fields
| Field | Values | Default |
|---|---|---|
name |
string | filename stem |
description |
string | — |
phases |
[architect, plan, code, review, security_review] or [all] |
all phases |
priority |
high, medium, low |
medium |
Skills are filtered by phase, sorted by priority, and injected as a ## Project Skills block in the prompt. The history log records which skills were loaded at each step.
Starter skills are in docs/skills-examples/. Copy and customise:
| File | Phases | Based on |
|---|---|---|
api-rest-conventions.md |
architect, plan, code, review | Zalando REST guidelines |
testing-patterns.md |
plan, code, review | goldbergyoni/javascript-testing-best-practices |
security-checklist.md |
architect, code, security_review | OWASP CheatSheetSeries |
clean-code.md |
code, review | zedr/clean-code-python |
architecture-patterns.md |
architect | kamranahmedse/design-patterns-for-humans |
_TEMPLATE.md |
— | blank template |
Test Configuration
Structured unit and integration tests are configured per-project in .sdd/config.json:
{
"tests": {
"unit": {
"enabled": true,
"command": "pytest tests/unit -v --cov=src --cov-fail-under=80",
"timeout": 120
},
"integration": {
"enabled": false,
"command": "pytest tests/integration -v",
"timeout": 300,
"base_url": "http://localhost:8000"
}
}
}
Commands run in project_dir. The harness injects:
HARNESS_WORKFILE— path to the written code blobHARNESS_SERVICE— service name from the taskTEST_BASE_URL— integration only, frombase_urlin config
Unit tests run first, then integration tests. Either can be disabled independently. Validator scripts run regardless of this config.
Artifacts
Everything is written inside the target project, not the harness:
your-service/
└── .sdd/
├── codebase/
│ ├── map.md ← AI architecture narrative (commit this)
│ └── symbols.db ← SQLite symbol index (commit or gitignore)
├── skills/
│ └── *.md ← your project skill files (commit these)
└── tasks/
└── 29062026140509-add-jwt-auth/
├── task.md ← original task + service
├── architect.md ← architecture proposal
├── arch_feedback.md ← architectural decisions (if any)
├── plan.md ← implementation plan
├── code.md ← generated code (last attempt)
├── test_report.md ← PASS / FAIL + test output
├── review.md ← code review
├── security_review.md← security review
└── confirmation.md ← human confirmation / feedback
What to commit: codebase/map.md, skills/, and tasks/ give the whole team context on what was built, how the architecture was decided, and what concerns were raised. symbols.db can be committed (saves re-indexing on clone) or gitignored (rebuilt with map_codebase).
Scratch files excluded by the auto-created .sdd/.gitignore:
state.sqlite ← session state DB
validators.log ← raw validator output
_work.code ← scratch file passed to validators
Resuming After a Crash
Pass the same thread_id — the harness picks up from the last saved checkpoint:
harness_architect(
task="add JWT auth middleware",
service="api-gateway",
thread_id="29062026140509-add-jwt-auth-middleware", ← same ID
project_dir="/path/to/your-service"
)
If the latest session is not done, harness_architect refuses to open a new task and tells the host agent to resume the unfinished one instead.
Check the state of any run:
harness_status(thread_id="...", project_dir="/path/to/your-service")
Validators and Hooks
Validators
Shell scripts that gate the test → review transition. Set VALIDATORS_DIR in your environment:
# validators/lint.sh
#!/usr/bin/env bash
# $1 = path to generated code $2 = service name
pylint "$1" --fail-under=8
Non-zero exit triggers a retry. After MAX_RETRIES failures the run ends in failed.
Hooks
Shell scripts that fire before/after each phase. Set HOOKS_DIR in your environment. Full state JSON arrives on stdin:
# hooks/post_review.sh
#!/usr/bin/env bash
state=$(cat)
echo "$state" | jq -r '.history[]'
Suffix the filename -blocking to halt the graph on non-zero exit; otherwise failures are warnings only.
Available events:
pre_architect · post_architect · pre_plan · post_plan · pre_code · post_code · pre_test · post_test · pre_review · post_review · pre_security_review · post_security_review
Keeping the Map Fresh
The symbol DB auto-refreshes after every completed ticket (fast mtime scan, no model call). For manual refresh — after pulling a big diff or restructuring directories:
refresh_map(project_dir="/path/to/your-service")
| Situation | Action |
|---|---|
| First time on a project | map_codebase |
| After each ticket | automatic |
| After pulling upstream changes | refresh_map |
| After renaming / moving many files | map_codebase (full rebuild) |
| Narrative feels stale | map_codebase |
MCP Tools Reference
| Tool | Purpose |
|---|---|
map_codebase(project_dir) |
Full index + AI narrative. Run once per project. |
refresh_map(project_dir) |
Incremental update + regenerated narrative. |
write_map_narrative(project_dir, narrative) |
Save a narrative written by the host (used when sampling unavailable). |
harness_architect(task, service, thread_id?, project_dir?) |
Start or resume a ticket. Returns architecture prompt. |
harness_code(thread_id, plan, arch_feedback?, project_dir?) |
Save plan + arch decisions. Returns coding prompt. |
harness_test(thread_id, code, project_dir?) |
Run all tests. Returns review prompt or fix prompt. |
harness_review(thread_id, review, project_dir?) |
Save code review. Returns security review prompt. |
harness_security(thread_id, security_report, project_dir?) |
Save security review. Stops at awaiting_confirmation. |
harness_confirm(thread_id, confirmed, feedback?, project_dir?) |
Mark done or reopen with human feedback. |
harness_status(thread_id, project_dir?) |
Inspect the last saved checkpoint for a run. |
Environment Variables
Set these in your shell, a .env file in the working directory, or your system environment.
| Variable | Default | Purpose |
|---|---|---|
ANTHROPIC_API_KEY |
"" |
CLI fallback only. Not needed for Claude Code or Codex MCP usage. |
SDD_MODEL |
claude-sonnet-4-6 |
Model used for CLI fallback path. |
SDD_CHECKPOINTS_DIR |
~/.sdd-harness/checkpoints |
Override the default fallback checkpoints location. |
MAX_RETRIES |
3 |
Max code→test retry cycles. |
REQUIRE_ARCH_APPROVAL |
false |
When true, harness pauses at architecture phase for explicit human sign-off. |
VALIDATORS_DIR |
"" |
Directory of *.sh validator scripts. |
HOOKS_DIR |
"" |
Directory of lifecycle hook scripts. |
CLI Usage
For scripted, fully autonomous runs without an MCP host. Requires ANTHROPIC_API_KEY:
python -m sdd_harness.main "add health endpoint" "my-service" "29062026140509-add-health" \
/path/to/project /path/to/project/.sdd
The CLI runs the full graph: map → architect → plan → code → test → review → security_review, then stops at awaiting_confirmation.
Publishing to PyPI
To make the harness available to anyone via pip install sdd-harness or uvx sdd-harness:
pip install build twine
python -m build
twine upload dist/*
After publishing, users need zero local setup — uvx sdd-harness downloads and runs the latest version automatically.
Development
git clone https://github.com/Jackson1996vn/sdd-harness-v2
cd sdd-harness-v2
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
# Run all tests — no API key needed
pytest tests/ -v
# Run a single test file
pytest tests/test_routing.py -v
How It Works
Architecture
map → architect → plan → code → test ──pass──► review → security_review ──► awaiting_confirmation
↑──fail (retry)──┘
The graph is a LangGraph state machine compiled with a SQLite checkpointer. The same thread_id resumes from the last checkpoint after any crash or interruption.
Each node: runs pre_<phase> hooks → does its work → updates state → runs post_<phase> hooks.
Symbol DB (SQLite)
The codebase map is backed by SQLite:
- Indexed lookups — symbol queries are O(log n) regardless of codebase size
- Targeted context —
map_nodefetches only symbols relevant to the current task - Incremental refresh — re-parses only files whose mtime changed (typically <50ms after a ticket)
Languages with AST-level parsing: Python, TypeScript, JavaScript, Go, Rust. Regex fallback for everything else.
No API Key — How Model Calls Work
Claude Code / Codex (your session)
└── spawns sdd-harness via stdio
└── harness tool called
└── ctx.sample("architect this task...")
└── routed back to the MCP host session
host agent executes the prompt
result returned to harness
Every model call is delegated back to the active host session via sampling. The harness never contacts the Anthropic API directly when running through Claude Code or Codex.
Legacy
legacy/watcher.sh — the original bash implementation, kept for reference.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sdd_harness-0.2.1.tar.gz.
File metadata
- Download URL: sdd_harness-0.2.1.tar.gz
- Upload date:
- Size: 45.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
004ec1b5a6ac7fb2b4d3cd42cfe20cdb14f8b4eb31dc309a36baf493fd1111f3
|
|
| MD5 |
7223ba498678b067be2efb9c9d75dcf5
|
|
| BLAKE2b-256 |
6990f47160610099add4bace34cf281f5700c97ad58453c75e202258e335e15c
|
File details
Details for the file sdd_harness-0.2.1-py3-none-any.whl.
File metadata
- Download URL: sdd_harness-0.2.1-py3-none-any.whl
- Upload date:
- Size: 43.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3ee4d3b41a375dc4d8f493bab162bd6b96b850fe6856ae964e49354a6cda50d4
|
|
| MD5 |
32c36e3527db910f71e7743a53b23c21
|
|
| BLAKE2b-256 |
863917e4f1b387ebc7fe90481cfeed3eda0761e4521f6825db1978294cc463e6
|