# Approve Design

> Record per-PR design-review approval (UI merge gate). ONLY on an explicit per-PR designer "approved".

- Skill: `me2resh/approve-design` (Agent Skill)
- Install (CLI): `npx skillmds@latest add me2resh/approve-design`
- Raw SKILL.md: https://api.skillmd.com/api/skills/me2resh/approve-design/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: me2resh (https://skillmd.com/u/me2resh)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/me2resh/approve-design

---


## Writing rule

When this skill writes a durable artifact, read .claude/rules/writing-standard.md. Use the controlled technical writing profile.

# /approve-design - Record Per-PR Design-Review Approval

Writes `.claude/session/reviews/<owner>__<repo>__<pr>-design.approved` (repo-qualified path, see AgDR-0060) with the current HEAD SHA so the `require-design-review-for-ui.sh` merge-gate hook will let a UI PR through. Without this marker, the hook blocks merges on any PR that touches `.tsx`, `.jsx`, `.vue`, `.svelte`, `.css`, `.scss`, `.sass`, `.less`, or `design-tokens*` files.

This skill is the design-review analog of `/approve-merge` (which writes the CEO marker for the merge gate). Same pattern, different gate.

## The one rule you must not break

**INVOKE THIS SKILL ONLY ON EXPLICIT, PER-PR, DESIGN-REVIEW APPROVAL.**

The valid invocation triggers look like this:

- "design approved" / "UI looks good" / "design review passed" — **if and only if** the surrounding context clearly names a specific PR and the designer has actually reviewed the PR's visual changes.
- "PR #42 design approved" / "the UI in #42 looks right" — names the PR explicitly.
- A reply to your own "PR #42 has UI changes — design review approved?" message that consists of any affirmative token — because you just named the PR and the user/designer is responding to that specific question.

**Invalid triggers** (do NOT run this skill):

- "looks good" / "nice" / "approved" — **when said about a Figma mockup, a design spec, a screenshot, or any artifact that is not a specific PR's diff**. Design review means reviewing the *actual code changes in a PR*, not a mockup. A mockup approval and a PR approval are different moments.
- "the design is fine" — **when said in a planning context** ("let's go with this design approach") rather than a PR-review context ("I've looked at the PR diff and the implementation matches the design"). The skill is for the latter.
- "go" / "continue" / "ship it" — when these are umbrella responses to a multi-step plan. Same rule as `/approve-merge`.
- Your own inference that "the designer probably approves because they liked the mockup earlier." NO. Mockup approval ≠ implementation approval. Stop and ask.

**If in doubt: STOP AND ASK.** "PR #X has UI changes — has the design been reviewed and approved?" is one message. Merging a PR with incorrect UI that needs a follow-up revert is much worse.

## Process

### 1. Parse the PR number — and the repo

Extract the PR number from `$ARGUMENTS`. If no argument is given, try to infer from:

- The current branch's open PR via `gh pr view --json number --jq '.number'`
- The user's most recent message, if it named a PR explicitly

If the PR number is ambiguous, STOP and ask.

