agentleFS
everpcpceverpcpc/KMReader/AGENTS.md

KMReader

AGENTS.md118 starsChanged 7 days agoMITView on GitHub

Rules that must not be violated when working in this repository. For architecture and feature details, read the code. Subsystem conventions and invariants live in the repo-conventions skill (.agents/skills/repo-conventions/SKILL.md) — load it when working on the reader, sync/offline/persistence, dashboard, detail pages, or platform UI placement. KMReader is a native SwiftUI client for Komga. iOS 17+ / macOS 14+ / tvOS 17+, Swift 6, Xcode 15+. There are no XCTest targets: validate with builds and manual testing. All builds run through…

  • Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.

    Of the AGENTS.md files we read, the 31,439 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.

  • In this repository8 other files it gives its agents.

The file

We split this AGENTS.md into the rules it gives an agent

11 rules. About 0 are common, 2 are distinctive, and 9 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈2

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 9

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    All builds run through the Makefile (wrapping misc/xcode.py).

    line 11
  2. Very specific:

    After changing code: make format, then make build.

    line 26
  3. Very specific:

    Git-facing text: commit messages, PR titles/bodies, and review comments are always in English.

    line 31
  4. Distinctive:

    No stored variables in view bodies.

    line 38
  5. Very specific:

    Do not store async/throwing/@Sendable closures in SwiftUI View value types (iOS 17 AttributeGraph crash risk).

    line 43
  6. Very specific:

    No patch-style fixes for structural problems — no compensating flags/delays/counters around a broken ownership boundary.

    line 45
  7. Very specific:

    When a change alters a lifetime, ownership, persistence, navigation, platform, reader-mode, or UI-placement boundary, update the …

    line 47
  8. Distinctive:

    No hand-rolled fallback shims for newer OS APIs.

    line 48
  9. Very specific:

    Never render an empty HStack/VStack.

    line 50
  10. Very specific:

    All logging goes through AppLogger (OSLog subsystems/categories).

    line 61
  11. Very specific:

    When building JSON strings for storage or cache keys, use JSONSerialization with sortedKeys for stable raw values.

    line 65

≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
AGENTS.md

AGENTS.md

Rules that must not be violated when working in this repository. For architecture and feature details, read the code. Subsystem conventions and invariants live in the repo-conventions skill (.agents/skills/repo-conventions/SKILL.md) — load it when working on the reader, sync/offline/persistence, dashboard, detail pages, or platform UI placement.

Project

KMReader is a native SwiftUI client for Komga. iOS 17+ / macOS 14+ / tvOS 17+, Swift 6, Xcode 15+. There are no XCTest targets: validate with builds and manual testing.

Commands

All builds run through the Makefile (wrapping misc/xcode.py); never invoke xcodebuild directly.

make build          # build all platforms (preferred validation)
make build-ios      # platform-specific; run sequentially, never in parallel
make build-macos    #   (xcodebuild shares one DerivedData database)
make build-tvos
make run-ios-sim / make run-macos / make run-tvos-sim   # run (device choice persisted in devices.json)
make format         # format code after editing
make localize       # update localizations; ./misc/translate.py list|update for keys
make bump / make minor / make major   # version management

Never edit MARKETING_VERSION or CURRENT_PROJECT_VERSION in project.pbxproj by hand. Run make bump only when the user explicitly asks; the bump commit then rides along in the feature/fix PR, not a separate PR. When several PRs queue up at once, either fold a new change into an existing PR or move the bump commit to the last PR in the queue — the bump always lands on whichever PR merges last.

After changing code: make format, then make build. Simulator interaction goes through baguette (see the simulator skill): filter logs with subsystem com.everpcpc.kmreader (categories API, SSE, ReaderViewModel).

