Metadata-Version: 2.4
Name: sdd-harness
Version: 0.2.0
Summary: Autonomous architect→plan→code→test→review→security-review loop exposed as a local MCP server
License-Expression: MIT
Keywords: mcp,claude,codex,langgraph,ai,coding-agent
Requires-Python: >=3.11
Description-Content-Type: text/markdown
Requires-Dist: langgraph>=0.2.0
Requires-Dist: langgraph-checkpoint-sqlite>=1.0.0
Requires-Dist: anthropic>=0.40.0
Requires-Dist: python-dotenv>=1.0.0
Requires-Dist: fastmcp>=2.0.0
Requires-Dist: aiosqlite>=0.19.0
Provides-Extra: dev
Requires-Dist: pytest>=8.0.0; extra == "dev"

# 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`):

```json
{
  "mcpServers": {
    "sdd-harness": {
      "command": "uvx",
      "args": ["sdd-harness"],
      "timeout": 300000
    }
  }
}
```

Verify Claude sees it:

```bash
claude mcp list
# sdd-harness  stdio  uvx sdd-harness
```

### Option B — pip install

```bash
pip install sdd-harness
```

Then use `sdd-harness` as the command:

```json
{
  "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/`](./docs/skills-examples/) — copy and customise the ones you want. See [Project Skills](#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:
1. **Validator scripts** — `*.sh` scripts in `VALIDATORS_DIR`
2. **Unit tests** — command from `.sdd/config.json` (if configured)
3. **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_RETRIES` attempts)
- 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 **done**
- `confirmed=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:

```markdown
---
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](https://github.com/zalando/restful-api-guidelines) |
| `testing-patterns.md` | plan, code, review | [goldbergyoni/javascript-testing-best-practices](https://github.com/goldbergyoni/javascript-testing-best-practices) |
| `security-checklist.md` | architect, code, security_review | [OWASP CheatSheetSeries](https://github.com/OWASP/CheatSheetSeries) |
| `clean-code.md` | code, review | [zedr/clean-code-python](https://github.com/zedr/clean-code-python) |
| `architecture-patterns.md` | architect | [kamranahmedse/design-patterns-for-humans](https://github.com/kamranahmedse/design-patterns-for-humans) |
| `_TEMPLATE.md` | — | blank template |

---

## Test Configuration

Structured unit and integration tests are configured per-project in `.sdd/config.json`:

```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 blob
- `HARNESS_SERVICE` — service name from the task
- `TEST_BASE_URL` — integration only, from `base_url` in 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:

```bash
# 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:

```bash
# 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`:

```bash
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`:

```bash
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

```bash
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_node` fetches 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.
