Skip to main content
Glama
README.md
# SDD Orchestrator

A standalone [Model Context Protocol](https://modelcontextprotocol.io) server
that gives coding agents the right spec-driven-development (SDD) context at the
right moment.

For each task it:

- **routes** the task to the best-fitting SDD framework (OpenSpec, GitHub Spec
  Kit, BMAD, Kiro, or a house workflow) using explainable rules;
- **keeps lifecycle state** per feature and runs deterministic gate checks
  between phases, so gates are enforced rather than advisory;
- **assembles a context pack** per phase from a company-wide knowledge base,
  with app-scoped memory (ADRs, accepted specs, decisions) and explicit
  cross-app lookup.

The host agent (Claude Code, Cursor, or any MCP client) remains the only thing
that edits files, runs tests or spawns sub-agents. The server reads and writes
only its own database.

## Why

Coding agents tend to follow whatever process was in the prompt last, forget
why a past decision was made once the conversation that made it is gone, and
start writing code before checking whether a spec is actually complete. None
of that is a model problem; it is a missing place to keep process state
outside the agent's own context window. This server is that place: one
explainable choice of framework per task, phase gates that block on the
artifact's own text rather than on trust, and a knowledge base that survives
across sessions, branches and hosts.

## Use cases

- **Brownfield feature work.** "Add CSV export to the orders page" against a
  service with an existing `openspec/` directory routes to OpenSpec's
  `default` track: a proposal and delta spec gated on measurable acceptance
  criteria before `implement` starts.
- **Production incidents.** A hotfix routes to OpenSpec's `hotfix` track,
  which defers spec review until after the fix ships and adds a mandatory
  `learn` phase whose gate requires an `Incident Memory Proposal` section, so
  the agent has to write up the incident before the feature can archive.
- **Compliance-sensitive paths.** An app's policy can pin a framework by path
  glob (`**/payments/**` → BMAD) regardless of what `route_task` would
  otherwise pick; overriding that pin needs an explicit
  `policy_override_reason` recorded on `start_feature`.
- **Greenfield services.** A repository with no spec library and fewer than
  20 commits routes to Spec Kit's `default` track — the full seven-phase
  lifecycle from `specify` through `learn`.
- **Behaviour-preserving refactors.** OpenSpec and Spec Kit both ship a
  `refactor` track that requires characterization tests before any change and
  blocks the move out of `verify` if the evidence shows an existing test was
  modified (`max_existing_tests_modified: 0`).
- **Cross-app knowledge reuse.** `search_memory` with `scope: "company"` or a
  list of app slugs answers "how do other apps handle X" without pulling in
  every other app's private decisions by default.

## Status

v1 implemented per
[`docs/superpowers/specs/2026-09-10-sdd-orchestrator-design.md`](docs/superpowers/specs/2026-09-10-sdd-orchestrator-design.md)
and the plan in
[`docs/superpowers/plans/2026-09-10-sdd-orchestrator-v1.md`](docs/superpowers/plans/2026-09-10-sdd-orchestrator-v1.md).
Host verification status is tracked in
[`docs/verification/feature-matrix.md`](docs/verification/feature-matrix.md).
Deployment characteristics (pool sizing against embedding latency, long-lived
`GET /mcp` streams, migrations on CLI start-up) are in
[`docs/operations.md`](docs/operations.md); what a host may and may not assume
about a context pack is in
[`docs/verification/host-integration.md`](docs/verification/host-integration.md).
An interactive runtime architecture diagram (core components, primary path,
external dependencies, trust boundaries) is published at
[dbianco.github.io/sdd-orchestrator/architecture/sdd-orchestrator.architecture.html](https://dbianco.github.io/sdd-orchestrator/architecture/sdd-orchestrator.architecture.html).

## Development

```bash
npm install
npm run db:test:up                       # Postgres + pgvector on :55432
export SDD_TEST_DATABASE_URL=postgres://sdd:sdd@localhost:55432/sdd_test
npm test                                 # unit, integration and contract tests
npm run typecheck
npm run dev:stdio                        # server over stdio against SDD_DATABASE_URL
npm run admin -- app list                # sdd-admin without building
```

## Planned stack

| Component | Choice |
|---|---|
| Runtime | TypeScript on Node 22 |
| Transport | MCP over Streamable HTTP (shared) and stdio (local dev) |
| Storage | Postgres with pgvector, shipped via Docker Compose |
| Embeddings | Voyage AI by default, Ollama for development |
| Admin | `sdd-admin` CLI for ingesting packs, approving proposals, deprecating items |

## Usage examples

The interface below is the v1 contract.

### 1. Run the server

```bash
git clone https://github.com/dbianco/sdd-orchestrator
cd sdd-orchestrator
cp .env.example .env            # set VOYAGE_API_KEY, or SDD_EMBEDDING_PROVIDER=ollama
docker compose up -d            # Postgres + pgvector + sdd-orchestrator on :8080
curl http://localhost:8080/healthz
```

### 2. Seed the knowledge base (admin, once)

```bash
sdd-admin app register checkout --name "Checkout Service" --compliance
sdd-admin app update checkout --stack typescript,react,node --budget 6000
sdd-admin app set-policy checkout policy.json --reason "PCI scope: BMAD for payments paths"

sdd-admin ingest packs/openspec
sdd-admin ingest packs/spec-kit
sdd-admin ingest packs/bmad
sdd-admin ingest packs/quality-layer
sdd-admin ingest packs/stack-guides/react
sdd-admin ingest packs/company            # always-on constitution
```

`policy.json`:

```json
{
  "framework": null,
  "path_rules": [{ "glob": "**/payments/**", "framework": "bmad" }],
  "risk_paths": ["**/webhooks/**"]
}
```

### 3. Connect a host

Claude Code (`.mcp.json` in the workspace):

```json
{
  "mcpServers": {
    "sdd": { "type": "http", "url": "http://sdd.internal:8080/mcp" }
  }
}
```

Cursor (`.cursor/mcp.json`):

```json
{
  "mcpServers": {
    "sdd": { "url": "http://sdd.internal:8080/mcp" }
  }
}
```

Local development against a local database, over stdio:

```json
{
  "mcpServers": {
    "sdd": { "command": "sdd-orchestrator", "args": ["--stdio"] }
  }
}
```

### 4. Route a task and start a feature

The developer types a task; the host agent calls the server.

```
You: Add CSV export to the orders page.
```

The agent calls `route_task`:

```json
{
  "task_description": "Add CSV export to the orders page",
  "app": "checkout",
  "workspace": {
    "stack": ["typescript", "react"],
    "is_greenfield": false,
    "has_spec_library": true,
    "estimated_files": 4,
    "paths_touched": ["src/orders/"],
    "host": "claude-code"
  }
}
```

and receives:

```json
{
  "decision": {
    "framework": "openspec",
    "track": "default",
    "confidence": "high",
    "rule": "10-brownfield-small-medium",
    "reasons": ["brownfield (asserted by host)", "size: medium (4 files, one top-level dir)"],
    "high_risk": false,
    "policy_version": 3,
    "framework_pack_version": "1.0.0"
  },
  "attached_layers": [
    { "pack_name": "quality-layer", "pack_version": "1.0.0", "kind": "standard" },
    { "pack_name": "stack-guides/react", "pack_version": "1.0.0", "kind": "stack_guide" }
  ]
}
```

The agent shows the decision, the developer accepts, and the agent calls
`start_feature` with the same decision and `actor: "daniel"`. The result
carries a `feature_id` and the first context pack: header, always-on
constitution, the OpenSpec proposal template, retrieved app memory such as
`ADR-7 Exports go through the reporting service`, React guide sections, and
the stop conditions plus the checks the next gate will run.

`route_task` also returns a `routing_id`: the server records one routing
event per unit of work (deduplicated by `external_ref` or by task text), so
trivial fixes that never become features still show up in the admin. Pass
the `routing_id` to `start_feature`, and call `record_commit` after each
commit to link it to the work.

### 5. Advance through the gates

After the agent writes the proposal and the developer reviews it:

```json
{
  "feature_id": "f_01j9…",
  "actor": "daniel",
  "expected_phase": "specify",
  "target_phase": "implement",
  "artifacts": { "proposal.md": "…", "specs": "…", "tasks.md": "…" },
  "human_approved": true
}
```

A failing gate is a normal result, not an error:

```json
{
  "result": "fail",
  "findings": [
    { "check": "placeholder_scan", "severity": "blocker", "location": "proposal.md:41", "message": "marker TBD" },
    { "check": "measurable_criteria", "severity": "blocker", "location": "proposal.md:58", "message": "\"export must be fast\" has no threshold" }
  ]
}
```

The agent fixes the proposal and calls again. On pass it receives
`next_instructions` for `implement`. At the end of implementation the host
sends evidence with the move out of `verify`:

```json
{
  "expected_phase": "verify",
  "target_phase": "integrate",
  "evidence": {
    "tests": { "command": "npm test", "passed": 48, "failed": 0 },
    "lint": "pass",
    "security": { "status": "pass", "new_high": 0 },
    "files_changed": ["src/orders/export.ts", "src/orders/export.test.ts"],
    "implements": ["REQ-12"]
  }
}
```

If tests keep failing, the agent moves back from `verify` to `implement` with
`cycle_failed: true`. The third such move blocks the feature until a human
intervenes.

### 6. Look things up across apps

```json
{ "query": "how do other apps handle CSV encoding", "app": "checkout", "scope": "company" }
```

or, for named apps:

```json
{ "query": "rate limiting decisions", "app": "checkout", "scope": ["billing", "reporting"] }
```

### 7. Grow and retire memory

During the `learn` phase the agent proposes an ADR:

```json
{
  "feature_id": "f_01j9…",
  "actor": "daniel",
  "kind": "app_memory",
  "memory_type": "adr",
  "title": "ADR-9 CSV exports stream rather than buffer",
  "body": "…",
  "links": ["openspec/changes/archive/2026-09-10-orders-csv-export/"]
}
```

An admin reviews and retires knowledge:

```bash
sdd-admin proposals list
sdd-admin proposals approve p_42
sdd-admin deprecate checkout.adr.0003 --successor checkout.adr.0009 --reason "superseded by streaming"
sdd-admin deprecate-framework kiro --reason "no longer used"
sdd-admin reindex                       # after switching embedding model
```

### 8. Browse adoption and flow metrics (optional)

Set `SDD_ADMIN_TOKEN` and restart the server to turn on a read-only admin
page at `/admin` — feature counts, gate blocker counts by check, a
phase-to-phase flow heatmap, the memory-proposal queue, and a **Work** tab
listing everything routed (features and trivial fixes alike) with linked
commits, filterable by app and date range. It is absent entirely (a plain
404) when the token is unset.

```bash
export SDD_ADMIN_TOKEN=s3cret   # or set it in .env / docker-compose.yml
docker compose up -d
open http://localhost:8080/admin   # any username, password = SDD_ADMIN_TOKEN
```

## Repository layout

```
docs/operations.md        deployment and operating notes
docs/superpowers/specs/   design specifications
docs/superpowers/plans/   implementation plans
docs/verification/        host integration guide, feature matrix, walkthroughs, workspace-facts script
migrations/               node-pg-migrate schema
packs/                    seed knowledge packs (frameworks, quality layer, stack guides, company)
src/                      server, services, assembler, ingestion and CLI
test/                     unit, integration and contract tests
```

## License

MIT