Boot simulator if needed, capture screenshot via XcodeBuildMCP, diff against mockup baseline using design-comparison MCP. Reports discrepancies with fix suggestions.
Install
npx skillscat add jthorare/agentic-workflow/design-verify-ios Install via the SkillsCat registry.
Before anything else: read $HOME/.agentic-workflow/toolkit/skills/_preamble.md and follow it (skill index, provider capability map, bootstrap check, session context). Run its Session Close section when this skill finishes.
Design context: read $HOME/.agentic-workflow/toolkit/skills/_design-preamble.md and follow it before continuing.
Design Verify iOS — Simulator Screenshot Diff vs Mockup
Boots the simulator per _shared/sim-bootstrap.md, navigates with snapshot_ui-verified gestures, captures an appearance/size matrix, and diffs each cell against its per-screen mockup baseline. Artifact paths and the comparison-report.json schema come from _shared/design-artifact-paths.md.
Step 1: Load screens.json and Baselines
SHARED_DIR="$HOME/.agentic-workflow/toolkit/skills/_shared"
source "$SHARED_DIR/repo-slug.sh"
cat "$AW_DIR/design/screens.json" 2>/dev/null || echo "NO_SCREENS_JSON"
ls "$AW_DIR/design/"mockup-ios-*.png 2>/dev/null
ls "$AW_DIR/design/mockup-ios.png" 2>/dev/null || trueRead $SHARED_DIR/design-artifact-paths.md for the screens.json (CD4) schema and baseline naming (CD3).
- Screens to verify: the
[screen-name]argument if given, else every screen inscreens.jsonwith"source": "design-mockup-ios". - Baselines:
mockup-ios-<screen>.png(light) and, when present,mockup-ios-<screen>-dark.png(dark). - Legacy baseline: a bare
mockup-ios.png(secondlsline) may be used only for a single light-appearance compare, with the warning: "legacy baseline — re-run /design-mockup to upgrade".
If a requested screen has no entry and no baseline, or none exist at all, stop:
"No iOS mockup baseline for
<screen>. Run/design-mockup-ios <screen>first."
Staleness check — warn (do not stop) if the screen's baseline_stale in screens.json is non-null: "baselines predate a design-token update (design-evolve) — re-run /design-mockup-ios".
Step 2: Acquire Simulator Lock
Single bash invocation per the lock recipe in $SHARED_DIR/sim-bootstrap.md (skill-lock.sh enables set -euo pipefail):
SHARED_DIR="$HOME/.agentic-workflow/toolkit/skills/_shared"
LOCK_NAME=ios-sim source "$SHARED_DIR/skill-lock.sh"; acquire_lockIf acquire_lock reports TIMEOUT, report "Another skill is using the simulator" and stop. Every failure branch after this point must, in one invocation, re-source (LOCK_NAME=ios-sim source "$SHARED_DIR/skill-lock.sh") and call release_lock before stopping. Use return, not exit, in sourced context — exit after sourcing can kill the caller's shell. Never end this skill with the lock held.
Step 3: Boot Simulator and Launch App
Follow the canonical sequence in $SHARED_DIR/sim-bootstrap.md:
mcp: xcodebuildmcp/session_show_defaults— verify project/workspace, scheme, simulator- If missing/wrong:
mcp: xcodebuildmcp/discover_projs→mcp: xcodebuildmcp/list_schemes mcp: xcodebuildmcp/list_sims— pick the target simulatormcp: xcodebuildmcp/boot_simif not already Bootedmcp: xcodebuildmcp/build_run_sim— or the split path:mcp: xcodebuildmcp/build_sim→mcp: xcodebuildmcp/get_app_bundle_id→mcp: xcodebuildmcp/install_app_sim→mcp: xcodebuildmcp/launch_app_sim
If any of these fails, release the lock (Step 2 recipe) and stop with the tool error.
Step 4: Navigate to Screen — snapshot_ui First
mcp: xcodebuildmcp/snapshot_ui— inspect the view hierarchy. If the target screen is already showing (labels/identifiers match), skip to Step 5.- Otherwise read the screen's
navrecipe from screens.json — an ordered list of{"action":"tap","target":"<label or x,y>"}steps recorded by/design-mockup-ios. - Capability probe (per
$SHARED_DIR/sim-bootstrap.md): before any gesture, check that the UI-automation workflow tools (tap/swipe/type_text) are available. If absent, print exactly:"XcodeBuildMCP UI-automation workflow not enabled — see github.com/getsentry/XcodeBuildMCP/docs/CONFIGURATION.md. Interaction steps will be SKIPPED (verdict capped at WARN)."
Then, because this screen requires navigation, do not merely cap at WARN: capturing whatever screen happens to be showing would produce a false verdict. Mark the screen FAIL with reasonnavigation required but gestures unavailable, and skip its capture. - Execute each nav step: resolve label targets to coordinates from the current
mcp: xcodebuildmcp/snapshot_uihierarchy, perform the gesture, then re-runmcp: xcodebuildmcp/snapshot_uito assert the expected transition happened. If a step's target cannot be found, mark the screen FAIL with the hierarchy evidence. - If navigation is needed but the screen has no
navrecipe (null), mark it FAIL: "no nav recipe in screens.json — re-run /design-mockup-ios (records one) or navigate the simulator manually and re-run."
Step 5: Create the Run Directory
SHARED_DIR="$HOME/.agentic-workflow/toolkit/skills/_shared"
source "$SHARED_DIR/repo-slug.sh"
RUN_ID="$(date -u +%Y%m%d-%H%M%S)-<screen-or-all>"
mkdir -p "$AW_DIR/design/verify/$RUN_ID"
echo "run-dir: $AW_DIR/design/verify/$RUN_ID"Previous runs are never overwritten.
Step 6: Capture the Appearance/Size Matrix
For each screen, capture with mcp: xcodebuildmcp/screenshot into $AW_DIR/design/verify/$RUN_ID/<screen>-<cell>.png, one cell at a time:
| Cell | What | Diffed against |
|---|---|---|
light |
light appearance (always) | mockup-ios-<screen>.png |
dark |
dark appearance | mockup-ios-<screen>-dark.png when it exists; otherwise capture for the record, no diff |
dynamic-type |
one Dynamic Type step-up; sanity-check for truncation/overlap via mcp: xcodebuildmcp/snapshot_ui |
no diff (recorded observation) |
<class2>-light |
a second device class (e.g. iPad) when mcp: xcodebuildmcp/list_sims offers one |
recorded; diffed only if a matching baseline exists |
Appearance/Dynamic Type switching requires the simulator-management workflow; if those tools are not enabled, record the affected cells as SKIPPED — simulator management workflow not enabled and cap the run verdict at WARN (the light cell alone can still PASS a cell-level diff, but never the overall run).
Step 7: Diff Against Baselines
For each matrix cell with a baseline, call mcp: design-comparison/compare_design:
- reference: the baseline PNG from Step 1
- implementation:
$AW_DIR/design/verify/$RUN_ID/<screen>-<cell>.png
Record the response's numeric diff-percentage field as diff_pct; save the returned diff image to $AW_DIR/design/verify/$RUN_ID/<screen>-<cell>-diff.png. Cell verdict (CD11): ≤2% PASS · 2–10% WARN · >10% FAIL.
Step 8: Write comparison-report.json (Run Manifest)
Write $AW_DIR/design/verify/$RUN_ID/comparison-report.json per the schema in $SHARED_DIR/design-artifact-paths.md, with the matrix cell carried in the viewport field:
{ "schema": "comparison-report/v1", "run_id": "<run-id>",
"screens": [ { "screen": "...", "viewport": "light|dark|dynamic-type|<class2>-light", "baseline": "...",
"capture": "...", "diff_image": "...", "diff_pct": 0.0, "verdict": "PASS|WARN|FAIL" } ],
"overall": { "max_diff_pct": 0.0, "verdict": "PASS|WARN|FAIL" } }overall.verdict = worst cell verdict (SKIPPED cells cap it at WARN); overall.max_diff_pct = max diff_pct. Nav-failed screens get diff_pct: 100, verdict: "FAIL", and the reason recorded in place of the diff image path. This file is the run's gate manifest — the dispatcher and ship chain read it.
Step 9: Report Results
Report honesty (region-level only): a pixel diff can say where pixels differ ("header area differs by N%"), never why. Do not attribute deviations to specific Theme values or tokens — there is no computed-style probe on iOS, so token-level attribution is forbidden.
[<PASS|WARN|FAIL>] iOS Design Verification — <screen(s)>
=========================================================
Overall: <verdict> (max diff <N>% · thresholds: ≤2% PASS / ≤10% WARN / >10% FAIL)
| screen | cell | diff % | verdict | deviating regions |
|--------|------|--------|---------|-------------------|
Skipped cells: <list with reasons, or "none">
Artifacts: ~/.agentic-workflow/<repo-slug>/design/verify/<run-id>/For WARN/FAIL cells, describe the deviating regions and point at the diff image; suggest /design-refine or /design-implement-ios, then /design-verify-ios again.
Step 10: Release Simulator Lock
Always — success or failure (single invocation, re-sourced):
SHARED_DIR="$HOME/.agentic-workflow/toolkit/skills/_shared"
LOCK_NAME=ios-sim source "$SHARED_DIR/skill-lock.sh"; release_lockRules
- Never diff a capture whose on-screen content was not confirmed via
mcp: xcodebuildmcp/snapshot_ui - Region-level findings only — no token/Theme attribution (Step 9)
- Do not modify any code — this skill is read-only verification
- If the simulator shows an unexpected state (system dialog, wrong screen after nav), record it as evidence and mark the affected screen FAIL rather than guessing
Next steps
Gate on overall.verdict — a FAIL run blocks the /shipRelease suggestion:
- PASS —
/shipRelease— diff is clean, ship the release - WARN —
/design-refine— address minor discrepancies or enable the missing simulator workflows, then/design-verify-iosagain - FAIL —
/design-refineor/design-implement-ios— significant deviation; re-verify before any ship step