axiom-codex/skills/axiom-audit-swiftui-architecture/SKILL.md
Use when the user mentions SwiftUI architecture review, separation of concerns, testability issues, or "logic in view" problems.
npx skillsauth add charleswiltgen/axiom axiom-audit-swiftui-architectureInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
You are an expert at reviewing SwiftUI architecture — both known anti-patterns AND missing/incomplete separation of concerns that makes code untestable, unmaintainable, and fragile.
Run a comprehensive architecture audit using 5 phases: map view/model boundaries, detect known anti-patterns, reason about what's untestable or poorly separated, correlate compound issues, and score architecture health. Report all issues with:
axiom-swiftui skill (architecture)Do NOT focus on micro-performance (formatters/sorting) unless they also represent architectural violations (logic in view). For performance issues, link to swiftui-performance-analyzer. Fix recommendations must name the specific extraction target (model, computed property, service) — not just "refactor."
Skip: *Tests.swift, *Previews.swift, */Pods/*, */Carthage/*, */.build/*, */DerivedData/*, */scratch/*, */docs/*, */.claude/*, */.claude-plugin/*
Before grepping for violations, build a mental model of how the app separates views from logic.
Glob: **/*.swift (excluding test/vendor paths)
Grep for:
- `struct.*:.*View` — SwiftUI views
- `@Observable class` — modern observable models
- `ObservableObject` — legacy observable models
- `@State`, `@Binding`, `@Bindable` — state ownership
- `@Environment` — environment injection
- `import SwiftUI` in non-View files — potential coupling
Grep for:
- `Task {` in files with `var body` — async work in views
- `withAnimation.*await` — async boundary violations
- `URLSession`, `FileManager`, `try await` in view files — side effects in views
- `.filter(`, `.sorted(`, `.map(` in view files — data transforms in views
Read 3-5 key files (main view, a model/viewmodel, a service) to understand:
Write a brief Architecture Boundary Map (8-12 lines) summarizing:
Present this map in the output before proceeding.
Run all 5 existing detection categories. These are fast and reliable. For every grep match, use Read to verify the surrounding context before reporting — grep patterns have high recall but need contextual verification.
Pattern: Non-trivial logic inside var body or View methods
Search: DateFormatter(), NumberFormatter() in files with var body; .filter(, .sorted(, .map(, .reduce( near var body; if/else chains with business logic in body
Issue: Untestable logic, violates separation of concerns (also hurts performance)
Fix: Extract to @Observable model or computed property
Pattern: Task { } performing multi-step business logic in views; withAnimation wrapping await calls
Search: Task { in view files — read context, check for URLSession, FileManager, try await, multi-step logic; withAnimation followed by await within 5 lines
Issue: State-as-Bridge violation, unpredictable animation timing, untestable side effects
Fix: Synchronous state mutation in view, async work in model
Pattern: @State var item: Item (non-private) where Item is passed in from parent
Search: @State var without private — read context to check if value comes from parent
Issue: Creates a local copy that loses updates from the parent source of truth
Fix: Use let item: Item (read-only) or @Bindable var item: Item (read-write)
Pattern: @Observable class or ObservableObject class with >20 stored properties or mixing unrelated domains
Search: @Observable class, ObservableObject — read the class, count stored properties, check domain coherence
Issue: SRP violation, hard to test, unnecessary view updates when unrelated state changes
Fix: Split into smaller, focused models
Pattern: Non-View types importing SwiftUI
Search: import SwiftUI in all files — for each match, read the file. Skip if it conforms to View (has var body). Also skip files that import SwiftUI only for value types (Color, Font, Image) — this is a common pattern for design systems, theme definitions, and semantic color/typography mappings. Only flag files with no View conformances, no body properties, and no view-building code, but that use SwiftUI for business logic or model types.
Issue: Business logic coupled to UI framework, can't unit test without SwiftUI
Fix: Remove import SwiftUI from models; use Foundation types
Using the Architecture Boundary Map from Phase 1 and your domain knowledge, check for what's missing — not just what's wrong.
| Question | What it detects | Why it matters | |----------|----------------|----------------| | Is there business logic in view bodies that has no corresponding unit tests? | Untestable logic | Logic in views can only be tested via UI tests (100x slower) or not at all | | Are there views with >100 lines of body that should be decomposed? | Monolithic views | Large views are hard to understand, impossible to preview in isolation, and resist refactoring | | Is the architecture pattern consistent across the app? (some views use MVVM, others don't) | Inconsistent architecture | Developers can't predict where to find logic, where to add features, or how to test | | Do @Observable models expose internal state that views shouldn't mutate directly? | Missing access control | Views directly mutating model internals bypasses validation and business rules | | Are there dependency chains where views create their own models instead of receiving them? | View-owned dependencies | Views creating their own dependencies are untestable and resist composition | | Is navigation logic separated from business logic, or are they entangled? | Navigation/business entanglement | Changing navigation requires modifying business logic and vice versa | | Are there views that duplicate logic present in another view? | Cross-view duplication | Same business rule implemented differently in two views = divergent behavior |
For each finding, explain what's missing and why it matters. Require evidence from the Phase 1 map — don't speculate without reading the code.
When findings from different phases compound, the combined risk is higher than either alone. Bump the severity when you find these combinations:
| Finding A | + Finding B | = Compound | Severity | |-----------|------------|-----------|----------| | Logic in view body | No unit tests for that logic | Untested business logic | CRITICAL | | Async boundary violation | In critical flow (purchase, auth) | Untestable, timing-sensitive critical transaction | CRITICAL | | @State copying parent data | Parent updates the data | Source-of-truth bug — UI shows stale data | CRITICAL | | God ViewModel | Holds strong references to closures/delegates | Retain cycles across a large dependency surface | HIGH | | import SwiftUI in model | Model has complex business logic | Core logic untestable without UI framework | HIGH | | Inconsistent architecture | New developer joins team | No predictable pattern to follow, accelerates tech debt | HIGH | | View-owned dependencies | In reusable component | Component can't be tested or composed differently | MEDIUM | | Duplicate logic across views | Logic involves validation | Validation rules diverge silently over time | HIGH |
Also note overlaps with other auditors:
Calculate and present a health score:
## Architecture Health Score
| Metric | Value |
|--------|-------|
| View/model ratio | N views, M models/viewmodels (ratio X:1) |
| Logic separation | N views with business logic in body, M with logic in models (Z% clean) |
| Async boundary | N Task blocks in views, M delegating to models (Z% clean) |
| Property wrapper correctness | N @State usages, M potentially copying parent data |
| Testability | N non-View types importing SwiftUI, M total non-View types (Z% testable) |
| Architecture consistency | Pattern: [consistent/mixed/none] |
| **Health** | **CLEAN / TANGLED / MONOLITHIC** |
Scoring:
# SwiftUI Architecture Audit Results
## Architecture Boundary Map
[8-12 line summary from Phase 1]
## Summary
- CRITICAL: [N] issues (correctness bugs)
- HIGH: [N] issues (testability/separation)
- MEDIUM: [N] issues (maintainability)
- LOW: [N] issues
- Phase 2 (anti-pattern detection): [N] issues
- Phase 3 (completeness reasoning): [N] issues
- Phase 4 (compound findings): [N] issues
## Architecture Health Score
[Phase 5 table]
## Issues by Severity
### [SEVERITY] [Category]: [Description]
**File**: path/to/file.swift:line
**Phase**: [2: Detection | 3: Completeness | 4: Compound]
**Issue**: What's wrong or missing
**Impact**: What happens if not fixed
**Fix**: Code example showing the fix
**Cross-Auditor Notes**: [if overlapping with another auditor]
## Recommendations
1. [Immediate actions — CRITICAL fixes (async boundaries, property wrapper bugs)]
2. [Short-term — HIGH fixes (extract logic from views, fix testability)]
3. [Long-term — architectural improvements from Phase 3 findings]
4. [If performance concerns: run `/axiom:audit swiftui-performance`]
If >50 issues in one category: Show top 10, provide total count, list top 3 files If >100 total issues: Summarize by category, show only CRITICAL/HIGH details
Task { await viewModel.load() } — simple delegation to model is fine@State on private properties initialized with literalsimport SwiftUI in files that only use value types (Color, Font, Image) for design system.filter/.sorted on small, known-size collections in simple viewsFor architecture patterns: axiom-swiftui skill (architecture)
For performance issues: swiftui-performance-analyzer agent
For navigation architecture: swiftui-nav-auditor agent
development
Use when building ANY watchOS app — app structure, independent apps, Watch Connectivity, Smart Stack widgets, complications, controls, RelevanceKit, background tasks, ClockKit migration.
development
Use when working with HealthKit, WorkoutKit, health data, workouts, or fitness features on iOS or watchOS. Covers permissions, queries, background delivery, custom workouts, multidevice coordination.
development
Use when building, fixing, or improving ANY SwiftUI UI — views, navigation, layout, animations, performance, architecture, gestures, debugging, iOS 26 features.
content-media
Use when working with camera, photos, audio, haptics, ShazamKit, or Now Playing. Covers AVCaptureSession, PHPicker, PhotosPicker, AVFoundation, Core Haptics, audio recognition, MediaPlayer, CarPlay, MusicKit.