---
name: yad-ui
description: 'Shape step 5 of the gated SDLC. With the ux-designer, author ui-design.md and DESIGN.md for an approved architecture, driving Impeccable as harness slash-commands (document/extract/craft) when installed, or authoring directly when not. Reads epic + architecture as input. Never auto-advances — hands off to the team review gate. Use when the user says "author the UI design" or after the architecture gate passes.'
---

# SDLC — Author UI Design (Shape step 5)

**Goal:** Produce a human-authored, AI-assisted `ui-design.md` and `DESIGN.md` for an approved
architecture **and**, when a design tool is connected, the **actual feature design** — the mobile
screens and/or web pages — inside that tool (e.g. Figma), linked back from the artifacts. This is a
**Shape step**: human-authored with AI assist, **never auto-advances**. When the UI is drafted, control
passes to `yad-review-gate` (base rule: 1 distinct approver, who should not be the author).

UI work is shaped by **Impeccable**, invoked as **harness slash-commands** (not a subprocess CLI) per
the Phase 0 deviation. If Impeccable is not used (**When a tool is missing** below), the `ux-designer` lens authors the same outputs
directly — the workflow does not block on the tool.

The visual design is materialized in the **design tool connected via `yad-connect-design`**
(`.sdlc/design.json`), reached through its MCP. When a tool is connected the `ux-designer` lens
**generates** screens into it (or **links** an existing human-made design and reads it back); when none
is connected, the step degrades to the Markdown artifacts only — the design tool is additive, exactly
like Impeccable.

## When a tool is missing

<!-- Written from yadflow's cli/toolbox.mjs (E87). Change the words there: a test holds this section to it. -->

No tool below is required. When one is missing, this skill still finishes, using the fallback written
beside it.

For Impeccable (the one tool here that is not a connector), decide from yad's answer, not from a guess:
run `yad toolbox list --json` and read, in its `tools` list, the entry with the tool's `id`. Run it
where the tool will run: for work inside a code repo, add `--dir <that repo>`, so the tools installed
there are found.

- **The team's choices.** They come from the Product. If the answer's `product` is null, yad found no
  Product, so a tool the team chose not to use still shows `used: true`. Tell the person that.
- **When yad cannot see the tool.** yad does not read every way a tool can be set up (an older install
  may be missed). If the entry says `missing` but the check in the steps below finds the tool, use
  it — but never when the entry says `used: false`.
- **When yad cannot answer** (yad is not installed here, or the command fails), use the check in the
  steps below.

Tell the person which tools you used and which fallbacks, and why.

- **Impeccable** (`impeccable`). Use it when its entry has `used: true` and `status.state` is `installed` or `available`. Otherwise — not found, its plugin turned off in Claude Code, or the team chose not to use it (`yad toolbox remove impeccable`) — use the fallback.
  - Fallback — markdown-only UI design: yad-ui writes ui-design.md and DESIGN.md directly.
  - Record `impeccable: not-installed`. It means the tool was not used, whatever the reason.
- **Figma** (`figma`, a connector). Used when `.sdlc/design.json` connects it. yad-connect-design writes that file; follow it, not yad's toolbox answer.
  - Fallback — markdown-only: yad-ui writes ui-design.md and DESIGN.md only.
- **Pencil (pen.dev)** (`pencil`, a connector). Used when `.sdlc/design.json` connects it. yad-connect-design writes that file; follow it, not yad's toolbox answer.
  - Fallback — markdown-only: yad-ui writes ui-design.md and DESIGN.md only.

<!-- end: When a tool is missing -->

## Conventions

- `{project-root}` resolves from the project working directory.
- Artifacts live under `{project-root}/epics/EP-<slug>/` (build plan §6).
- `DESIGN.md` is Impeccable's conventional root design-system file (RESEARCH-NOTES §4).
- The connected design tool is recorded in `{project-root}/.sdlc/design.json` (`config.yaml` `design`),
  written by `yad-connect-design`. The per-epic screen→frame map is `design-links.json` (Step 4b).
- Speak in the `communication_language` set in `{project-root}/.sdlc/config.yaml`; write documents in `document_output_language`.

