---
name: brownfield-onboard
description: "Onboard an existing-WIP product to AutoPilot conventions. Chains /gsd-ingest-docs (ingest existing ADRs/PRDs/SPECs) -> /gsd-map-codebase (inventory existing implementation) -> reconciliation subagent (compare to AutoPilot conventions, archive conflicts) -> /wedge-synthesis --from-existing (emit capabilities.yaml with retroactive MERGED status on existing code) -> hand to /autopilot <product>. Activates on /brownfield-onboard <product>, retrofit <product>, onboard existing codebase, migrate legacy product to AutoPilot, brownfield ingestion."
---

# /brownfield-onboard — Onboard an existing-WIP product to AutoPilot

You take a product that already has a codebase (partial or complete),
existing planning docs (ADRs, PRDs, SPECs, roadmaps), and pre-AutoPilot
conventions — and onboard it to AutoPilot's substrate one capability at a
time, with no big-bang rewrites.

The output: a `PLATFORM/<product>/` tree that looks like a new AutoPilot
product (capabilities.yaml + .planning/ + scope-fenced CLAUDE.md) but with
existing code retroactively marked `status: MERGED` and pre-AutoPilot
planning docs archived (not deleted) to `.planning/archive/pre-autopilot/`.

After this skill completes, `/autopilot <product>` picks up the next
PLANNED capability and runs the standard composed loop.

## Why this is composition, not native

AutoPilot does NOT implement ingestion logic. GSD already ships
`/gsd-ingest-docs` (bootstrap or merge .planning/ from existing docs with
conflict detection), `/gsd-map-codebase` (parallel codebase analysis →
.planning/codebase/), and `/gsd-import` (external plan ingestion). This
skill composes them into a brownfield-specific pipeline with AutoPilot's
capability emission + archive policy.

## Invocation

```
/brownfield-onboard <product>                                   # full pipeline
/brownfield-onboard <product> --resume                          # resume after operator HITL
/brownfield-onboard <product> --phase A|B|C|D                   # run a specific phase only
/brownfield-onboard <product> --dry-run                         # outline only, no edits
```

## Inputs (REQUIRED — STOP if missing)

| Input | Source | If missing |
|---|---|---|
| `PLATFORM/<product>/` tree exists | repo | STOP — this skill is for EXISTING products; use /platform-init for greenfield |
| At least one of: `.planning/`, ADR / PRD / SPEC docs at known locations | repo | STOP — nothing to ingest |
| Operator has reviewed AutoPilot's INTENT / DOCTRINE / PRD conventions | doc | WARN — proceed but flag in INGEST-REPORT.md |

## Steps

### Step 1 — Bootstrap & validate inputs

```sh
AUTOPILOT_ROOT=$(git rev-parse --show-toplevel)/PLATFORM/AutoPilot
[ -f "$AUTOPILOT_ROOT/.envrc" ] && . "$AUTOPILOT_ROOT/.envrc"

PRODUCT="$1"
[ -z "$PRODUCT" ] && exit "STOP: product name required"
PRODUCT_DIR="$(git rev-parse --show-toplevel)/PLATFORM/$PRODUCT"
[ -d "$PRODUCT_DIR" ] || exit "STOP: PLATFORM/$PRODUCT/ does not exist (this skill is for EXISTING products; use /platform-init for greenfield)"

# Operator may pass --read-only (Level-3 In-flight preview mode).
READ_ONLY=0
for arg in "$@"; do
  [ "$arg" = "--read-only" ] && READ_ONLY=1
done

if [ "$READ_ONLY" = "1" ]; then
  INFO: "READ-ONLY mode active — output stays at .planning-staged/, no promotion to .planning/."
  INFO: "To promote later, operator must re-run without --read-only (or with explicit --apply)."
fi

# Pre-AutoPilot artifact inventory (anything to ingest?)
# Use robust counts (not `... | head -1 && echo 1`) because `head` exits 0
# even on empty input, which would falsely set HAS_DOCS=1.
HAS_PLANNING=$( [ -d "$PRODUCT_DIR/.planning" ] && echo 1 || echo 0 )
DOCS_COUNT=$(find "$PRODUCT_DIR" -maxdepth 3 -type f \
                \( -iname "ADR*.md" -o -iname "PRD*.md" -o -iname "SPEC*.md" -o -iname "ROADMAP*.md" \) \
                2>/dev/null | wc -l | tr -d ' ')
HAS_DOCS=$( [ "$DOCS_COUNT" -gt 0 ] && echo 1 || echo 0 )
[ "$HAS_PLANNING" = "0" ] && [ "$HAS_DOCS" = "0" ] && \
  exit "STOP: no .planning/ directory, no ADR/PRD/SPEC/ROADMAP docs detected — nothing to ingest"
```

