UI Path Radar

SkillDev tools

UI 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.

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

CommandDescription
/ui-path-radarFull 5-layer audit
/ui-path-radar layer1Discovery only — find all entry points
/ui-path-radar layer2Trace — trace critical paths
/ui-path-radar layer3Issues — detect problems across codebase
/ui-path-radar layer4Evaluate — assess user impact
/ui-path-radar layer5Data wiring — verify real data usage
/ui-path-radar trace "A → B → C"Trace a specific user flow path
/ui-path-radar diffCompare current findings against previous audit
/ui-path-radar fixGenerate fixes for found issues
/ui-path-radar statusShow audit progress and remaining issues
--show-suppressedShow findings suppressed by known-intentional entries
--accept-intentionalMark current finding as known-intentional (not a bug)

Overview

UI Path Radar uses a 5-layer approach:

LayerPurposeEst. Time (small / large codebase)Output
Layer 1Pattern Discovery — Find all UI entry points~1-2 min / ~3-5 minEntry point inventory
Layer 2Flow Tracing — Trace critical paths in depth~2-3 min / ~5-8 minDetailed flow traces
Layer 3Issue Detection — Categorize issues across codebase~2-4 min / ~5-10 minIssue catalog
Layer 4Semantic Evaluation — Evaluate from user perspective~1-2 min / ~3-5 minUX impact analysis
Layer 5Data Wiring — Verify features use real data~2-4 min / ~5-10 minData 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.

CategorySeverityDefault AxisDescription
Dead End🔴 CRITICALaxis_1_bug (→ axis_3_dead_code if unreachable)Entry point leads nowhere
Wrong Destination🔴 CRITICALaxis_1_bugEntry point leads to wrong place
Mock Data🔴 CRITICALaxis_1_bugFeature shows fabricated data when real data exists
Destructive Without Confirmation🔴 CRITICALaxis_1_bugDelete/clear happens immediately without confirmation dialog
Silent State Reset🔴 CRITICALaxis_1_bugIn-progress work lost when navigating away and back (form clears, selections lost)
Incomplete Navigation🟡 HIGHaxis_1_bugUser must scroll/search after landing
Missing Auto-Activation🟡 HIGHaxis_1_bugExpected mode/state not set
Unwired Data🟡 HIGHaxis_1_bug (→ axis_3_smelly if model field has no read/write sites)Model data exists but feature ignores it
Platform Parity Gap🟡 HIGHaxis_1_bugFeature works on one platform, broken on another
Promise-Scope Mismatch🟡 HIGHaxis_1_bugSpecific CTA opens generic/broad destination
Buried Primary Action🟡 HIGHaxis_1_bugPrimary button hidden below scroll fold
Dismiss Trap🟡 HIGHaxis_1_bugOnly visible action is Cancel/back, no forward path
macOS Dismiss Trap🔴 CRITICALaxis_1_bugSheet/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🟡 HIGHaxis_1_bugNavigation path loses item context between platforms or via notifications
Notification Nav Fragility🟡 HIGHaxis_1_bugUntyped NotificationCenter dict used for navigation context
Sheet Presentation Asymmetry🟡 HIGHaxis_2_scatter (→ axis_1_bug if only one platform works)Different presentation mechanisms per platform for same feature
Empty State Missing🟡 HIGHaxis_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🟡 HIGHaxis_1_bugError displayed but no retry button or recovery path
Keyboard Obscures Input🟡 HIGHaxis_1_bugText field covered by keyboard with no scroll adjustment (iOS)
Permission Denied Dead End🟡 HIGHaxis_1_bugPermission denied but no explanation or path to Settings
Modal Stacking🟡 HIGHaxis_1_bugMultiple sheets/alerts open on top of each other
Navigation Container Mismatch🟡 HIGHaxis_1_bugselectedSection value not a valid tag in current TabView/sidebar
Two-Step Flow🟢 MEDIUMaxis_1_bugIntermediate selection required
Missing Feedback🟢 MEDIUMaxis_1_bugNo confirmation of success
Gesture-Only Action🟢 MEDIUMaxis_1_bugFeature only accessible via swipe/long-press
Loading State Trap🟢 MEDIUMaxis_1_bugSpinner with no cancel/timeout/escape
Stale Navigation Context🟢 MEDIUMaxis_2_scatter (→ axis_1_bug if user observes stale data)Cached context with no clearing/validation mechanism
Phantom Touch Target🟢 MEDIUMaxis_1_bugVisual element looks tappable but isn't (icon without action, card without nav)
Race Condition UX🟢 MEDIUMaxis_1_bugUser can trigger conflicting operations simultaneously (double-tap, edit while sync)
Invisible Selection🟢 MEDIUMaxis_1_bugItem is selected/active but visual indicator missing or too subtle
Inconsistent Pattern⚪ LOWaxis_2_scatterSame feature accessed differently
Orphaned Code⚪ LOWaxis_3_dead_code (if unreachable) or axis_3_smelly (if reachable but unjustified)Feature exists but no entry point
Command-Palette-Only Feature🟡 HIGHaxis_1_bugFeature reachable only via command palette (QuickFind/Go To), no visible UI entry point
Deeply Buried Feature🟡 HIGHaxis_1_bugUser-facing feature requires 4+ taps from nearest tab bar item
Double-Nested Navigation⚪ LOWaxis_2_scatterNavigationStack 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:

  1. Assign default axis from the table above based on the issue category.

  2. 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) / #else block before claiming platform-broken. Stuffolio has 266 such blocks; dropping the #else branch 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_approach field. A finding without this citation is REJECTED.
  3. Write coaching fields. Populate current_approach, suggested_fix, better_approach (with citation), better_approach_tradeoffs — all mandatory. Load coaching examples via .radar-suite/project.yaml coaching_examples array.

  4. 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 to possible and increment rejected_no_citation in the handoff.

  5. 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):

  1. Hands-Free overrides FIX_MODE. Even if Question 2 was answered Auto-fix safe items or Batch mode, no fixes are applied in Hands-Free mode. All findings are emitted with Status: 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.
  2. 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 the AskUserQuestion call is omitted and replaced by the completion message below.
  3. 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.
  4. 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:

  1. Finish the current phase
  2. Emit findings for what you've audited so far
  3. 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) in radar-suite-core.md, archive any existing .ui-path-radar/*-audit.md to .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 the AskUserQuestion next-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)

  1. Known-intentional suppression: Run the protocol in radar-suite-core.md § Known-Intentional Suppression. Core owns this — do not restate the steps here.

  2. 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
  1. Find the app's navigation skeleton: TabView, NavigationSplitView, sidebar sections
  2. For each top-level destination, identify the view file
  3. Scan for sheet routing enums: grep -r "enum.*Sheet\|enum.*SheetType" Sources/
  4. 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