## On Activation

### Step 1 — Resolve the epic and check the gate
Resolve the `EP-<slug>` (ask if not provided).

**Precondition gate (rail):** run `yad next EP-<slug> --check ui-design` first. If it exits non-zero,
**STOP** — surface the blocker it prints and point the user at `yad next EP-<slug>`. Do not author until
it passes.

This passes when `ui-design` is the next runnable step per the state sequence — every prior step
(through the architecture review) is `done` and `ui-design` is not already `done`.

**This step is OPTIONAL.** If the epic has no user-facing surface (a backend/API service, a data
pipeline, infra work), it does not need a UI design. Two signals to watch for:

- **Already skipped or deferred:** if `ui-design.status` is `skipped` in `state.json` — or, in a file
  from before shape 7, `done` with `skipped: true` beside it — the step was marked N/A. If it is
  `deferred`, the team set it aside to come back to later. Either way the `--check` above refuses it
  (`ui-design is already skipped`, or `already deferred`). **STOP**, there is nothing to author now;
  point the user at `yad next EP-<slug>` (the next step is `stories`). To pick a deferred UI back up,
  run `yad undefer EP-<slug> ui-design` first.
- **Should be skipped:** if you reach this step and the epic clearly produces no screens, do **not**
  invent a hollow UI artifact. Offer to mark it N/A instead:
  `yad skip EP-<slug> ui-design --reason "<why, e.g. backend-only service>"`. That marks both the
  `ui-design` and `ui-design-review` steps `skipped` (recorded reason + actor), short-circuits the review
  gate, and advances to `stories`. It is reversible with `yad unskip EP-<slug> ui-design` until the
  stories review opens. See `../yad-epic/references/state-schema.md` → "ui-design is optional".
- **Will have screens, just not yet:** if the epic does need a UI but the team wants to design it later,
  offer `yad defer EP-<slug> ui-design --reason "<why, and who is waiting for it>"` instead of a skip.
  It passes the step for now and keeps it visibly owed. If the team is setting it aside under pressure
  and owes it back, add `--debt`: `yad next` and `yad doctor` then remind them until its review passes.
  It can be picked back up with `yad undefer EP-<slug> ui-design` at any time — after the stories are
  finished, the UI re-opens beside them and the stories stay done.
- **On a verified Product (the mode check below), none of these verbs works here:** by this step the
  epic's ledger is on the default branch, so `yad skip`, `yad defer` and `yad undefer` refuse (CI owns
  `state.json`, and has no step for them yet). Tell the user that, and do not edit the ledger by hand.

### Step 1b — Open the authoring branch
Open the UI authoring branch `ui-design/EP-<slug>` per the shared procedure
(`../yad-epic/references/state-schema.md` → "Authoring branches"): git-safe (skip with a note
if `{project-root}` is not a git work tree), check out the branch if it exists, else create it from the
Product's default branch. Author `ui-design.md` / `DESIGN.md` on it, and end the step with `yad fold EP-<slug> ui-design` — the one
commit the step keeps (E44). This is **distinct** from
the verified ledger's `review/…` branch.

### Step 2 — Read inputs
Read `epic.md` (user-level acceptance signals, scope) and `architecture.md` (flows, components by
repo). The UI must cover the user-facing flows the architecture defines.

### Step 2b — Load existing-code context (make the brain code-aware)
Read the registry `{project-root}/.sdlc/repos.json` (`config.yaml` `code_context`). For **each repo in
`epic.repos`**, load the code-map `{project-root}/.sdlc/code-context/<repo>/code-map.md` so the UI
**reuses existing components and conventions** rather than inventing parallel ones. This complements
Impeccable's `/impeccable document` (Step 3), which reads code directly for the design system — when
Impeccable is not used, the code-map is the brain's view of what UI/components already exist.

- **Greenfield-safe:** if `repos.json` is absent/empty, note "no repos connected" and proceed.
- **Staleness:** if a repo's current HEAD ≠ its registry `syncedHead`, warn and suggest
  `yad repo refresh <repo>` (a human decision — flag and stop, never auto-refresh); stamp
  `code-context: stale` in the frontmatter.
