examples / multi-repo product

A multi-repo product

Some products are several repos — an API and a web client — but one product. sdd handles a feature that spans them: one spec and plan grounded across the parts, and a build that fans out a PR per repo.

The layout

Keep the parts as sibling checkouts under one folder — that folder is the product root:

acme/                       ← run `sdd` from here
├── .sdd/project.json       ← the parts registry (written by `sdd product init`)
├── PRODUCT.md              ← the shared north star
├── api/                    ← part: its own git repo, its own CLAUDE.md
├── web/                    ← part
└── legacy-viewer/          ← reference part: context only, never edited

1 Scaffold the registry

cd ~/code/acme
sdd product init --name acme --reference legacy-viewer

Scans the child git repos and writes .sdd/project.json — each part owned (sdd builds features here) or reference (context/contracts only) — plus a PRODUCT.md scaffold to fill in:

{ "product": "acme",
  "parts": [
    { "name": "api", "path": "./api", "role": "owned",
      "repo": "acme/api", "contract": "openapi.json" },
    { "name": "web", "path": "./web", "role": "owned", "repo": "acme/web" },
    { "name": "legacy-viewer", "path": "./legacy-viewer", "role": "reference" }
  ] }

Add a contract to a part — like the API's openapi.json — and the other parts will build against it.

2 Spec — grounded across the parts

sdd spec "add CSV export of the items list"

The spec is grounded in the shared PRODUCT.md plus each part's own CLAUDE.md and contract, and the agent proposes a ## Touchpoints section — which parts this feature changes — for you to confirm:

## Touchpoints
- api
- web

The acceptance criteria come out cross-repo-aware: the API adds GET /items/export and updates openapi.json; the web client regenerates its API client from the updated contract and puts the button behind a feature flag — each side following its own conventions. (The reference part is correctly left out.)

3 Plan — per-part task groups

sdd plan csv-export-items

Scopes its grounding to the touched parts and decomposes into tasks tagged by part, ordered so a contract provider lands before its consumer:

### 1. [api] Add CSV serialization helper
### 2. [api] Add GET /items/export endpoint
### 3. [api] Document /items/export in openapi.json
### 4. [web] Regenerate API client from openapi.json
### 5. [web] Add "Export CSV" button, gated by a flag

4 Build — a PR per repo

On the board runner (see the board example), the build stage fans out: it groups the [part] tasks and builds each part in its own checkout, on an sdd/<slug> branch, opening a PR in that part's repo — then comments a summary on the feature ticket:

## sdd build — fan-out

2/2 part(s) opened a PR.

- api → PR #16 (tests green)   https://github.com/acme/api/pull/16
- web → PR #1  (tests green)   https://github.com/acme/web/pull/1

A part with no changes, failing tests, or no checkout opens no PR and is left for another pass. Merge stays yours — review and land the per-part PRs, contract provider first.

The board across repos

With a product registry, sdd board provisions gate labels in every owned part's repo and one org-level GitHub Project that aggregates all the parts' issues and PRs — so a feature spanning three repos is still one thing you watch, on one board.

Single-repo projects are completely unaffected by any of this: no project.json, no change in behaviour.

← The board runner Command reference →