Tca developer
Develop new features in a modular iOS app using The Composable Architecture (TCA) and Swift Package Manager. Use when implementing a new screen, adding a sub-feature, extending an existing reducer, adding SwiftUI previews, or writing TCA tests. Covers the full development workflow: reading the existing codebase, creating reducer + view files, wiring navigation, writing SwiftUI previews for all meaningful states (loaded, empty, error, and feature-specific variants), and writing TestStore tests. Always explore the target module before writing code to match its existing style and conventions.From its SKILL.md
npx -y skills add ninjaproger/skills --skill tca-developerAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
4.8 KB, ~1.0k tokens by cl100k_base, as published. Nobody here has run it
TCA Feature Development
Workflow
- Explore first — read the target module and its neighbours before writing anything
- Create the reducer — see
references/feature-template.md - Create the view — see
references/view-patterns.md - Add previews — one per meaningful state; see Preview Rules below
- Write tests — see
references/testing-patterns.md - Register — add target to
Package.swift; wire into parent if it's a new tab
Explore Before Writing
Before implementing any feature, read:
- An existing feature's reducer + view (understand current patterns)
- The parent module (understand how this feature is composed in)
Sources/Services/for available dependency clientsSources/Models/for the relevant data types
Reducer Checklist
@Reducermacro on astruct@ObservableStateonState, which conforms toEquatablepublic init() {}when all state fields have defaults; explicit memberwise init otherwise- Idempotency guard in
.onAppear:guard state.data == nil else { return .none } @Reducer enum Destinationwhen the feature navigates to children (@Presents+ifLet)delegate(Delegate)action +@CasePathable enum Delegatefor upward communicationcase .delegate: return .none— the reducer always ignores its own delegate cases- Capture dependencies explicitly in
.run:[client = someClient] - Errors stored as
String?viaerror.localizedDescription, not asErrortype
View Checklist
@Bindable var store: StoreOf<FeatureReducer>— always@Bindablepublic init(store:)— always explicit public initstore.send(.onAppear)in.onAppearmodifier- Use
Group { }for multi-branch body (loading / error / empty / content) - Use
ContentUnavailableViewfor error and empty states - Wire navigation destinations with
$store.scope(state:action:) - Toggle bindings:
Binding(get: { store.flag }, set: { _ in store.send(.toggleFlag) }) - Break complex body into
@ViewBuilder private varcomputed properties
Preview Rules
Every view must have at minimum 4 previews: loading (live reducer, fires .onAppear), content (pre-built state with sample data), empty, and any feature-specific variants (error, completed, failed, etc.).
- Wrap in
NavigationStack { }when the view uses.navigationTitleor.navigationDestination - Name format:
"FeatureName - StateName"e.g."Quiz - Partially Answered" - Do not use
withDependenciesin previews — use the live reducer directly - Add
static var sample: Self/static var samples: [Self]on model types for preview data
See references/feature-template.md for complete #Preview block templates (Patterns A–D).
Key Decisions
| Question | Answer |
|---|---|
| Reducer + View in one file? | Yes, when combined ≤ ~200 lines |
| Where do computed properties go? | On State, not the view |
| How to pass data to a child feature? | Initialize child's State when setting destination |
| How to communicate upward? | .delegate(Delegate) action |
| Where does error text live? | state.loadError: String? via error.localizedDescription |
| How to cancel in-flight effects? | .cancellable(id:, cancelInFlight: true) |
| Where do sub-view components live? | File-private structs in the same .swift file |
Should I use UIViewRepresentable? | Only when SwiftUI has no equivalent (e.g. MKMapView, WKWebView). Never for styling convenience. |
| Which concurrency primitive? | async/await + AsyncStream first; Combine only if the API has no async alternative; GCD/NSLock only for legacy C/ObjC callbacks |
Reference Files
references/feature-template.md— Complete file templates: reducer, view with previews, tests, Package.swift snippet, AppCore wiring. Read when starting a new feature from scratch.references/view-patterns.md— View sub-patterns: loading/error/empty states, navigation wiring, Toggle binding, private sub-views, file-local components, animation. Read when implementing or refining a view.references/testing-patterns.md— TestStore setup, dependency mocking, async flow testing, delegate testing, computed property tests, idempotency tests. Read when writing or debugging tests.
What ships with it: 3 files
34.4 KB alongside SKILL.md
references/
- feature-template.md13.9 KB
- testing-patterns.md8.9 KB
- view-patterns.md11.5 KB