/flow-walkthrough
Verify UI *workflow* correctness that a task list, code review, and static screenshots miss. Drives end-to-end user flows in the Simulator via XCUITest with per-step screenshots, statically audits the navigation graph for dead-ends and missing edit paths, and emits a human
$ npx -y skills add rshankras/claude-code-apple-skills --skill flow-walkthrough --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/flow-walkthrough
Context preview
The summary Claude sees to decide when to auto-load this skill.
Verify UI *workflow* correctness that a task list, code review, and static screenshots miss. Drives end-to-end user flows in the Simulator via XCUITest with per-step screenshots, statically audits the navigation graph for dead-ends and missing edit paths, and emits a human
SKILL.md
flow-walkthrough.SKILL.mdname: flow-walkthrough
description: Verify UI *workflow* correctness that a task list, code review, and static screenshots miss. Drives end-to-end user flows in the Simulator via XCUITest with per-step screenshots, statically audits the navigation graph for dead-ends and missing edit paths, and emits a human discoverability checklist. Use after building any phase/slice that adds or changes UI, or when a user reports "I could only figure out the flow by running it."
allowed-tools: [Read, Write, Edit, Bash, Glob, Grep]
last_verified: 2026-07-16
review_by: 2027-06-22
Flow Walkthrough Skill
Task lists, compilers, and code review verify that *screens exist and compile*. They are structurally blind to whether the **flow between screens actually works for a human with a goal** — the transitions, the return paths, the dead-ends, the discoverability. This skill closes that gap.
Why this exists (the three failure classes)
Real UX bugs fail at three different layers, and **no single mechanism catches all three** — so this skill uses three:
| Failure class | Example | Caught by | |---|---|---| | **Dead-end / missing path** | A saved record can only be *viewed*, never reopened to edit; `Done` calls `popToRoot()` and orphans an in-progress entity | **Layer 1** — static nav-graph audit (no build) | | **Reachability regression** | "Run round" no longer reaches the capture screen after a refactor; a `Done` lands on the wrong screen | **Layer 2** — automated flow driving (XCUITest) | | **Discoverability** | "How do I even select a contestant?" — the only affordance is a bare row tap | **Layer 3** — human checklist (a UI test taps the row and *passes*) |
> The trap: a UI test happily taps a hidden control and reports PASS. Automation proves a path *works*; only a human judges whether it is *findable*. That residue is why Layer 3 is mandatory, not optional.
Input: the `<flows>` from PLAN.md
`/apple:plan` emits a `<flows>` block — end-to-end journeys, each a testable script. If `PLAN.md` has no `<flows>`, derive them from the phase's `<mvp-features>`/views and **write them back into PLAN.md first** (a flow that isn't written down can't be checked). A good flow names, for every persisted entity created: the step that **reopens it editable**, and the single **least-discoverable action**.
The method
Layer 1 — Static navigation-graph audit (no build required)
Grep the navigation surface and reason over it. Do this first; it's free and catches the highest-severity class.
1. **Build the graph.** Find entry points and edges:
- `Grep`: `NavigationStack`, `navigationDestination`, `NavigationLink`, `\.sheet`, `\.fullScreenCover`, `router.push`, `enum Route`, `dismiss()`, `popToRoot`, `@Query`.
2. **Assert reachability & return paths.** For every screen: how do you get in, and does every `Done`/`Back`/`dismiss` land somewhere intentional? Flag any `popToRoot()` that discards an in-progress or just-saved entity. 3. **CRUD-completeness.** For every `@Model` with a **Create** path, is there a **Read** *and* an **Update/reopen** path from the persistence surface (a list/history)? A list that only opens a read-only detail is a dead-end for editing — flag it. 4. **Entry-point sanity.** Does "New X" always create a *fresh* entity with no way back to the previous one except an incomplete list? Flag create-only loops. 5. **Nested navigation containers.** For every `NavigationLink`/`navigationDestination` destination, check whether the destination view declares its own `NavigationView`/`NavigationStack` — a pushed view must never wrap one. This renders a second nav bar under the parent's and its leading bar items displace the back button. It's a cross-file bug: each file looks correct alone (and previews fine in isolation), so single-file review never catches it — only this pairwise check does.
Output each finding as `DEAD-END` / `NO-EDIT-PATH` / `ORPHANS-ENTITY` / `NESTED-NAV` with the file:line and the missing arrow.
Layer 2 — Automated flow driving (XCUITest + per-step screenshots)
Turn each `<flow>` into a UI test that taps through it and screenshots every step, so the agent can *see* the transitions and assert the destinations.
1. **Ensure a UITest target exists.** If none, add one (xcodegen: a `type: bundle.ui-testing` target; or `xcodebuild`). Keep the generated tests — they become the Phase 5 regression suite. 2. **Generate one test method per flow** from `<steps>`. After each step, attach a screenshot:
func snap(_ name: String) {
let s = XCTAttachment(screenshot: XCUIScreen.main.screenshot())
s.name = name; s.lifetime = .keepAlways; add(s)
}Launch with any needed args (e.g. a `-uiTestSeed` launch argument that seeds SwiftData and, in DEBUG, flips entitlement flags so gated flows are reachable without a real purchase). Assert the **destination** of each step (`XCTAssert(app.staticTexts["Results"].waitForExistence(timeout: 2))`), especially after `Done`/`Back` — that is what catches wrong-destination bugs. 3. **Run and extract:**
xcodebuild test -project <App>.xcodeproj -scheme <App> \
-destination 'platform=iOS Simulator,name=<device>' \
-resultBundlePath .planning/walkthrough/<flowId>.xcresult
# export per-step screenshots for the agent to read:
xcrun xcresulttool export attachments \
--path .planning/walkthrough/<flowId>.xcresult \
--output-path .planning/walkthrough/<flowId>/ # adapt flag to installed Xcode(The `xcresulttool` attachment-export subcommand name shifts across Xcode versions — check `xcrun xcresulttool --help` and adapt.) 4. **Read the screenshots** in order → a "filmstrip." Confirm each step lands where the flow says it should. A failed assertion or a wrong screen = a flow bug with visual proof. 5. **One unseeded pass (fresh-install reality).** Every seeded run hides zero states — run at least one pass with NO seed argument that visits each top-level screen and scr
Read more
name: flow-walkthrough description: Verify UI *workflow* correctness that a task list, code review, and static screenshots miss. Drives end-to-end user flows in the Simulator via XCUITest with per-step screenshots, statically audits the navigation graph for dead-ends and missing edit paths, and emits a human discoverability checklist. Use after building any phase/slice that adds or changes UI, or when a user reports "I could only figure out the flow by running it." allowed-tools: [Read, Write, Edit, Bash, Glob, Grep] last_verified: 2026-07-16 review_by: 2027-06-22
Flow Walkthrough Skill
Task lists, compilers, and code review verify that *screens exist and compile*. They are structurally blind to whether the **flow between screens actually works for a human with a goal** — the transitions, the return paths, the dead-ends, the discoverability. This skill closes that gap.
Why this exists (the three failure classes)
Real UX bugs fail at three different layers, and **no single mechanism catches all three** — so this skill uses three:
| Failure class | Example | Caught by | |---|---|---| | **Dead-end / missing path** | A saved record can only be *viewed*, never reopened to edit; `Done` calls `popToRoot()` and orphans an in-progress entity | **Layer 1** — static nav-graph audit (no build) | | **Reachability regression** | "Run round" no longer reaches the capture screen after a refactor; a `Done` lands on the wrong screen | **Layer 2** — automated flow driving (XCUITest) | | **Discoverability** | "How do I even select a contestant?" — the only affordance is a bare row tap | **Layer 3** — human checklist (a UI test taps the row and *passes*) |
> The trap: a UI test happily taps a hidden control and reports PASS. Automation proves a path *works*; only a human judges whether it is *findable*. That residue is why Layer 3 is mandatory, not optional.
Input: the `<flows>` from PLAN.md
`/apple:plan` emits a `<flows>` block — end-to-end journeys, each a testable script. If `PLAN.md` has no `<flows>`, derive them from the phase's `<mvp-features>`/views and **write them back into PLAN.md first** (a flow that isn't written down can't be checked). A good flow names, for every persisted entity created: the step that **reopens it editable**, and the single **least-discoverable action**.
The method
Layer 1 — Static navigation-graph audit (no build required)
Grep the navigation surface and reason over it. Do this first; it's free and catches the highest-severity class.
1. **Build the graph.** Find entry points and edges:
- `Grep`: `NavigationStack`, `navigationDestination`, `NavigationLink`, `\.sheet`, `\.fullScreenCover`, `router.push`, `enum Route`, `dismiss()`, `popToRoot`, `@Query`.
2. **Assert reachability & return paths.** For every screen: how do you get in, and does every `Done`/`Back`/`dismiss` land somewhere intentional? Flag any `popToRoot()` that discards an in-progress or just-saved entity. 3. **CRUD-completeness.** For every `@Model` with a **Create** path, is there a **Read** *and* an **Update/reopen** path from the persistence surface (a list/history)? A list that only opens a read-only detail is a dead-end for editing — flag it. 4. **Entry-point sanity.** Does "New X" always create a *fresh* entity with no way back to the previous one except an incomplete list? Flag create-only loops. 5. **Nested navigation containers.** For every `NavigationLink`/`navigationDestination` destination, check whether the destination view declares its own `NavigationView`/`NavigationStack` — a pushed view must never wrap one. This renders a second nav bar under the parent's and its leading bar items displace the back button. It's a cross-file bug: each file looks correct alone (and previews fine in isolation), so single-file review never catches it — only this pairwise check does.
Output each finding as `DEAD-END` / `NO-EDIT-PATH` / `ORPHANS-ENTITY` / `NESTED-NAV` with the file:line and the missing arrow.
Layer 2 — Automated flow driving (XCUITest + per-step screenshots)
Turn each `<flow>` into a UI test that taps through it and screenshots every step, so the agent can *see* the transitions and assert the destinations.
1. **Ensure a UITest target exists.** If none, add one (xcodegen: a `type: bundle.ui-testing` target; or `xcodebuild`). Keep the generated tests — they become the Phase 5 regression suite. 2. **Generate one test method per flow** from `<steps>`. After each step, attach a screenshot:
func snap(_ name: String) {
let s = XCTAttachment(screenshot: XCUIScreen.main.screenshot())
s.name = name; s.lifetime = .keepAlways; add(s)
}Launch with any needed args (e.g. a `-uiTestSeed` launch argument that seeds SwiftData and, in DEBUG, flips entitlement flags so gated flows are reachable without a real purchase). Assert the **destination** of each step (`XCTAssert(app.staticTexts["Results"].waitForExistence(timeout: 2))`), especially after `Done`/`Back` — that is what catches wrong-destination bugs. 3. **Run and extract:**
xcodebuild test -project <App>.xcodeproj -scheme <App> \
-destination 'platform=iOS Simulator,name=<device>' \
-resultBundlePath .planning/walkthrough/<flowId>.xcresult
# export per-step screenshots for the agent to read:
xcrun xcresulttool export attachments \
--path .planning/walkthrough/<flowId>.xcresult \
--output-path .planning/walkthrough/<flowId>/ # adapt flag to installed Xcode(The `xcresulttool` attachment-export subcommand name shifts across Xcode versions — check `xcrun xcresulttool --help` and adapt.) 4. **Read the screenshots** in order → a "filmstrip." Confirm each step lands where the flow says it should. A failed assertion or a wrong screen = a flow bug with visual proof. 5. **One unseeded pass (fresh-install reality).** Every seeded run hides zero states — run at least one pass with NO seed argument that visits each top-level screen and scr
A collection of Claude Code skills for iOS, macOS, watchOS, visionOS, and Apple platform development. These skills help you plan and build apps, maintain code quality, ensure HIG compliance, and guide you from idea to App Store.
Repo: rshankras/claude-code-apple-skills
Other skills on rshankras-apple-skills.
- /app-store
App Store optimization and marketing skills for descriptions, screenshots, keywords, review responses, and comprehensive promotional strategy. Use when user needs help with App Store presence, ASO, marketing, or customer communication.
Open skill - /ad-attribution
Privacy-preserving ad measurement with AdAttributionKit (SKAdNetwork's successor) — install and re-engagement attribution, conversion-value strategy under crowd anonymity, and end-to-end postback testing. Use when running paid acquisition beyond Apple Ads, measuring
Open skill - /app-description-writer
Generate compelling App Store descriptions that convert browsers into users. Use when writing initial descriptions, improving existing copy, or drafting promotional text and What's New for a major update.
Open skill - /apple-search-ads
Apple Search Ads campaign strategy for indie developers — paid acquisition, keyword bidding, budget planning, and ROAS optimization. Use when user asks about running ads, paid user acquisition, or Apple Search Ads campaigns.
Open skill - /iap-finalizer
Take a one-time in-app purchase from MISSING_METADATA to READY_TO_SUBMIT in App Store Connect — set its price schedule and localized display name/description (and optional review screenshot) via the ASC REST API. Use at Phase 6 (Pre-Release), after the IAP is built in-app (Phase
Open skill - /keyword-optimizer
Optimize app title, subtitle, and keywords for maximum App Store discoverability. Use when launching a new app, improving search rankings, entering new markets/languages, or safely optimizing ASO for an app with existing traffic.
Open skill