### Step 2 — Phase A: Ingest existing planning (dispatch /gsd-ingest-docs)

Per WirePerfect User Journey Act 2 + GSD `/gsd-ingest-docs` doctrine:

```
Skill: /gsd-ingest-docs \
  --source-dirs "$PRODUCT_DIR/.planning,$PRODUCT_DIR/docs" \
  --target-dir "$PRODUCT_DIR/.planning-staged/" \
  --conflict-detection on \
  --output-report "$PRODUCT_DIR/.planning-staged/INGEST-REPORT.md"
# GSD parallel-spawns classifier agents to label each doc (ADR / PRD / SPEC /
# DOC / UNKNOWN), then synthesizes to a unified .planning/ tree. Conflict
# detection runs against AutoPilot's required artifacts (INTENT, DOCTRINE,
# PRD, capabilities.yaml schema). Flags any decisions that conflict with
# AutoPilot conventions.
```

Operator gate (single AskUserQuestion):
```
INGEST-REPORT.md shows N conflicts, M auto-resolved.
Proceed to Phase B (codebase map), or pause for HITL?
[PROCEED / PAUSE / ABORT]
```

### Step 3 — Phase B: Inventory existing codebase (dispatch /gsd-map-codebase)

```
Skill: /gsd:map-codebase \
  --target "$PRODUCT_DIR/" \
  --output-dir "$PRODUCT_DIR/.planning-staged/codebase/" \
  --focus-areas tech,arch,quality,concerns
# Parallel mapper agents produce .planning/codebase/ with:
#   - tech.md (languages, frameworks, package managers, build tools)
#   - arch.md (module structure, layering, entry points, public surface)
#   - quality.md (test coverage, lint status, type-check status, dead code)
#   - concerns.md (security flags, secrets-in-code, hard-coded paths, TODOs)
```

### Step 3.5 — Survey-report + scale gate (B2: the ideation seam)

**Why this step exists (INTEGRATION-DESIGN Output #2):** the old A→B→C→D flow went from
"what exists" straight to "what the capabilities are" and **never asked where the product
should go** — no ideation. Brownfield is ~95% of real entries (`BROWNFIELD-DEFAULT.md`), so
the missing ideation gap was the common case. This step closes it at the B↔C seam.

**Always do two things, then branch:**

1. **Survey-report** — show the operator what Phase B's map found (from
   `.planning-staged/codebase/` — tech / arch / quality / concerns, one-line each).
2. **Ask scale** — the in-house-first / hyperscale-aware question (the gate ASKS; the anchor
   itself is committed inside `/ideate-wedge`).

