ai-docs/assets/skills/swift-clean-architecture/SKILL.md
Matt Bruce 88e4402d38 fix: use tool-agnostic ~/.agents/ as default install path
Copilot, Claude, Cursor, and others all read from ~/.agents/.
The npx skills CLI handles fan-out to tool-specific directories.
2026-02-11 12:13:20 -06:00

4.8 KiB

name description globs
Swift Clean Architecture File organization, layer separation, folder structures, and proactive refactoring
**/*.swift

Clean Architecture for Swift

Separation of concerns is mandatory. Code should be organized into distinct layers with clear responsibilities and dependencies flowing inward.

File Organization Rules

One Public Type Per File

Each file should contain exactly one public struct, class, or enum. Private supporting types may be included only if they are small and used exclusively by the main type.

Keep Files Lean (300 Line Limit)

Aim for files under 300 lines. If a file exceeds this:

  • Extract reusable sub-views into Components/ folder
  • Extract sheets/modals into Sheets/ folder
  • Extract complex logic into dedicated types
  • Split private view structs into their own files

No Duplicate Code

Before writing new code:

  1. Search for existing implementations
  2. Extract common patterns into reusable components
  3. Consider protocol extraction for shared behavior

Layer Responsibilities

Layer Contains Depends On
Views SwiftUI views, UI components State, Models
State @Observable stores, view models Models, Services
Services Business logic, networking, persistence Models
Models Data types, entities, DTOs Nothing
Protocols Interfaces for services and stores Models

Layer Rules

  1. Views are dumb renderers - No business logic. Read state and call methods.
  2. State holds business logic - Computations, validations, data transformations.
  3. Services are stateless - Pure functions where possible. Injected via protocols.
  4. Models are simple - Plain data types. No dependencies on UI or services.

Folder Structures

Choose based on project size and team structure:

Feature-First (Large Apps / Teams)

Best for: Multiple developers, features that could become SPM packages, complex apps.

App/
├── Shared/
│   ├── Design/           # Colors, typography, constants
│   ├── Protocols/        # Shared protocol definitions
│   ├── Services/         # Shared services (networking, auth)
│   └── Components/       # Shared UI components
└── Features/
    ├── Home/
    │   ├── Views/
    │   │   ├── HomeView.swift
    │   │   ├── Components/
    │   │   │   ├── HomeHeaderView.swift
    │   │   │   └── HomeCardView.swift
    │   │   └── Sheets/
    │   │       └── HomeFilterSheet.swift
    │   ├── Models/
    │   │   └── HomeItem.swift
    │   └── State/
    │       └── HomeStore.swift
    └── Profile/
        ├── Views/
        ├── Models/
        └── State/

Layer-First (Small/Medium Apps / Solo)

Best for: Solo developers, simpler apps, faster navigation.

App/
├── Design/               # Colors, typography, constants
├── Models/               # All data models
├── Protocols/            # All protocol definitions
├── Services/             # All services
├── State/                # All observable stores
└── Views/
    ├── Components/       # Shared reusable components
    ├── Sheets/           # Shared modal presentations
    ├── Home/             # Home feature views
    └── Profile/          # Profile feature views

Proactive Refactoring

The agent will actively identify and suggest fixes for these violations:

File Size Violations

When a file exceeds 300 lines, suggest specific extractions:

  • "This file is 450 lines. Consider extracting SomePrivateView (lines 200-280) to Components/SomePrivateView.swift"

Duplicate Code Detection

When similar code patterns appear:

  • "This filtering logic also exists in OtherStore.swift. Consider extracting to a shared protocol or utility."

View Struct Proliferation

When a view file contains multiple private struct definitions:

  • "This view has 5 private structs. Extract HeaderView, RowView, and FooterView to the Components/ folder."

Misplaced Business Logic

When business logic appears in views:

  • "This validation logic belongs in the Store, not the View. Move isValid computed property to FeatureStore."

Protocol Extraction Opportunities

When similar interfaces appear across types:

  • "Both UserService and TeamService have similar fetch/save patterns. Consider a Persistable protocol."

Naming Conventions

  • Views: FeatureNameView.swift, FeatureNameRowView.swift
  • Stores: FeatureNameStore.swift
  • Models: FeatureName.swift or FeatureNameModel.swift
  • Services: FeatureNameService.swift
  • Protocols: FeatureNameProviding.swift or Persistable.swift