**Also resolve the repo (`REPO`).** Accept the fully-qualified `owner/repo#N` form, or an explicit `owner/repo` second token. In split-portfolio v2 the PR lives in a *sibling* repo, so a bare `gh pr view <pr>` resolved against the ops-fork cwd hits the WRONG repo — the marker would then be written under the ops-fork qualifier and the `require-design-review-for-ui.sh` gate (which keys on the PR's real repo, derived from the merge command's cd-target, me2resh/apexyard#687) would never find it → false-block. Pass `--repo "$REPO"` to **every** `gh pr view` call below when `REPO` is known. **Fail loud:** if only a bare number was given and `gh pr view <pr>` cannot resolve the PR from the current cwd, STOP and ask for the `owner/repo#N` form — never write the marker under a guessed qualifier.

### 2. Sanity-check the user's intent

Before writing the marker, re-read the user's most recent message. Ask yourself:

- Did the user/designer explicitly name this PR, or can I point at a direct "PR #X design approved?" question from me that they are responding to?
- Did the designer review the *PR diff* (code changes), or just a mockup / screenshot / Figma link?
- Is the approval for the design aspects of this specific PR, or for a general design direction?

If any of these are unclear — **STOP**. Reply with a per-PR explicit question:
> "PR #X touches UI files (.tsx/.css/etc). Has the design review been completed on the actual PR diff — approved?"

### 3. Verify the PR state

Run `gh pr view <pr> ${REPO:+--repo "$REPO"} --json state,isDraft,mergeable`. Sanity checks:

- `state` must be `OPEN`.
- Refuse if `MERGED`, `CLOSED`, or `DRAFT`.
- `mergeable` should be `MERGEABLE` or `UNKNOWN`.

### 4. Verify the Rex marker exists at current HEAD

Design review is a stamp on top of a Rex-approved HEAD, not parallel to code review. Resolve the ops fork root and source the marker path helper:

```bash
REPO_ROOT=$(git rev-parse --show-toplevel)
OPS_ROOT=""
r="$REPO_ROOT"
while [ -n "$r" ] && [ "$r" != "/" ]; do
  if [ -f "$r/.apexyard-fork" ]; then OPS_ROOT="$r"; break; fi
  if [ -f "$r/onboarding.yaml" ] && [ -f "$r/apexyard.projects.yaml" ]; then OPS_ROOT="$r"; break; fi
  r=$(dirname "$r")
done
MARKER_HOME="${OPS_ROOT:-$REPO_ROOT}"
# shellcheck source=/dev/null
. "$MARKER_HOME/.claude/hooks/_lib-review-markers.sh"
# Base (host) repo — the canonical marker key: it matches Rex's marker AND the
# merge gate's lookup (which keys on the merge command's base repo, #765). Prefer
# the repo resolved in step 1 (already the base, #687); if it wasn't given, fall
# back to the CURRENT checkout's own remote — a deterministic, non-ambient
# source of truth. Do NOT fall back to an unscoped
# `gh pr view <pr> --json headRepository`: that call reads the wrong field (the
# PR's head/fork) and is itself an ambient-resolved gh query that can silently
# prefer the wrong repo in a fork checkout (#887). pr_base_repo now REQUIRES
# this repo and scopes its own gh query to it — never gh's ambient default —
# so same-repo PRs still resolve unchanged.
if [ -n "$REPO" ]; then
  REPO_FOR_BASE="$REPO"
else
  origin_url=$(git remote get-url origin 2>/dev/null)
  origin_url="${origin_url%.git}"
  REPO_FOR_BASE=$(printf '%s' "$origin_url" | sed -E 's#^(https?://[^/]+/|git@[^:]+:)##')
fi
PR_HOST_REPO=$(pr_base_repo <pr> "$REPO_FOR_BASE")
PR_REPO="$PR_HOST_REPO"
REX=$(review_marker_path "$PR_HOST_REPO" <pr> rex "$MARKER_HOME")
[ -f "$REX" ] && [ "$(tr -d '[:space:]' < "$REX")" = "$(git rev-parse HEAD)" ]
```

If Rex's marker is missing or its SHA doesn't match HEAD, refuse and tell the user to re-invoke the code-reviewer first. Do not write the design marker on a stale base.

### 5. Verify the PR actually touches UI files

Check whether the PR's diff includes files that would trigger the design-review gate. If the PR has NO UI files, the marker is unnecessary — tell the user and skip.

```bash
gh pr diff <pr> --name-only | grep -qE '\.(tsx|jsx|vue|svelte|css|scss|sass|less)$|design-tokens'
```

### 6. Write the design marker

Use the repo-qualified path via `_lib-review-markers.sh` (already sourced in step 4):

```bash
# (MARKER_HOME and PR_HOST_REPO already resolved in step 4 — reuse them here.)
mkdir -p "$MARKER_HOME/.claude/session/reviews"
# design marker keyed on the BASE repo — same key as Rex's marker + the gate (#765).
DESIGN=$(review_marker_path "$PR_HOST_REPO" <pr> design "$MARKER_HOME")
git rev-parse HEAD > "$DESIGN"
```

The file contains exactly one line: the 40-character HEAD SHA.

### 7. Confirm to the user

Output a single-line confirmation:

```
Design approval recorded for PR #<pr> at <sha>. The design-review merge gate will now allow this PR through.
```

**Do NOT run `gh pr merge` yourself in the same turn.** The skill's job ends at recording the marker. The merge is a separate action that still requires the CEO marker via `/approve-merge` plus an explicit merge instruction.

## Notes

- The design marker is gitignored (`.claude/session/` is in `.gitignore`). It's session state, not code.
- Re-running `/approve-design <pr>` is idempotent — it overwrites the marker with the current HEAD.
- New commits after the design approval invalidate the marker: the hook will refuse to merge because the SHA no longer matches HEAD. This is intentional — a new commit might change the UI. Re-request design review.
- This skill does NOT invoke the UI Designer role. It records the approval *after* the designer has reviewed. The review itself happens through whatever process the team uses (role activation, human review, Figma comparison, etc.).

## Anti-pattern

```
Designer: "The mockup in Figma looks great, ship it"
You: *tries to invoke /approve-design 42*  ← WRONG, twice over: a mockup nod is
                                             not implementation review, AND
                                             since #1042 the model cannot
                                             invoke this skill at all.
```

The designer approved a **mockup**, not the **PR's implementation of that mockup**. The implementation might differ from the mockup. The correct flow:

```
Designer: "The mockup in Figma looks great, ship it"
You: *implements the mockup in PR #42*
You: "PR #42 implements the approved mockup. Can you review the PR diff to confirm the implementation matches?"
Designer: "Reviewed PR #42, implementation matches the mockup. Design approved."
You: "Then run /approve-design 42 to record it."
Designer: /approve-design 42       ← CORRECT: a human invokes it. The skill is
                                     human-only (#1042), so the model cannot.
```

Two distinct moments. One is mockup approval (design phase). The other is implementation-review approval (code-review phase). They are not the same approval.

## Relationship to other approval skills

| Skill | Marker (repo-qualified, see AgDR-0060) | Gate hook | Who invokes |
|-------|----------------------------------------|-----------|-------------|
| `/approve-merge` | `<owner>__<repo>__<pr>-ceo.approved` | `block-unreviewed-merge.sh` | On explicit CEO per-PR merge nod |
| **`/approve-design`** | `<owner>__<repo>__<pr>-design.approved` | `require-design-review-for-ui.sh` | On explicit designer per-PR design nod |

Both skills follow the same pattern: verify PR state → verify Rex marker → write marker at ops fork root → confirm → stop. Both refuse to write on a stale Rex base. Both are invalidated by new commits. Neither runs `gh pr merge`.

The merge flow for a UI PR requires **three** markers before the merge-gate hooks allow through:

1. `<pr>-rex.approved` — from the code-reviewer agent
2. `<pr>-design.approved` — from this skill
3. `<pr>-ceo.approved` — from `/approve-merge`

---

*Part of [ApexYard](https://github.com/me2resh/apexyard) — multi-project SDLC framework for Claude Code · MIT.*

