Structures iOS apps by feature with MVVM using @Observable, dependency injection via protocols, navigation routing, and layered architecture for testability.
How this skill is triggered — by the user, by Claude, or both
Slash command
/swift-architecture-pro:swift-architecture-proThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Structure apps so features are isolated, testable, and easy to reason about.
Structure apps so features are isolated, testable, and easy to reason about.
Trigger: /swift-architecture-pro.
@Observable models.❌ By layer
Views/ Models/ ViewModels/ Services/ // every feature scattered across all four
✅ By feature
Features/
Feed/ FeedView.swift FeedModel.swift FeedService.swift
Profile/ ProfileView.swift ProfileModel.swift
Core/ Networking/ Persistence/ DesignSystem/
@MainActor @Observable
final class FeedModel {
private(set) var posts: [Post] = []
private let service: FeedServing
init(service: FeedServing) { self.service = service }
func load() async { posts = (try? await service.posts()) ?? [] }
}
struct FeedView: View {
@State private var model: FeedModel
var body: some View {
List(model.posts) { PostRow($0) }
.task { await model.load() }
}
}
View has no networking, no business rules — only presentation.
❌ Singleton reached from inside
final class FeedModel {
func load() async { posts = await API.shared.posts() } // untestable
}
✅ Protocol injected
protocol FeedServing { func posts() async throws -> [Post] }
final class FeedModel { init(service: FeedServing) { ... } }
// tests inject a fake; app injects the real one
Centralize a typed route; drive NavigationStack from it.
enum Route: Hashable { case detail(Post.ID), settings }
@Observable final class Router { var path: [Route] = [] }
NavigationStack(path: $router.path) {
HomeView()
.navigationDestination(for: Route.self) { route in
switch route { case .detail(let id): DetailView(id: id)
case .settings: SettingsView() }
}
}
Don't scatter NavigationLink(destination:) literals across the tree.
View → Model (@Observable) → Service (protocol) → Client (network/db). Dependencies
point downward only; lower layers never import UI.
View.Per issue: file:line, the boundary violated, suggested split. Lead with testability blockers (hard-wired singletons, logic in views).
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub laxrajpurohit/swift-skills-pro --plugin swift-architecture-pro