Then branch (**default = run the brainstorm; skip is the explicit opt-in** — so we don't
recreate the very ideation gap we're closing):

```
Phase B map ready: <N modules, M gaps, K concerns>. Scale: in-house wedge now, hyperscale horizon?
Is this a NEW DIRECTION (re-ideate the wedge) or a MECHANICAL RETROFIT (you already know the wedge)?
  [NEW DIRECTION (default) / MECHANICAL RETROFIT]
```

- **NEW DIRECTION (default)** → delegate to the **same** shared skill greenfield uses, seeded
  with the codebase map (no duplicated brainstorm logic):
  ```sh
  Skill: /ideate-wedge \
    --hypothesis "$HYPOTHESIS_OR_INFERRED" \
    --scratch-dir "$PRODUCT_DIR/.planning-staged/" \
    --codebase-map "$PRODUCT_DIR/.planning-staged/codebase/"
  # grounded bluesky: the brainstorm is seeded with what already exists.
  # Output OFFICE-HOURS-DESIGN-v1.md flows into Phase D wedge-synthesis --validated-thesis.
  ```
- **MECHANICAL RETROFIT** → skip ideation, proceed straight to Phase C / Phase D
  (`wedge-synthesis --from-existing`) as before. The operator already knows the wedge.

**Guard:** never silently skip the brainstorm. If the operator doesn't choose, default to
NEW DIRECTION (re-ideate) — closing the gap is the whole point of this step.

### Step 4 — Phase C: Reconcile against AutoPilot conventions

Spawn a reconciliation subagent that compares ingested docs + codebase map
to AutoPilot's required artifacts:

| Required AutoPilot artifact | Reconcile from |
|---|---|
| `.planning/INTENT.md` | Synthesize from ingested PRDs + roadmap context |
| `.planning/DOCTRINE.md` | Copy AutoPilot template; flag any conflicting conventions found in existing docs |
| `.planning/PRD.md` | Use highest-rank ingested PRD; merge supplementary PRDs into it |
| `.planning/capabilities.yaml` | Phase D emits this from wedge-synthesis |
| `.planning/ARCHITECTURE.md` | Synthesize from codebase/arch.md; lock_hash computed from the synthesized doc |
| `CLAUDE.md` (scope-fenced) | Copy template; populate scope-fence paths from codebase/arch.md |

Conflicting pre-AutoPilot docs (ones that contradict AutoPilot conventions
AND don't have a clear merge path) get archived to:

```
PLATFORM/<product>/.planning/archive/pre-autopilot/<YYYY-MM-DD>/
  ├── <original-doc-name>.md
  └── WHY-ARCHIVED.md   # explains the conflict + why this doc was superseded
```

Operator gate:
```
Reconciliation summary: K artifacts synthesized, J docs archived, I conflicts unresolved.
Review the archive list before proceeding to Phase D?
[REVIEW-AND-PROCEED / SKIP-REVIEW-PROCEED / ABORT]
```

### Step 5 — Phase D: Emit capabilities.yaml (dispatch /wedge-synthesis --from-existing)

```
Skill: /wedge-synthesis \
  --from-existing \
  --product "$PRODUCT" \
  --planning-dir "$PRODUCT_DIR/.planning-staged/" \
  --codebase-map "$PRODUCT_DIR/.planning-staged/codebase/" \
  --output "$PRODUCT_DIR/.planning-staged/capabilities.yaml"
# If Step 3.5 took the NEW DIRECTION branch, also pass the ideation output so the
# re-ideated wedge flows into capability synthesis (same flag greenfield uses):
#   --validated-thesis "$PRODUCT_DIR/.planning-staged/OFFICE-HOURS-DESIGN-v1.md"
# (MECHANICAL RETROFIT branch omits it — no re-ideation occurred.)
# --from-existing mode emits capabilities.yaml with:
#   - existing code modules -> status: MERGED with retroactive merge_sha
#     (computed from git blame; nearest merge commit per file)
#   - unfinished work in ingested PRDs/SPECs -> status: PLANNED
#   - lock_hash bound to the newly synthesized ARCHITECTURE.md
#   - dep graph reverse-engineered from import/export topology in codebase/arch.md
```

Validate the emitted capabilities.yaml against AutoPilot's schema:

```sh
python -c "
import yamale
s = yamale.make_schema('$AUTOPILOT_ROOT/.planning/capabilities.schema.yaml')
d = yamale.make_data('$PRODUCT_DIR/.planning-staged/capabilities.yaml')
yamale.validate(s, d)
print('PASS')
"
```

If schema invalid → STOP, surface errors, operator fixes manually.

### Step 6 — Architecture stress-test (sanity check)

```
Skill: /architecture-stress-test \
  --architecture "$PRODUCT_DIR/.planning-staged/ARCHITECTURE.md" \
  --capabilities "$PRODUCT_DIR/.planning-staged/capabilities.yaml"
# Adversarial review: does the synthesized architecture actually meet every
# capability's acceptance criteria? Reverse-engineered architectures often
# miss invariants that were implicit in the original implementation.
```

If stress-test fails → BLOCKED-ARCH on flagged capabilities, operator HITL.

### Step 7 — Promote staged planning to live + commit

```sh
if [ "$READ_ONLY" = 1 ]; then
  # Read-only short-circuit: at this point READ_ONLY=1 means operator passed --read-only.
  INFO: "READ-ONLY mode: skipping promotion to live .planning/"
  INFO: "Staged output remains at: $PRODUCT_DIR/.planning-staged/"
  INFO: "Operator review next steps:"
  INFO: "  1. Inspect $PRODUCT_DIR/.planning-staged/INGEST-REPORT.md"
  INFO: "  2. Inspect $PRODUCT_DIR/.planning-staged/{INTENT,DOCTRINE,PRD,ARCHITECTURE}.md"
  INFO: "  3. To promote: re-run /brownfield-onboard $PRODUCT (no --read-only flag)"
  exit 0
fi
# (original mv + git checkout + git commit logic unchanged below this guard)

# Move staged .planning/ into the live position (replacing any conflicting
# pre-AutoPilot .planning/ entries that weren't archived — those are bugs
# in Phase C, surface immediately)
mv "$PRODUCT_DIR/.planning-staged/"* "$PRODUCT_DIR/.planning/"
rmdir "$PRODUCT_DIR/.planning-staged"

# Stage + commit on a brownfield-onboard branch
git checkout -b "${PRODUCT}/brownfield-onboard-$(date +%Y%m%d)"
git add "$PRODUCT_DIR/"
git commit -m "feat(${PRODUCT}): brownfield onboard to AutoPilot conventions

Generated by /brownfield-onboard:
  - Ingested pre-AutoPilot planning docs via /gsd-ingest-docs
  - Inventoried codebase via /gsd-map-codebase
  - Synthesized .planning/{INTENT,DOCTRINE,PRD,ARCHITECTURE}.md
  - Emitted capabilities.yaml with retroactive MERGED status on existing code
  - Archived N conflicting pre-AutoPilot docs to .planning/archive/pre-autopilot/

Ready for /autopilot ${PRODUCT}."
```

### Step 8 — Hand to /autopilot

```
INFO: brownfield onboarding complete. Next steps:
  1. Review .planning/PRD.md, .planning/ARCHITECTURE.md, .planning/capabilities.yaml
  2. Inspect .planning/archive/pre-autopilot/ to confirm nothing important was archived
  3. Approve the ARCHITECTURE.md lock_hash (sets the L2 modest-extension boundary)
  4. Run: /autopilot ${PRODUCT}
     → picks the highest-priority PLANNED capability and starts the standard composed loop
```

## Failure modes & escapes

- **Ingest conflict storm (>10 unresolved):** STOP at Step 2 operator gate, hand-resolve in `.planning-staged/INGEST-REPORT.md`, re-run with `--resume`.
- **Architecture reverse-engineering fails L2 stress-test:** BLOCKED-ARCH escalation, operator HITL on the flagged capabilities. Common cause: existing code has invariants that weren't documented; either add them to ARCHITECTURE.md §11 appendix or split the capability.
- **Capability emission misses an existing module:** operator adds capability manually to capabilities.yaml, marks MERGED with current SHA. /brownfield-onboard's reconciler is best-effort; gaps are recoverable.
- **Pre-AutoPilot docs are too stale to ingest cleanly (>50% conflict rate):** consider a full archive + greenfield re-init via `/platform-init` instead.
- **--read-only abort:** Operator runs `/brownfield-onboard <product> --read-only`. Steps 2-6 execute normally; Step 7 short-circuits before any `mv` or `git checkout -b`. Output remains at `$PRODUCT_DIR/.planning-staged/`. No mutation to live `.planning/` or git history. Use case: Level-3 In-flight products (WirePerfect) where operator wants a preview before committing.

## Relationship to other skills

- **/gsd-ingest-docs** — Phase A workhorse; classifies + synthesizes existing docs
- **/gsd:map-codebase** — Phase B workhorse; parallel codebase analysis
- **/wedge-synthesis** (with `--from-existing` flag) — Phase D capabilities.yaml emitter
- **/architecture-stress-test** — Phase E sanity check
- **/platform-init** — greenfield equivalent (this skill's "new" sibling)
- **/autopilot** — the loop this skill hands off to

## What this skill explicitly does NOT do

- Does NOT modify the existing codebase. Reads only.
- Does NOT delete pre-AutoPilot planning docs. Archives them to `.planning/archive/pre-autopilot/<date>/` with `WHY-ARCHIVED.md` notes.
- Does NOT make architectural decisions. The reconciliation subagent surfaces conflicts; the operator decides at the Phase C gate.
- Does NOT auto-validate the synthesized ARCHITECTURE.md against runtime. That's `/architecture-stress-test`'s job (Step 6).
- In --read-only mode: Does NOT promote `.planning-staged/` to `.planning/`. Does NOT create a branch. Does NOT commit. Steps 2-6 still execute (ingest + map + reconcile + capabilities emit + stress-test all run against the staged tree).

## Doctrine fidelity

- [`AGENTS.md`](../../../../AGENTS.md) — Kohlex doctrine (scope-fence enforcement, archive-don't-delete)
- [`PLATFORM/AutoPilot/.planning/PRD.md`](../../.planning/PRD.md) line 31 — "AutoPilot does NOT replace GSD, Superpowers, GStack… It composes them."
- [`docs/doctrine/WIREPERFECT-USER-JOURNEY.md`](../../docs/doctrine/WIREPERFECT-USER-JOURNEY.md) — the journey assumes greenfield; this skill is the brownfield counterpart so legacy products (WirePerfect, future retrofits) can join the AutoPilot substrate.
- [`docs/recipes/brownfield-onboard.md`](../../docs/recipes/brownfield-onboard.md) — generic operator recipe
- [`docs/recipes/retrofit-wireperfect.md`](../../docs/recipes/retrofit-wireperfect.md) — WirePerfect-specific operator manual (first user of this skill)