- **Traceability:** record the loaded maps in the `ui-design.md` `code-context:` frontmatter field.

### Step 3 — Shape the UI (assist: ux-designer + Impeccable slash-commands)
Adopt the **ux-designer** lens. Drive Impeccable as slash-commands:

- **Existing project** (a codebase/design system already exists): `/impeccable document` → then
  `/impeccable extract` → then `/impeccable craft`.
- **New project** (no design system yet): `/impeccable craft` → then `/impeccable extract`.

`/impeccable document` generates the root `DESIGN.md` from existing code; `/impeccable extract` pulls
components/tokens into the design system; `/impeccable craft` is shape-then-build for the new screens.

**Graceful degradation:** if Impeccable is not used (**When a tool is missing** says how to tell; if
yad cannot answer, it is not used when no `/impeccable …` commands are available), the
`ux-designer` lens authors `ui-design.md` and `DESIGN.md` directly, and you **note in `ui-design.md`
that Impeccable was not used**. Do not run `npx impeccable skills install` as part of this step — tool
installation is out of scope for Shape.

### Step 3b — Materialize the design in the connected tool (generate or link)
Read `{project-root}/.sdlc/design.json` (`config.yaml` `design.registry`). Decide the path:

- **No tool / `tool: "none"` / `source: "unavailable"`** (or the file is absent): **degrade** —
  author the Markdown artifacts only and record `design: none` in the frontmatter with a one-line note
  (mirrors the `impeccable: not-installed` degrade). Skip to Step 4.
- **A tool is connected and its MCP is available:** adopt the `ux-designer` lens and, using the provider
  recorded in `design.json` (Figma via a Figma/html.to.design MCP, `pencil` via its MCP, etc.):
  - **Generate** — when the provider is write-capable, produce one frame per screen the design covers,
    for the platforms in `epic.repos` (mobile and/or web), reusing the code-maps (Step 2b) and
    `DESIGN.md` tokens so screens match built components rather than inventing parallel ones.
  - **Link** — when the user points at an existing design file (or the provider is read-only), reference
    it and **read the frames back** so `ui-design.md` reflects the real design.

  Capture each screen's `name`, `platform`, `nodeId`, and `url`. Record which direction was used
  (`generated | linked`). Honest-capability rule: a read-only MCP supports **link** only — never claim a
  screen was generated that the provider cannot produce. See
  `../yad-connect-design/references/design-context.md`.

### Step 4 — Write the UI artifacts
Write `{project-root}/epics/EP-<slug>/ui-design.md` using EXACTLY this template:

```markdown
---
id: EP-<slug>
artifact: ui-design
status: draft
owner: <inherit from epic.md owner>   # the epic owner carries through; not retyped
repos: [<inherit from epic>]
impeccable: <used | not-installed>
code-context: { repos: [], loaded: <YYYY-MM-DD or none> }   # code-maps that informed component reuse (Step 2b)
design: <none | { tool: <figma|pencil|…>, direction: <generated|linked>, file: <url>, screens: <N> }>   # the connected design tool (Step 3b)
---

## Screens & states
<!-- one subsection per screen: purpose, key states (empty/loading/error/success) -->

## User flows
<!-- the click-paths that satisfy the epic's acceptance signals -->

## Components & tokens
<!-- components used; reference DESIGN.md tokens; what is new vs reused -->

## Accessibility & responsiveness
<!-- a11y notes; breakpoints/viewports covered -->

## Design (<tool>)
<!-- omit this section when design: none. one row per screen, linking to its frame in the tool.
     mirrors design-links.json (Step 4b). -->
<!-- - <Screen name> (<mobile|web>) — <frame url> -->
```

Also create/update `{project-root}/epics/EP-<slug>/DESIGN.md` (Impeccable's design-system file, or a
hand-authored equivalent when degraded) capturing the design tokens/components the screens rely on.

### Step 4b — Write the design-links map (when a tool was used)
When Step 3b generated or linked a design, write the machine-readable screen→frame map to
`{project-root}/epics/EP-<slug>/.sdlc/design-links.json` (sibling of `contract-lock.json`):

