|
| 1 | +# Repository Guidelines |
| 2 | + |
| 3 | +This file is operating guidance for agents and contributors working in `PersistentKeyValueKit`. Keep changes small, explicit, and aligned with the package’s public API guarantees. |
| 4 | + |
| 5 | +> [!IMPORTANT] |
| 6 | +> Use relevant Agent Skills before changing Swift APIs, concurrency code, tests, or technical prose. They capture platform rules and local preferences that code search does not reliably reveal. |
| 7 | +
|
| 8 | +## Overview |
| 9 | + |
| 10 | +`PersistentKeyValueKit` is a Swift Package Manager library for type-safe persistence on Apple platforms. It wraps `UserDefaults` and `NSUbiquitousKeyValueStore`, provides SwiftUI property wrappers, and exposes async observation for persistent key changes. |
| 11 | + |
| 12 | +- **Swift tools version**: 6.2 |
| 13 | +- **Platforms**: `Package.swift` is the source of truth. |
| 14 | +- **Product**: `PersistentKeyValueKit` |
| 15 | +- **Tests**: XCTest |
| 16 | +- **Runtime resources**: none |
| 17 | + |
| 18 | +## Core Rules |
| 19 | + |
| 20 | +Keep call sites typed. Consumers define a key once, then use that key to read, write, bind, or observe values. Store internals stay inside the package. |
| 21 | + |
| 22 | +Treat public API changes as release decisions. Before adding requirements, changing defaults, renaming symbols, or raising platform minimums, identify the compatibility impact and document the reason. |
| 23 | + |
| 24 | +Do not leak Foundation storage quirks into user-facing APIs. Handle normalization, launch-argument coercion, observation filtering, cancellation, and deregistration inside the package. |
| 25 | + |
| 26 | +## Repository Structure |
| 27 | + |
| 28 | +```text |
| 29 | +├── Package.swift |
| 30 | +├── README.md |
| 31 | +├── Sources/PersistentKeyValueKit/ |
| 32 | +│ ├── Async Sequence/ |
| 33 | +│ ├── Key-Value Persistible/ |
| 34 | +│ ├── Persistent Key/ |
| 35 | +│ ├── Persistent Key-Value Representation/ |
| 36 | +│ ├── Persistent Key-Value Store/ |
| 37 | +│ └── Property Wrapper/ |
| 38 | +└── Tests/PersistentKeyValueKitTests/ |
| 39 | + ├── Scaffolding/ |
| 40 | + └── Tests/ |
| 41 | +``` |
| 42 | + |
| 43 | +Source folders are grouped by feature area. Put new code beside the feature it extends. Keep reusable mocks, observable stores, and custom persistible types in `Tests/PersistentKeyValueKitTests/Scaffolding/`. |
| 44 | + |
| 45 | +## Architecture |
| 46 | + |
| 47 | +`PersistentKeyProtocol` models typed keys. `PersistentKeyValueStore` defines storage operations. `KeyValuePersistible` and `PersistentKeyValueRepresentation` define conversion between Swift values and property-list-compatible storage. |
| 48 | + |
| 49 | +Concrete stores stay thin: |
| 50 | + |
| 51 | +- `UserDefaults`: Foundation defaults plus KVO observation. |
| 52 | +- `NSUbiquitousKeyValueStore`: iCloud key-value storage plus notification observation. |
| 53 | +- `InMemoryPersistentKeyValueStore`: test and ephemeral storage. |
| 54 | + |
| 55 | +Keep `PersistentValue` and `PersistentKeyValues` behavior aligned. SwiftUI observation and async observation should agree on defaults, emitted values, unrelated-key filtering, cancellation, and deregistration unless the difference is intentional and documented. |
| 56 | + |
| 57 | +## Development Commands |
| 58 | + |
| 59 | +Run from the repository root. |
| 60 | + |
| 61 | +```sh |
| 62 | +swift build |
| 63 | +swift test |
| 64 | +swift test --filter PersistentKeyValuesTests |
| 65 | +swift test -c release |
| 66 | +swift test -Xswiftc -strict-concurrency=complete -Xswiftc -warn-concurrency -Xswiftc -enable-actor-data-race-checks |
| 67 | +``` |
| 68 | + |
| 69 | +Use the filtered command while iterating. Use strict-concurrency tests for observation, locking, cancellation, or sendability changes. Use release tests for performance-sensitive changes. |
| 70 | + |
| 71 | +## Programming |
| 72 | + |
| 73 | +Preserve existing Swift style: 4-space indentation, grouped declarations, and `// MARK:` sections. Public types use `UpperCamelCase`; properties, functions, and tests use `lowerCamelCase`. |
| 74 | + |
| 75 | +Use the static accessor pattern for reusable keys: |
| 76 | + |
| 77 | +```swift |
| 78 | +extension PersistentKeyProtocol where Self == PersistentKey<Bool> { |
| 79 | + static var isFeatureEnabled: Self { |
| 80 | + Self("IsFeatureEnabled", defaultValue: false) |
| 81 | + } |
| 82 | +} |
| 83 | +``` |
| 84 | + |
| 85 | +Check availability before using new Apple APIs. Support every platform minimum in `Package.swift`, or add guarded fallbacks. |
| 86 | + |
| 87 | +Do not add `Sendable` requirements to public value protocols unless the compatibility cost is intentional. Protect shared mutable state explicitly; Foundation store integrations should not force consumers into actor isolation. |
| 88 | + |
| 89 | +Use comments for nonobvious whys only. Public documentation comments should describe behavioral contracts, especially observation lifetime, buffering, storage conversion, and compatibility constraints. |
| 90 | + |
| 91 | +## Testing |
| 92 | + |
| 93 | +Add focused XCTest coverage for every behavior change. Use unique keys such as `key:\(#function)` to avoid cross-test state leakage. |
| 94 | + |
| 95 | +For store behavior, test each affected store. For async observation, cover initial emission, change-only streams, buffering, unrelated keys, cancellation, iterator deinitialization, deregistration, and concurrent cancellation/change races. |
| 96 | + |
| 97 | +## Contributing |
| 98 | + |
| 99 | +Recent commits use short imperative subjects: `Fix UserDefaults launch argument parsing`, `Improve hot path performance`. Match that style and never credit tools or agents. |
| 100 | + |
| 101 | +Before committing, run: |
| 102 | + |
| 103 | +```sh |
| 104 | +git log --oneline -10 |
| 105 | +git status --short |
| 106 | +``` |
| 107 | + |
| 108 | +Pull requests must list behavior changes, test commands run, and any public API, platform minimum, concurrency, or versioning impact. |
| 109 | + |
| 110 | +## Prose |
| 111 | + |
| 112 | +Read surrounding prose before editing `README.md`, `AGENTS.md`, or long doc comments. Integrate changes into the document’s structure; do not append isolated notes. Tighten wording by default. |
| 113 | + |
| 114 | +Watch for **phantom rationale**: prose that invents a reason for an API shape instead of stating the fact. If an API has two equivalent spellings, say that. Do not explain it with a fake workflow preference. |
| 115 | + |
| 116 | +## Agent-Specific Instructions |
| 117 | + |
| 118 | +Do not overwrite unrelated local changes. Commit when asked. Do not push unless explicitly requested. |
0 commit comments