---
name: harden
description: "Use after a working prototype is locked and the user says 'codify', 'harden', 'ready to productionize', 'extract decisions', 'time to build for real', or runs /feature past the prototype phase. Extracts architecture, ADRs, design system, slice graph, and convention/gotcha promotions FROM the working prototype — does not invent them. Skip if prototype is still iterating — re-iterate or restart instead."
---

# Harden

## Overview

A working prototype contains real decisions: what data shape works, which interactions feel right, where the seams are, what failures recur. Production code needs those decisions written down before it can be built. This skill codifies — it does not invent.

**Core principle:** the prototype is the verification; this skill is the transcription. Every output cites the prototype file, wireframe state, or iteration gotcha it derives from. ADRs that can't cite a concrete prototype decision are flagged for review — they may be premature.

**Announce at start:** "I'm using the harden skill to codify the prototype into production plans."

## When to Use

- Right after the user locks the prototype phase ("satisfied — go to production"). Triggered by the prototype-lock event or by an explicit invocation.
- Ad-hoc when a feature's prototype is mature enough that production planning should begin while iteration continues at low intensity.

**Do NOT skip when:**
- The prototype "feels obvious" — obvious shape still needs an architecture document so the production build is testable against it
- The team is in a hurry — skipping codification means the production build is improvising; the gates downstream rely on this skill's outputs as inputs

