UI Path Radar
SkillDev toolsUI path tracer for SwiftUI/UIKit apps. 5-layer audit with 34 issue categories and 19 automated checks: discover entry points, trace flows, detect dead ends and broken promises, evaluate UX impact, verify data wiring. Supports targeted trace, diff against previous audits, and handoff to planning skills. Triggers: "trace UI paths", "find dead ends", "/ui-path-radar".
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the UI Path Radar skill
What this skill tells your AI
The instructions your AI receives, as published by terryc21/radar-suite in skills/ui-path-radar/SKILL.md and read by ahel’s review.
Quick Ref: 5-layer UI path audit: discover entry points → trace flows → detect issues → evaluate UX → verify data wiring. Output:
.ui-path-radar/in project root.
You are performing a systematic UI path audit on this SwiftUI application.
Required output: Every finding MUST include Urgency, Risk, ROI, and Blast Radius ratings using the Issue Rating Table format. Do not omit these ratings.
Quick Commands
| Command | Description |
|---|---|
/ui-path-radar | Full 5-layer audit |
/ui-path-radar layer1 | Discovery only — find all entry points |
/ui-path-radar layer2 | Trace — trace critical paths |
/ui-path-radar layer3 | Issues — detect problems across codebase |
/ui-path-radar layer4 | Evaluate — assess user impact |
/ui-path-radar layer5 | Data wiring — verify real data usage |
/ui-path-radar trace "A → B → C" | Trace a specific user flow path |
/ui-path-radar diff | Compare current findings against previous audit |
/ui-path-radar fix | Generate fixes for found issues |
/ui-path-radar status | Show audit progress and remaining issues |
--show-suppressed | Show findings suppressed by known-intentional entries |
--accept-intentional | Mark current finding as known-intentional (not a bug) |
Overview
UI Path Radar uses a 5-layer approach:
| Layer | Purpose | Est. Time (small / large codebase) | Output |
|---|---|---|---|
| Layer 1 | Pattern Discovery — Find all UI entry points | ~1-2 min / ~3-5 min | Entry point inventory |
| Layer 2 | Flow Tracing — Trace critical paths in depth | ~2-3 min / ~5-8 min | Detailed flow traces |
| Layer 3 | Issue Detection — Categorize issues across codebase | ~2-4 min / ~5-10 min | Issue catalog |
| Layer 4 | Semantic Evaluation — Evaluate from user perspective | ~1-2 min / ~3-5 min | UX impact analysis |
| Layer 5 | Data Wiring — Verify features use real data | ~2-4 min / ~5-10 min | Data integrity report |
Codebase size guide: Small = <200 files, Large = 500+ files. Estimate from
find Sources -name "*.swift" | wc -l.
Issue Categories
Each category maps to a default axis (see skills/radar-suite-axis-classification/SKILL.md for the framework). The default axis may be overridden by the verification checklist (see "Axis Classification Protocol" section below) — e.g., a "Dead End" finding whose branch is unreachable from any production call site gets reclassified from axis_1_bug to axis_3_dead_code by the reachability trace.
| Category | Severity | Default Axis | Description |
|---|---|---|---|
| Dead End | 🔴 CRITICAL | axis_1_bug (→ axis_3_dead_code if unreachable) | Entry point leads nowhere |
| Wrong Destination | 🔴 CRITICAL | axis_1_bug | Entry point leads to wrong place |
| Mock Data | 🔴 CRITICAL | axis_1_bug | Feature shows fabricated data when real data exists |
| Destructive Without Confirmation | 🔴 CRITICAL | axis_1_bug | Delete/clear happens immediately without confirmation dialog |
| Silent State Reset | 🔴 CRITICAL | axis_1_bug | In-progress work lost when navigating away and back (form clears, selections lost) |
| Incomplete Navigation | 🟡 HIGH | axis_1_bug | User must scroll/search after landing |
| Missing Auto-Activation | 🟡 HIGH | axis_1_bug | Expected mode/state not set |
| Unwired Data | 🟡 HIGH | axis_1_bug (→ axis_3_smelly if model field has no read/write sites) | Model data exists but feature ignores it |
| Platform Parity Gap | 🟡 HIGH | axis_1_bug | Feature works on one platform, broken on another |
| Promise-Scope Mismatch | 🟡 HIGH | axis_1_bug | Specific CTA opens generic/broad destination |
| Buried Primary Action | 🟡 HIGH | axis_1_bug | Primary button hidden below scroll fold |
| Dismiss Trap | 🟡 HIGH | axis_1_bug | Only visible action is Cancel/back, no forward path |
| macOS Dismiss Trap | 🔴 CRITICAL | axis_1_bug | Sheet/modal relies ONLY on .presentationDragIndicator / .presentationDetents (iOS-only) with NO macOS-visible dismiss control (Done/Cancel/Close button, SheetContainer, or @Environment(\.dismiss) button). macOS has NO swipe-to-dismiss → user is TRAPPED. Heuristic: a presented View that uses drag-indicator/detents but the file has no cancellationAction/confirmationAction/Button("Done"|"Cancel"|"Close")/xmark/SheetContainer/dismiss(). Beware false positives where the presented view delegates to a wrapper that provides the dismiss — trace through to the wrapped view. (Real instances 2026-06: MaintenanceTaskListView, LegacyShareSheet.) Detect mechanically with a build-script grep: flag any file using drag-indicator/detents that lacks a dismiss signal, bypassable via a // dismiss-parity: ok comment. |
| Context Dropping | 🟡 HIGH | axis_1_bug | Navigation path loses item context between platforms or via notifications |
| Notification Nav Fragility | 🟡 HIGH | axis_1_bug | Untyped NotificationCenter dict used for navigation context |
| Sheet Presentation Asymmetry | 🟡 HIGH | axis_2_scatter (→ axis_1_bug if only one platform works) | Different presentation mechanisms per platform for same feature |
| Empty State Missing | 🟡 HIGH | axis_1_bug (→ axis_3_dead_code if empty case unreachable) | No guidance when list/view is empty — users think app is broken |
| Error Recovery Missing | 🟡 HIGH | axis_1_bug | Error displayed but no retry button or recovery path |
| Keyboard Obscures Input | 🟡 HIGH | axis_1_bug | Text field covered by keyboard with no scroll adjustment (iOS) |
| Permission Denied Dead End | 🟡 HIGH | axis_1_bug | Permission denied but no explanation or path to Settings |
| Modal Stacking | 🟡 HIGH | axis_1_bug | Multiple sheets/alerts open on top of each other |
| Navigation Container Mismatch | 🟡 HIGH | axis_1_bug | selectedSection value not a valid tag in current TabView/sidebar |
| Two-Step Flow | 🟢 MEDIUM | axis_1_bug | Intermediate selection required |
| Missing Feedback | 🟢 MEDIUM | axis_1_bug | No confirmation of success |
| Gesture-Only Action | 🟢 MEDIUM | axis_1_bug | Feature only accessible via swipe/long-press |
| Loading State Trap | 🟢 MEDIUM | axis_1_bug | Spinner with no cancel/timeout/escape |
| Stale Navigation Context | 🟢 MEDIUM | axis_2_scatter (→ axis_1_bug if user observes stale data) | Cached context with no clearing/validation mechanism |
| Phantom Touch Target | 🟢 MEDIUM | axis_1_bug | Visual element looks tappable but isn't (icon without action, card without nav) |
| Race Condition UX | 🟢 MEDIUM | axis_1_bug | User can trigger conflicting operations simultaneously (double-tap, edit while sync) |
| Invisible Selection | 🟢 MEDIUM | axis_1_bug | Item is selected/active but visual indicator missing or too subtle |
| Inconsistent Pattern | ⚪ LOW | axis_2_scatter | Same feature accessed differently |
| Orphaned Code | ⚪ LOW | axis_3_dead_code (if unreachable) or axis_3_smelly (if reachable but unjustified) | Feature exists but no entry point |
| Command-Palette-Only Feature | 🟡 HIGH | axis_1_bug | Feature reachable only via command palette (QuickFind/Go To), no visible UI entry point |
| Deeply Buried Feature | 🟡 HIGH | axis_1_bug | User-facing feature requires 4+ taps from nearest tab bar item |
| Double-Nested Navigation | ⚪ LOW | axis_2_scatter | NavigationStack inside NavigationStack causing doubled nav bars |
Axis Classification Protocol (MANDATORY — before emitting any finding)
Every finding must be classified on the 3-axis framework and pass the schema gate in radar-suite-core.md before emission. The protocol:
-
Assign default axis from the table above based on the issue category.
-
Run required verification checks:
- Reachability trace (MANDATORY for Dead End, Empty State Missing, Orphaned Code) — walk upstream from the flagged branch at least 2 call-site levels. If no production call site reaches it, RECLASSIFY to
axis_3_dead_code. - Whole-file scan (MANDATORY for "missing handler" categories: Empty State Missing, Error Recovery Missing, Missing Feedback) — read the ENTIRE file (not just the flagged region) for handlers elsewhere. If found, RECLASSIFY to
axis_2_scatter. - Branch enumeration (MANDATORY for Platform Parity Gap, Sheet Presentation Asymmetry) — read BOTH sides of every
#if os(iOS)/#elseblock before claiming platform-broken. Stuffolio has 266 such blocks; dropping the#elsebranch is the #1 false-positive source. - Pattern citation lookup (MANDATORY for every finding, regardless of category) — grep the audited codebase for a similar pattern shape. Cite by file:line in the
better_approachfield. A finding without this citation is REJECTED.
- Reachability trace (MANDATORY for Dead End, Empty State Missing, Orphaned Code) — walk upstream from the flagged branch at least 2 call-site levels. If no production call site reaches it, RECLASSIFY to
-
Write coaching fields. Populate
current_approach,suggested_fix,better_approach(with citation),better_approach_tradeoffs— all mandatory. Load coaching examples via.radar-suite/project.yamlcoaching_examplesarray. -
Validate against schema gate. Run the gate checks from
radar-suite-core.md. If any mandatory field is missing, either fix the finding or downgrade confidence topossibleand incrementrejected_no_citationin the handoff. -
Write the finding to the handoff YAML with full axis + coaching fields.
Reclassification logging: When the verification checklist reclassifies a finding's axis (e.g., "Dead End" → axis_3_dead_code via reachability trace), log the reclassification in the finding's verification_log so capstone and the user can see the framework caught a would-be false positive:
verification_log:
- check: reachability_trace
result: "no production call site found; reclassified from axis_1_bug (Dead End) to axis_3_dead_code"
Axis summary block. At the end of the handoff, include:
axis_summary:
axis_1_bug: [count]
axis_2_scatter: [count]
axis_3_dead_code: [count]
axis_3_smelly: [count]
rejected_no_citation: [count]
Design Principles
1. Honor the Promise
When a button/card says "Do X", tapping it should DO X. Not "go somewhere you might find X."
2. Context-Aware Shortcuts
If user's context implies a specific item, skip pickers.
3. State Preservation
When navigating to a feature, set up the expected state.
4. Consistent Access Patterns
Same feature should be accessed the same way everywhere.
5. Data Integrity
If the app tracks data relevant to a feature, the feature must use it. Never show mock/hardcoded data when real user data exists. Never ignore model relationships that would improve decisions.
6. Primary Action Visibility
The primary action must be visible without scrolling after the user completes the key interaction. Pin Save/Continue/Done buttons outside ScrollView or in toolbar. Never bury them below tall content.
7. Escape Hatch
Every view must have a visible way to go forward OR back. Cancel alone is not enough after user completes a step.
8. Gesture Discoverability
Every action available via gesture (swipe, long-press) should also be accessible via a visible button or menu.
Freshness
Base all findings on current source code only. Do not read or reference
files in .agents/, scratch/, or prior audit reports. Ignore cached
findings from auto-memory or previous sessions. Every finding must come
from scanning the actual codebase as it exists now.
Before Starting
All setup questions were captured during the Skill Introduction call below (USER_EXPERIENCE, FIX_MODE, DELIVERY, PRESENCE_MODE). Do NOT re-ask them here. Show the one-line settings reminder from § Skill Introduction and proceed to the audit.
If any of the four variables is missing for some reason (e.g., session-prefs file deleted mid-session), re-run the full Skill Introduction call before continuing — never partially re-ask, since the questions are interdependent (Question 4 overrides Question 1 — see Hands-Free Mode below).
Permission Modes
Normal Mode
- Read any file without asking.
- Edit files only if user chose auto-fix and the fix is isolated to the audited flow.
- Build and run tests without asking.
- If a fix breaks the build, restore the original code and document as "Documented."
Hands-Free Mode
Guarantees no blocking prompts. Only uses: Read, Grep, Glob.
Does NOT use: Bash, Edit, Write, AskUserQuestion.
Precedence rules (load-bearing — Hands-Free wins all ties):
- Hands-Free overrides
FIX_MODE. Even if Question 2 was answeredAuto-fix safe itemsorBatch mode, no fixes are applied in Hands-Free mode. All findings are emitted withStatus: Deferred (hands-free)in the Issue Rating table. The Fix Plan is still produced (so the user can act on it on return), but no Wave 1-4 fix application runs. - Hands-Free suppresses the next-wave
AskUserQuestion. The "CRITICAL — BLOCKING requirement" rule under § Progress Banner applies in Normal and Pre-Approved modes only. In Hands-Free mode, the progress banner still prints, but theAskUserQuestioncall is omitted and replaced by the completion message below. - Hands-Free defers all write-tool layer steps. The following steps require Edit/Write and are deferred until the user returns: writing
.ui-path-radar/layer3-results.yaml,.ui-path-radar/layer5-data-wiring.yaml,.ui-path-radar/canaries.yaml,.ui-path-radar/handoff.yaml,.agents/ui-audit/ui-path-radar-handoff.yaml, and.radar-suite/ledger.yaml. To resolve: in Hands-Free mode, the skill emits these YAML files inline in the conversation as fenced YAML blocks so the user can persist them on return. Inline emission does not count as a write. - Hands-Free covers all 5 layers, not just 1-4. Layer 5 step 7 (write
layer5-data-wiring.yaml) and Layer 3's cross-layer verification table edits both fall under rule 3 above — emitted inline rather than written to disk.
When complete:
⏱ Hands-free audit complete through Layer [N] of 5: [plain description].
Layers requiring write access: [list]
Findings deferred: [count] (no fixes applied — Hands-Free mode)
Handoff YAML + ledger entries: emitted inline above; copy to .ui-path-radar/, .agents/ui-audit/, and .radar-suite/ when you return
Reply to continue with supervised steps.
Pre-Approved Mode
Full speed, no restrictions. Assumes you've set up permissions.
Permission Setup (for unattended runs)
# Already safe by default (no setup needed):
Read, Grep, Glob — always auto-approved
# Add these for unattended Bash scans:
Bash(find:*)
Bash(wc:*)
Bash(stat:*)
Do NOT auto-approve (keep prompted — they modify state):
Edit, Write — file modifications
Bash(rm:*), Bash(git:*) — destructive operations
Tip: If you frequently run audit-only layers (1-4), the Hands-free mode eliminates permission prompts entirely without changing any settings.
Context Budget
If context is running low, prioritize in this order:
- Finish the current phase
- Emit findings for what you've audited so far
- Skip remaining unaudited flows
Never start auditing a new flow you can't finish.
Experience-Level Adaptation
Adjust ALL output based on the user's experience level:
Beginner
- Use plain language with real-world analogies.
- Define technical terms on first use in parentheses.
- Explain flags/categories and why they matter.
- Include file context: "DashboardView.swift (the main home screen) line 118"
- Explain the "why" behind each suggestion.
- Use compact 4-column table format.
Intermediate
- Use standard SwiftUI terminology without defining basics.
- Explain non-obvious patterns.
- Standard file:line format.
- Full 9-column format with brief finding descriptions.
Experienced (default)
- Concise findings. No definitions or explanations of standard patterns.
- Recommendations: what to fix, where.
- Full 9-column format, terse findings.
Senior/Expert
- Minimal findings text. No prose between tables.
- File:line + one-line fix description only.
- Skip: progress explanations, design principle citations, category definitions.
- Full 9-column format, maximally compressed.
Enforcement Rule
At the start of each layer, silently check: "Am I writing at the selected experience level?" Do NOT drift toward "Experienced" as a default.
Execution Instructions
Skill Introduction (MANDATORY — run before anything else)
This section replaces radar-suite-core.md § Session Setup for the ui-path-radar entry point. Do NOT also run core's 4-question Session Setup — its questions are consolidated below. On first invocation, ask all four setup questions in a single AskUserQuestion call. The "Before Starting" section above reuses these answers and never re-asks.
Question 1: "What's your experience level with Swift/SwiftUI?"
- Beginner — New to Swift. Plain language, analogies, define terms on first use.
- Intermediate — Comfortable with SwiftUI basics. Standard terms, explain non-obvious patterns.
- Experienced (Recommended) — Fluent with SwiftUI. Concise findings, no definitions.
- Senior/Expert — Deep expertise. Terse, file:line only, skip explanations.
Question 2: "How should fixes be handled?"
- Auto-fix safe items (Recommended) — Apply isolated, low-blast-radius fixes automatically. Present cross-cutting fixes and design decisions for approval first.
- Review first — Present all findings with ratings, then ask before making any changes. Fixes still happen — you just approve each wave first.
- Batch mode — Approve all fixes in each wave at once.
IMPORTANT: All three modes lead to fixes. "Review first" means the user sees the plan before code changes — it does NOT mean "skip fixes and jump to handoff." After presenting findings, ALWAYS offer to fix them regardless of which mode was selected. (Exception: Hands-Free mode overrides this — see Question 4.)
Question 3: "How should results be delivered?"
- Display only (Recommended) — Show findings in the conversation. No file written.
- Report only — Write findings to
.ui-path-radar/[DATE]-audit.md. Minimal conversation output. Before writing, per Artifact Lifecycle (Class 3) inradar-suite-core.md, archive any existing.ui-path-radar/*-audit.mdto.ui-path-radar/archive/superseded/. - Display and report — Show findings in the conversation AND write to file.
Question 4: "Will you be stepping away during the audit?"
- I'll be here (Recommended) — Normal mode. Permission prompts may appear for writes/edits.
- Hands-Free (walk away safe) — Read-only tools (Read, Grep, Glob) only. No Bash, no Edit, no Write, no AskUserQuestion. Hands-Free overrides Question 2: all fixes are deferred regardless of
FIX_MODE. The progress banner still prints, but theAskUserQuestionnext-wave prompt is suppressed; the skill emits the "audit complete through Layer N" completion message instead (see Hands-Free Mode below). - Pre-Approved — You have already configured Claude Code permissions. Run at full speed.
Store as: USER_EXPERIENCE, FIX_MODE, DELIVERY, PRESENCE_MODE. Apply to ALL output for the session, per radar-suite-core.md § Experience-Level Output Rules. Also persist to .radar-suite/session-prefs.yaml per radar-suite-core.md § Session Persistence.
Question 5 (optional follow-up): "Would you like a brief explanation of what this skill does?"
- No, let's go (Recommended) — Skip explanation, proceed to audit.
- Yes, explain it — Show one of the explanations below adapted to experience level, then proceed.
Experience-adapted explanations:
-
Beginner: "UI Path Radar checks every button, link, and menu item in your app to make sure they actually work. Think of it like walking through every door in a building to verify none are locked, lead nowhere, or open to the wrong room. It finds 'dead ends' (buttons that do nothing), 'broken promises' (a button says 'Export PDF' but opens the wrong screen), and missing features. It runs in 5 layers, each going deeper — from finding all the buttons, to tracing what happens when you tap them, to checking if the data behind them is real."
-
Intermediate: "UI Path Radar systematically audits all UI entry points (sheets, navigation links, toolbar buttons, deep links, notifications) across your SwiftUI app. It traces user flows end-to-end, flags dead ends, promise-scope mismatches, platform gaps, and orphaned state. Five layers: discovery → flow tracing → issue detection → UX evaluation → data wiring verification."
-
Experienced: "5-layer UI path audit across 34 issue categories and 19 automated checks: entry point discovery, flow tracing, issue detection, semantic UX evaluation, and data wiring verification. Outputs issue rating tables with fix plans."
-
Senior/Expert: "Entry point → flow trace → issue scan → UX eval → data wiring. 34 categories, 19 checks. Rating tables + fix plans."
User impact explanations: Can be toggled at any time with --explain / --no-explain. When enabled, each finding gets a 3-line companion explanation (what's wrong, fix, user experience before/after). See radar-suite-core.md for format and rules. Store as EXPLAIN_FINDINGS (default: false).
Experience-level auto-apply (ui-path-radar local): If USER_EXPERIENCE = Beginner, auto-set EXPLAIN_FINDINGS = true and default sort to impact. If Senior/Expert, default sort to effort. Apply all output rules from radar-suite-core.md § Experience-Level Output Rules.
Shared Patterns
See radar-suite-core.md for: Tier System, Pipeline UX Enhancements, Table Format, Plain Language Communication, Work Receipts, Contradiction Detection, Finding Classification, Audit Methodology, Context Exhaustion, Progress Banner, Issue Rating Tables, Handoff YAML schema, Known-Intentional Suppression, Pattern Reintroduction Detection, Experience-Level Output Rules, Implementation Sort Algorithm, short_title requirement.
Pre-Scan Startup (MANDATORY — before any layer scan)
-
Known-intentional suppression: Run the protocol in
radar-suite-core.md § Known-Intentional Suppression. Core owns this — do not restate the steps here. -
Pattern reintroduction detection: Run the protocol in
radar-suite-core.md § Pattern Reintroduction Detection. Core owns this.
When invoked, perform the audit:
If no arguments or "full":
Before starting, print:
Full Audit: 5 layers — estimated total: ~10-30 min depending on codebase size
Layer 1: Find all entry points → Layer 2: Trace how users navigate → Layer 3: Detect issues → Layer 4: Evaluate user impact → Layer 5: Verify data wiring
Run all 5 layers sequentially, outputting findings to .ui-path-radar/ in the project root.
Between layers, print: ✓ Layer [N] of 5 complete: [plain description] — starting Layer [N+1]: [plain description]
If "layer1" or "discovery": enumerate-required
Before starting, count Swift files and print an estimate:
Layer 1: Discovery — scanning [N] Swift files
Estimated time: ~[1-2 min for <200 files / 3-5 min for 500+ files]
Progress will be shown after each tier completes.
Scan in 3 tiers, from top-level down. After completing each tier, print a progress line:
Tier 1: Top-Level Structure
- Find the app's navigation skeleton:
TabView,NavigationSplitView, sidebar sections - For each top-level destination, identify the view file
- Scan for sheet routing enums:
grep -r "enum.*Sheet\|enum.*SheetType" Sources/ - Scan for navigation state:
grep -r "selectedSection\|selectedTab\|activeSheet" Sources/
After Tier 1, print: Layer 1: ✓ Tier 1 Structure (1/3) — found [N] tabs, [N] sidebar items, [N] sheet enums
Tier 2: Entry Point Patterns
Scan for these patterns across ALL source files:
Shortened here. Read the whole file on GitHub.
Signals
- GitHub stars
- 20
- Forks
- 1
- Last commit
- Aug 2026
ahel review
K1binfo
installs-packages (in radar-suite-core.md)
Automated review, not a security audit. Ruleset v1+k2.
Advanced
- Catalog kind
- skill
- Gateway key
ui-path-radar- Source
- github.com/terryc21/radar-suite