Coding Conventions

  1. Comments: minimal, English only; no issue/PR numbers (link issues in the PR description instead).
  2. Git-facing text: commit messages, PR titles/bodies, and review comments are always in English. Never add Co-Authored-By trailers to commits.
  3. UI frameworks: SwiftUI, UIKit, and AppKit are all acceptable; pick per feature and platform.
  4. No inline Binding.
  5. No confirmationDialog.
  6. One type per file.
  7. State: @Observable, never ObservableObject.
  8. Preferences: @AppStorage in views, AppConfig elsewhere; UserDefaults only inside AppConfig.swift.
  9. No stored variables in view bodies; avoid computed-property clutter there too.
  10. Platform differences via PlatformHelper and #if os(...).
  11. UIKit/AppKit interop in either direction is fine; be explicit about dependency injection and verify environment/data propagation across hosting boundaries.
  12. Banned: non-optional object-style environment dependencies (@Environment(SomeType.self), @EnvironmentObject). Pass objects via initializers, context structs, or action closures; use non-object custom EnvironmentKeys when needed.
  13. Banned: @unchecked Sendable, nonisolated(unsafe), unsafeBitCast, other unsafe* escape hatches. Redesign instead.
  14. Do not store async/throwing/@Sendable closures in SwiftUI View value types (iOS 17 AttributeGraph crash risk); use concrete command types or passed-in services.
  15. Animation boundaries: local implicit .animation(..., value:) only for micro-interactions (press/hover/selected states); explicit withAnimation {} for navigation, presentation, content, and pagination changes. No broad/root .animation on containers rendering lists. @AppStorage-backed lists are the exception: UserDefaults writes carry no transaction, so withAnimation cannot animate them — drive row/section changes there with .animation(_:value:) on the list container, scoped to the changing value. Never wrap paginated List row insertions in withAnimation — inserted rows animate from compressed to natural height, which reads as rows jumping taller after the page settles.
  16. No patch-style fixes for structural problems — no compensating flags/delays/counters around a broken ownership boundary. Refactor toward the stable architecture even when it means rewriting a subsystem; end-state quality beats diff size.
  17. Temporary compatibility layers must say why they exist and what replaces them; treat them as debt.
  18. When a change alters a lifetime, ownership, persistence, navigation, platform, reader-mode, or UI-placement boundary, update the conventions in the same change: AGENTS.md for repo-wide rules, the repo-conventions skill for subsystem boundaries.
  19. No hand-rolled fallback shims for newer OS APIs; gate features to the OS version that supports them natively.
  20. No force casts (as!), especially on GRDB Row subscripts; use the generic converting subscript (let date: Date = row["created_date"]) or as? with a fallback.
  21. Never render an empty HStack/VStack; put the condition around the stack itself so nothing renders when there is no content.
  22. Lazy containers (LazyVStack/LazyHStack/LazyVGrid) only for genuinely unbounded content (paginated or otherwise huge lists); eager stacks everywhere else — lazy stacks cache child frames and misplace children during animated layout updates.
  23. Plain-style buttons and links (.buttonStyle(.plain), text-or-label-only) must declare .contentShape(Rectangle()) (or an equivalent hit shape) on the content inside the button's label so the whole frame is tappable; without it only the glyphs respond. .contentShape applied outside on the button itself has no effect on hit-testing, regardless of button style.
  24. Hardcoded .frame sizes are a last resort: never pin pixel dimensions to paper over a sizing difference (e.g. normalizing buttons whose glyphs have different bounding boxes). Fix the cause instead — pick glyphs from one visual family, use control sizes, or change the layout.
  25. Banned: fatalError/preconditionFailure in app logic — a reachable one crashes the app. Model impossible cases away instead (narrower enums, exhaustive switches). Exception: required init?(coder:) stubs.
  26. Button styles: style buttons with .adaptiveButtonStyle(_:), never .buttonStyle(...) directly. The adaptive style picks the glass styles on OS 26 and pairs the prominent tint with a readable foreground; a raw .borderedProminent renders white on white with the white accent in dark mode. Use a raw style only where no adaptive case fits (e.g. .borderless for an action inside a Form row, which must not take the whole row's tap), and say why in a comment.

Additional patterns:

  • Pass shared object dependencies explicitly at split/tab roots, NavigationStack roots, sheets, full-screen covers, scene boundaries, and any UIHostingController/NSHostingController boundary; do not assume environment inheritance survives snapshot/rotation/scene transitions.
  • New API endpoints belong in the appropriate service; keep request-building out of views.
  • All logging goes through AppLogger (OSLog subsystems/categories); user-visible errors through ErrorManager.shared (notify for transient success).
  • The Xcode project uses folder references (not groups); adding/removing files does not require editing project.pbxproj.
  • Translate all supported languages after changing UI strings (see the localization skill).
  • Localization keys must be static literals: the strings extractor cannot see a key computed at runtime (e.g. a ternary inside String(localized:)), so the catalog entry gets flagged extractionState: stale on every make localize and risks deletion as unused. Branch outside the call, with one String(localized:) per literal.
  • When building JSON strings for storage or cache keys, use JSONSerialization with sortedKeys for stable raw values.
  • Types persisted through RawCodableStore and also conforming to RawRepresentable must provide their own keyed init(from:) and encode(to:); never encode self from rawValue, because that re-enters encoding and overflows the stack. Scalar catalog DTOs such as ModelEngine and ModelPurpose still use single-value containers.
  • Colors that vary only between light and dark mode belong in Assets.xcassets as color sets with light/dark appearances, referenced as Color.<name> — not colorScheme branching in views. Assets also carry alpha and can encode gradient-stop pairs (start/end as two assets). Reserve colorScheme reads for layout or logic differences; clusters of one-off decorative tints serving a single view may stay local.
  • SF Symbol fill/outline is a rendering concern, not data: models and enums expose the base (outline) symbol name, and the site that knows its rendering context applies .symbolVariant(.fill) — never thread hardcoded *.fill names or parallel filled-name parameters through view APIs. Exception: an icon filled in every context is part of the status's identity (e.g. checkmark.icloud.fill, exclamationmark.circle.fill in download statuses); models may return the .fill name directly.
  • Icon names with a shared meaning go through constants, not string literals: AppIcon (actions, statuses, errors) and ContentIcon (content types) in Shared/Helpers, and ReadStatus.icon / SeriesStatus.icon on the models. Add a constant when a glyph is used across features; one-off decorative glyphs (section identities, form rows) stay inline.
  • Standard animation curves are Animation.appCurve(_:) (quick UI transitions) and Animation.appSpring (overdamped, gesture-interruptible motion) — prefer them over ad-hoc .easeInOut/.snappy in new transitions. Haptics go through HapticFeedback (Shared/Helpers) and fire only on discrete boundary crossings, never on continuous motion.
  • High-frequency progress-style updates (transfer progress, meters, byte counters) must be throttled at the source before reaching UI state: cap the rate (e.g. 10 Hz) and always emit the first and final values. Never forward raw callback frequency into view state. Animation is exempt.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.