**Do NOT use this skill for:**
- Generating architecture from scratch with no prototype (use `plan-architecture` directly during a non-prototype-driven flow)
- Reviewing existing architecture docs (that's `craft-reviewer` and `code-reviewer`'s job)
- Building the production code itself (that's the production-build phase, after this skill closes)

## What harden produces (multi-output)

This is an orchestrator skill. A single invocation may produce all of the below:

| Output | Where | Purpose |
|---|---|---|
| Architecture file(s) | `aiwiki/architecture/{topic}.md` (one per subsystem) | The system shape, components, boundaries, tradeoffs as observed in the prototype |
| ADRs | `aiwiki/decisions/{nnnn}-{slug}.md` | Production-only decisions that the prototype implicitly made; needs explicit recording (with `review:` block per the adversarial-review trigger list) |
| Convention additions | `aiwiki/conventions/{slug}.md` | Production-surface conventions the frontend prototype didn't cover (API route handler naming, error shapes, etc.) |
| Gotcha addenda | `aiwiki/gotchas/{date}-{slug}.md` (existing files updated) | Re-evaluates Phase 4 gotchas under production scope; adds "still applies under server-rendered hydration" or similar production-only notes |
| Production task graph | `.forge/work/{type}/{name}/tasks.md` + `slice_graph` field in manifest | What needs to be built to take the prototype to production |
| Session entry | `aiwiki/sessions/{date}-{slug}.md` | Index linking everything produced this session |

The expected total is short: ~200-400 lines across all architecture files combined, ~3-8 ADRs, a slice graph with explicit dependencies. Not 1000+ lines of monolithic plan.

## What harden does NOT do

- Does NOT write production code (Phase 6's job)
- Does NOT run gates (LINT runs on the wiki output; reachability runs on production code later)
- Does NOT modify the prototype (it's the source of truth — leave it alone)
- Does NOT pre-promote raw entries from `aiwiki/raw/` to typed pages (dream's job at phase close)
- Does NOT skip the adversarial-review step on ADRs — every production ADR is reviewed inline at Step 2: harden runs the review pass and records reviewer, objections, resolutions, and verdict in the ADR `review:` block before promoting to `accepted`. If Codex is configured (`protocols/codex.md`), the review pass may dispatch Codex in verify mode; otherwise Claude performs the pass directly.

## Inputs

| Source | Required | Purpose |
|---|---|---|
| Locked prototype directory | yes for stacks where prototype is active (`vite-react`, `nextjs`, `existing-repo`, `python-fastapi`, `cli`, `go-service`); no for `stack: none` | The codebase being codified |
| Wireframe single-HTML | yes for UI stacks (`vite-react`, `nextjs`, `existing-repo`); no for non-UI (`cli`, `go-service`, `python-fastapi`, `none`) — read the executable verification surface from the prototype (curl fixtures / grpcurl traces / `/docs` playground / working binary + demo) instead | Visual spec; design-system extraction source |
| Concept slides | yes | High-level intent context |
| `aiwiki/gotchas/` (Phase 4 entries) | if present | Prototype iteration gotchas to re-evaluate under production scope |
| `aiwiki/conventions/` (Phase 4 entries) | if present | Conventions captured during prototype iteration |
| Existing `aiwiki/architecture/` | if present | Prior architecture this work extends or supersedes |
| Existing `aiwiki/decisions/` | if present | Prior ADRs to check for supersession |
| `references/common/coding-standards.md` + `references/{lang}/standards.md` | yes | Production standards loaded as constraints on codified output |
| `rules/common/{testing,quality-gates,git-workflow}.md` | yes | Phase-conditional rules that activate from this phase forward |
| Manifest at `.forge/work/{type}/{name}/manifest.yaml` | yes | Target for slice graph + task list output |

## Process

### Step 0: locate inputs

```
Repo root: `git rev-parse --show-toplevel` or `${CLAUDE_PROJECT_DIR}`
Manifest: the in-progress manifest under `.forge/work/*/*/manifest.yaml`. Multiple in flight = ask user.
Stack: from manifest's `artifacts.prototype.stack:` (UI stacks: vite-react / nextjs / existing-repo. Non-UI: cli / go-service / python-fastapi. None: no prototype phase ran).
Prototype dir: from manifest's `prototype_path` field, or default `pocs/{name}-prototype/`. Skip the read for `stack: none`.
Wireframe path: from manifest's `wireframe_path` field, or default `pocs/{name}-wireframe/index.html`. Only required when stack is UI-shaped; non-UI stacks skip this — the prototype's executable verification surface (curl fixtures / grpcurl traces / `/docs` playground / CLI demo script) is the design-system + interaction source instead.
```

If `phase_plan.prototype: active` for this work item and the manifest does not yet have `artifacts.prototype.locked_at`, surface the gap and stop — this skill runs after prototype lock. If `stack: none` (no prototype phase by design), this check is skipped; harden derives architecture from concept slides + requirements + the existing codebase directly.

**aiwiki prerequisite.** Harden writes every output (architecture, ADRs, conventions, gotchas, oracles, session entry) into `aiwiki/`. If `project.aiwiki_enabled: false` in `.claude/CLAUDE.md` (or `aiwiki/` does not exist), surface to the user before doing any work:

```
Harden depends on the aiwiki knowledge layer — it writes architecture, ADRs,
conventions, and oracles there for Phase 6's TDD slices and quality gates to
read. The current project has aiwiki disabled.

Options:
  1. Enable aiwiki (re-run /setup and pick Y) — recommended for projects
     graduating from prototype to production.
  2. Skip harden AND skip codify — flip `phase_plan.codify: skipped` in the
     work manifest. Phase 6 (build-tdd) honors `codify: skipped` and proceeds
     without oracle lookups; otherwise build-tdd halts at its Step 1.6 oracle
     check (no oracles to map). The prototype stays the source of truth;
     architecture decisions live only in code + prototype state.

Which do you want?
```

Wait for the user's response. If they pick Option 2, update the manifest immediately: set `phase_plan.codify: skipped` and `artifacts.codify.skipped_reason: "aiwiki layer disabled — no oracle/ADR/architecture writes"`. Then return without doing harden's work. Do NOT silently degrade — both halves of Option 2 (skip harden AND mark codify skipped) must land together so build-tdd's contract stays consistent.

### Step 1: dispatch the prototype-codifier subagent

The bulk of the codification work happens in a separate context window so the main session stays lean.

Dispatch `prototype-codifier` with:
- Prototype directory path
- Wireframe HTML path
- Concept slides path
- Path lists for existing `aiwiki/gotchas/`, `aiwiki/conventions/`, `aiwiki/architecture/`
- Manifest path (writes target)

The subagent returns a structured report listing:
- Proposed architecture files (with topics + content)
- Proposed ADRs (with subjects + draft content, marked `status: proposed`)
- Convention additions
- Gotcha addenda
- Slice graph + task list

The subagent does NOT write the files itself — it returns the proposals. The main session writes them after step 2.

### Step 2: invoke adversarial review on each proposed ADR

Each proposed ADR represents a decision that's hard to reverse — by definition, ADR-worthy. The `prototype-codifier` agent only proposes ADRs that match the adversarial-review trigger list (the canonical list lives in `agents/prototype-codifier.md` Phase 4); every proposal therefore arrives flagged for review.

For each proposed ADR, run an adversarial review pass and write a structured `review:` block (reviewers, objections, resolutions, verdict) into the draft. The review is performed inline within harden: interrogate the decision against the trigger list's failure modes, surface objections explicitly, and either record resolutions or escalate to the user. If Codex is configured (`protocols/codex.md`), dispatch it in verify mode to perform the review pass and merge its findings; otherwise Claude runs the pass directly.

Only ADRs with `verdict: approved` get written as `status: accepted`. ADRs with `verdict: escalate` are surfaced to the user for resolution before the phase closes. ADRs with `verdict: reject` are dropped from the proposal set.

### Step 2.5: test-oracle capture

Snapshot the prototype's behavior — route renders, key interactions, golden output traces — as integration-test oracles. Production code in Phase 6 must pass these.

This is the SDLC's load-bearing wiring-test backbone — without it, mock-heavy unit tests pass while real integration breaks at the wiring boundary (CLI ↔ filesystem, process exec, manifest I/O, external services). Capture at least:

- **Route/render oracles** for every page or HTTP endpoint the prototype exposes (status + body shape + critical DOM/JSON nodes)
- **Interaction oracles** for the click-through paths the wireframe demos (sequence of state transitions and observable outputs)
- **Golden output traces** for any pipeline, transform, or CLI command in the prototype (input fixture → expected output, byte- or structure-exact)

Write the oracles to `aiwiki/oracles/{slug}.md` (one per slice or subsystem) with: source citation (prototype file + sha7), capture method (manual click-through, recorded fixture, snapshot diff), and the expected observable. Reference them in the slice graph so Phase 6 knows which oracle each task must satisfy.

Oracles are not unit tests — they describe behavior at the same boundaries `build-tdd`'s Wiring Coverage subsection requires real-wiring tests for. They are the contract that says "the production rebuild meets the prototype's verified behavior," and they are what closes the mock-only gap.

### Step 3: write the outputs

In order:

1. Architecture files → `aiwiki/architecture/{topic}.md` (one per topic; do NOT collapse into a monolith)
2. Approved ADRs → `aiwiki/decisions/{nnnn}-{slug}.md` (numbering: continue from the highest existing number)
3. Convention additions → `aiwiki/conventions/{slug}.md`
4. Gotcha addenda → update existing `aiwiki/gotchas/{date}-{slug}.md` files with production scope notes
5. Slice graph + tasks → manifest's `slice_graph` field + `.forge/work/{type}/{name}/tasks.md`
6. Session entry → `aiwiki/sessions/{date}-{slug}.md` linking everything written this session

Each write triggers wiki-lint synchronously; lint failures must be resolved before continuing.

### Step 4: trigger a focused dream

After the Step 3 writes land, fire a phase-close dream. Invoke the `support-dream` skill with:

- **scope:** the subfolders Step 3 touched — typically `aiwiki/architecture/`, `aiwiki/decisions/`, `aiwiki/conventions/`, `aiwiki/gotchas/`, `aiwiki/oracles/`, `aiwiki/sessions/`
- **trigger:** `phase-close`
- **trigger_detail:** `"Phase 5 (codify) — {feature/name}"`

The dream is the consolidation pass: it may merge new ADRs with existing ones, promote raw entries that became relevant during codification, and prune stale entries the new architecture supersedes.

Dream output goes to `aiwiki/proposed/{dream_id}/` for user review. Surface the dream id and review path:

```
Phase 5 writes complete. Dream queued: 2026-05-18-HHMM-codify-{name}
Review: `forge wiki review {dream_id}` or open `forge wiki ui`
The codify gate (Step 5) does not pass until this dream is reviewed.
```

The phase does NOT close until the user accepts or rejects the dream output.

### Step 5: gate

User reviews:
- The architecture files (do they accurately reflect the prototype?)
- The ADRs (each `review:` block has a clear verdict; objections are addressed)
- The slice graph (is the production task decomposition reasonable?)
- The dream proposal (any consolidation conflicts to resolve?)

User approves → Phase 6 (production-build) starts. User has objections → harden iterates: revise outputs, re-run dream, re-gate.

The user reviews ALL outputs as a unit, not piecemeal. The codified plan is short by design (~200-400 lines architecture + ~3-8 ADRs + slice graph) — review should be a single sitting, not a series of sessions.

## Adversarial review integration

Every production-only decision is an ADR-worthy decision; the prototype-codifier subagent flags them all. Adversarial review runs on each proposed ADR before it's written as `accepted`. This is non-optional — production code that ships against an ADR with no recorded review is silent debt. The review pass runs inline within harden Step 2 and writes the verdict directly into the ADR. When Codex is configured (`protocols/codex.md`), the pass may be dispatched to Codex in verify mode; otherwise Claude performs it directly.

Decisions that don't make the trigger list (variable naming, inline-vs-extract, choosing between known-good libraries with no real tradeoff) don't need ADRs at all and are NOT proposed by the subagent.

## Common mistakes

| Mistake | Fix |
|---|---|
| Generating architecture from imagination instead of citing the prototype | Every claim about a component cites `prototype-dir/path/to/file.ts:line@<sha7>` — if you can't cite, the claim is premature |
| One giant `aiwiki/architecture.md` file | Split by subsystem: `data-layer.md`, `auth-flow.md`, `event-bus.md`. Each <400 lines. |
| Writing ADRs for non-trigger-list decisions | Variable naming and inline-vs-extract are NOT ADRs. Use the trigger list strictly. |
| Skipping adversarial review because "the decision is obvious" | If the decision is obvious it doesn't need an ADR; if it needs an ADR it needs review (performed inline at Step 2, optionally via Codex verify mode) |
| Pre-promoting raw entries during codification | Raw entries are dream's territory; harden writes to typed pages directly, raw stays raw until dream consolidates |
| Modifying the prototype during codification | The prototype is the source of truth — leave it alone. Annotation goes in the architecture file, not in prototype source |
| Treating the gate as advisory | Phase 6 reads these outputs; if codification is incomplete, the production build is improvising. Block until the user accepts. |

## Red Flags

**Never:**
- Write production code in this phase (that's Phase 6)
- Skip the adversarial review on any proposed ADR
- Leave a proposed ADR with `verdict: escalate` unresolved at gate time
- Commit to the slice graph without listing explicit dependencies between slices
- Bypass wiki-lint on the outputs

**Always:**
- Cite the prototype file (or wireframe state) for every claim about how the system works
- Run the focused dream after writes — it catches conflicts the codification step alone misses
- Surface ALL outputs to the user for unified review
- Keep the codified plan short — if it grows past ~500 lines combined, it's invented, not codified

## I/O Contract

| Field | Value |
|---|---|
| **Requires** | Locked prototype, wireframe, concept slides, Phase 4 wiki entries, manifest |
| **Produces** | `aiwiki/architecture/*.md`, `aiwiki/decisions/*.md` (ADRs), `aiwiki/conventions/*.md` (additions), `aiwiki/gotchas/*.md` (updates), manifest's `slice_graph` field, `.forge/work/{type}/{name}/tasks.md`, `aiwiki/sessions/*.md` |
| **Updates manifest** | `slice_graph`, `artifacts.codify.locked_at` |
| **Triggers** | wiki-lint on every write; phase-close dream after writes complete |

## Integration

| Caller | When |
|---|---|
| Prototype-lock event in `/feature` and `/greenfield` | Phase 4 → Phase 5 transition |
| Manual invocation | When prototype is mature enough that production planning should begin |

| Dispatches | For |
|---|---|
| `prototype-codifier` subagent | Bulk codification work in own context window |
| Codex (verify mode, via `protocols/codex.md`) | Optional adversarial review on each proposed ADR — if Codex is not configured, harden runs the review pass inline at Step 2 |
| `support-dream` | Focused dream over touched subfolders after writes |
| `support-wiki-lint` | Synchronous validation on every wiki write |

| Pairs with | For |
|---|---|
| `iterate-prototype` | Phase 4 driver that hands off to harden at lock |
| `build-tdd` | Phase 6 driver that reads harden's outputs as inputs |
| `quality-code-review` | Phase 6 reviewer that checks production code against the codified architecture |
