The AGENTS.md running my shipping iOS app. Simulator names, the exact xcodebuild invocations, SwiftUI conventions the agent kept violating until they were written down, and a definition of done that includes a green test run.
Best for
Feature work and bug fixes in a single-target SwiftUI app. Less useful for multi-platform targets (watchOS/visionOS) — the destinations section needs extending for those.
- `Ledgerline/App/` — entry point, app-level state (`AppModel`), routing
- `Ledgerline/Features/` — one folder per screen; View + Model side by side
- `Ledgerline/Core/` — models, persistence (SwiftData), `APIClient`
- `Ledgerline/DesignSystem/` — colors, typography, reusable components. Do not define styles elsewhere.
- `LedgerlineTests/` — unit tests. `LedgerlineUITests/` — UI tests, slow, run only when asked.
02 · Build & test
- Build: `xcodebuild -scheme Ledgerline -destination 'platform=iOS Simulator,name=iPhone 16' -quiet build`
- Unit tests: `xcodebuild -scheme Ledgerline -destination 'platform=iOS Simulator,name=iPhone 16' -quiet test -only-testing:LedgerlineTests`
- Pipe both through `xcbeautify --quiet` when reading failures.
- After ANY .swift change: build. After changing logic in Core or a Model: run unit tests.
Raw file
AGENTS.md
History
v1.4
Added the snapshot re-record scoping rule after an agent re-recorded all 94 snapshots to hide one layout regression.
Jul 22, 2026
v1.3
Spelled out the @Observable migration ('do not add to the old pattern') — agents kept pattern-matching the legacy ObservableObject code.
Jun 9, 2026
v1.2
Added 'run fresh — do not trust a cached result' to done criteria after two false-green sessions.
May 5, 2026
Your report
Running this config?
Sign in to add your report — every count here is backed by a named account.
Discussion
03 · SwiftUI conventions
- State: `@Observable` model classes, owned by the View via `@State`. No new `ObservableObject`/`@Published` — we are mid-migration, do not add to the old pattern.
- Views are structs under 120 lines; extract subviews rather than nesting closures three deep.
- No `AnyView`. No `GeometryReader` where a layout container works.
- Colors and fonts come from `DesignSystem` (`Color.dsBackground`, `Font.dsBody`). Hex literals in a View are a review rejection.
- Strings shown to users go through `String(localized:)`.
04 · Testing rules
- New logic in `Core/` needs a unit test in the same PR. Views don't need tests; their Models do.
- Never weaken an assertion to make a test pass. If a test looks wrong, say so and stop.
- Snapshot tests live in `LedgerlineTests/Snapshots`. If your change breaks one, re-record ONLY the snapshots your change explains: `RECORD=1 xcodebuild ... -only-testing:LedgerlineTests/Snapshots`.
05 · Prohibited
- Do not edit `project.pbxproj` by hand beyond adding files you created.
- Do not add third-party dependencies. Propose them in the PR description instead.
- Do not touch `Ledgerline.entitlements`, provisioning, or anything under `fastlane/`.
- Do not re-record all snapshots wholesale.
06 · Definition of done
1. Builds with zero warnings introduced by your change.
2. `LedgerlineTests` green, run fresh — do not trust a cached result.
3. New user-facing strings localized; new colors/fonts routed through DesignSystem.
4. A short PR description: what changed, why, what you tested, anything you're unsure about.
# AGENTS.md — Ledgerline (iOS)
Personal-finance iOS app. SwiftUI, iOS 17+, no UIKit unless a section below says otherwise.
## Project map
- `Ledgerline/App/` — entry point, app-level state (`AppModel`), routing
- `Ledgerline/Features/` — one folder per screen; View + Model side by side
- `Ledgerline/Core/` — models, persistence (SwiftData), `APIClient`
- `Ledgerline/DesignSystem/` — colors, typography, reusable components. Do not define styles elsewhere.
- `LedgerlineTests/` — unit tests. `LedgerlineUITests/` — UI tests, slow, run only when asked.
## Build & test
- Build: `xcodebuild -scheme Ledgerline -destination 'platform=iOS Simulator,name=iPhone 16' -quiet build`
- Unit tests: `xcodebuild -scheme Ledgerline -destination 'platform=iOS Simulator,name=iPhone 16' -quiet test -only-testing:LedgerlineTests`
- Pipe both through `xcbeautify --quiet` when reading failures.
- After ANY .swift change: build. After changing logic in Core or a Model: run unit tests.
## SwiftUI conventions
- State: `@Observable` model classes, owned by the View via `@State`. No new `ObservableObject`/`@Published` — we are mid-migration, do not add to the old pattern.
- Views are structs under 120 lines; extract subviews rather than nesting closures three deep.
- No `AnyView`. No `GeometryReader` where a layout container works.
- Colors and fonts come from `DesignSystem` (`Color.dsBackground`, `Font.dsBody`). Hex literals in a View are a review rejection.
- Strings shown to users go through `String(localized:)`.
## Testing rules
- New logic in `Core/` needs a unit test in the same PR. Views don't need tests; their Models do.
- Never weaken an assertion to make a test pass. If a test looks wrong, say so and stop.
- Snapshot tests live in `LedgerlineTests/Snapshots`. If your change breaks one, re-record ONLY the snapshots your change explains: `RECORD=1 xcodebuild ... -only-testing:LedgerlineTests/Snapshots`.
## Prohibited
- Do not edit `project.pbxproj` by hand beyond adding files you created.
- Do not add third-party dependencies. Propose them in the PR description instead.
- Do not touch `Ledgerline.entitlements`, provisioning, or anything under `fastlane/`.
- Do not re-record all snapshots wholesale.
## Definition of done
1. Builds with zero warnings introduced by your change.
2. `LedgerlineTests` green, run fresh — do not trust a cached result.
3. New user-facing strings localized; new colors/fonts routed through DesignSystem.
4. A short PR description: what changed, why, what you tested, anything you're unsure about.
Discussion · 3 comments
Strong evidence gets promoted into the record above.
It holds because of the second clause — 'rather than nesting closures three deep' anchors WHY to extract. Without a reason, agents treat the number as a game to win. If yours over-extracts, add 'prefer fewer, larger subviews with clear names over many trivial ones'.
The 'mid-migration, do not add to the old pattern' line is quietly the best idea here. Agents imitate whatever's most common in the codebase — during a migration that's the OLD pattern by definition. Stating the direction of travel fixes it.
21
Sign in to join the discussion, vote, and verify fixes.
Does the 120-line view rule actually hold? My agent extracts subviews so aggressively I end up with 15-file screens.
It holds because of the second clause — 'rather than nesting closures three deep' anchors WHY to extract. Without a reason, agents treat the number as a game to win. If yours over-extracts, add 'prefer fewer, larger subviews with clear names over many trivial ones'.