```json
{
  "tool": "figma",
  "fileUrl": "https://www.figma.com/file/<key>/<name>",
  "generatedAt": "<YYYY-MM-DD>",
  "direction": "generated | linked",
  "screens": [
    { "name": "Checkout", "platform": "mobile",
      "nodeId": "123:45", "url": "https://www.figma.com/file/<key>/?node-id=123-45" }
  ],
  "source": "figma-mcp"
}
```

Keep the `## Design (<tool>)` section of `ui-design.md` in step with this file. When Step 3b degraded
(`design: none`), do **not** write `design-links.json`.

### Step 5 — Advance the authoring step (NOT the gate)
**Check the mode first — the two modes have opposite instructions here.** Read `.sdlc/product.json` (`.sdlc/hub.json` on an older Product that has only that name):
**verified mode** is `platform` set AND `ledger: "verified"` — or, on a project that has not run `yad migrate` yet, `bridge_enabled` (or legacy `bridge`) `true`. `ledger` wins whenever it is present.

**verified mode — do NOT write `state.json`.** The ledger is CI-owned: the `ledger-guard` check rejects
any non-bot commit touching `epics/*/.sdlc/{state,approvals,comments,product-prs,hub-prs}.json` or
`epics/*/reviews/*.md`, `yad gate open` deliberately skips this write for the same reason, and
`yad gate ci --merged` performs the whole transition when the review PR merges. Making the edit here
fails the gate if it rides the review PR, and desynchronises the ledger CI is about to rewrite if it
is pushed around the gate. Commit the artifact set — **`ui-design.md`, `DESIGN.md`, and, when a
design tool was used, `.sdlc/design-links.json`** (artifact-side, not ledger) — with `yad fold EP-<slug> ui-design`,
which takes exactly these and leaves the ledger to CI — then hand off to
`yad-review-gate`.

**Otherwise — local, or a platform with no gate-sync CI — the engine makes this edit, not you.**
`yad gate open <epic> ui-design.md` marks `ui-design-review` `in_review`, closes `ui-design` as `done`, and moves `currentStep` to the gate
— unless the chain is already past it: a `ui-design` re-opened with a late `yad undefer` runs beside the
finished stories, and opening its review leaves `currentStep` where it is — the same transition, from the one function that owns it (`markInReview`, `cli/epic-state.mjs`).
`yad-review-gate action: open` runs that command; hand off to it rather than editing the ledger here.

**With no platform configured** it writes the ledger and simply opens no PR, so this works offline.
**With a platform** the `review/EP-<slug>/ui-design` branch must already be **on origin** — the command
refuses and writes nothing otherwise. Cut it from the authoring branch and push it before handing off
(or run `yad open-pr` from that branch: it pushes the branch, then delegates).

Do **not** hand-edit `state.json`, and do **not** touch `approvals.json` — only real reviewers approve,
through the gate.

### Step 6 — Stop at the gate (do NOT advance)
Report: the paths to `ui-design.md` and `DESIGN.md`, whether Impeccable was used, the connected design
tool and what it produced (e.g. "Figma — 4 screens generated", the file URL + `design-links.json` path,
or "no design tool — markdown-only"), and that the next action is **review** via `yad-review-gate` (base
rule: 1 distinct approver, who should not be the author). **Never record approval here.** Shape steps do not auto-advance. When the Product has a platform, the gate opens a review PR on the
Product (via `yad-product-bridge`) and `yad-review-gate action: sync` pulls platform approvals/comments into
the ledger; otherwise the review is recorded local.

## Reference
- Impeccable commands and the slash-command-vs-CLI deviation: `RESEARCH-NOTES.md` §4 + Deviation 3.
- State schema and field meanings: `../yad-epic/references/state-schema.md`.
- Connecting a design tool (Figma, pluggable) + generate-vs-link recipes and the degrade path:
  `../yad-connect-design/SKILL.md` (+ `references/design-context.md`).
- Connecting code repos + the code-context the brain reads: `../yad-connect-repos/SKILL.md`.
