From 846d331be095f5d79256560a06abb13718f574ea Mon Sep 17 00:00:00 2001 From: Fernando Fernandes Date: Tue, 21 Jul 2026 13:58:10 +0200 Subject: [PATCH 1/6] Squashed 'AgentGuidelines/' content from commit f5e7da0 git-subtree-dir: AgentGuidelines git-subtree-split: f5e7da011a1449715b9fff9742a0a5104ef087ae --- .github/workflows/ci.yml | 21 +++ .gitignore | 2 + AGENTS.md | 38 +++++ CHANGELOG.md | 12 ++ Guidelines/Architecture/Redux.md | 231 ++++++++++++++++++++++++++++++ Guidelines/CICD.md | 39 +++++ Guidelines/Documentation.md | 35 +++++ Guidelines/Packages.md | 48 +++++++ Guidelines/Swift/Localization.md | 43 ++++++ Guidelines/Swift/Swift.md | 35 +++++ Guidelines/Swift/SwiftLint.md | 8 ++ Guidelines/Swift/SwiftStyle.md | 25 ++++ Guidelines/Swift/SwiftUI.md | 61 ++++++++ Guidelines/Testing/UnitTesting.md | 50 +++++++ Guidelines/Xcode/MCP.md | 65 +++++++++ Guidelines/Xcode/Security.md | 35 +++++ LICENSE | 22 +++ README.md | 129 +++++++++++++++++ Scripts/validate_guidelines.py | 119 +++++++++++++++ Templates/AGENTS.md | 39 +++++ VERSION | 2 + 21 files changed, 1059 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 .gitignore create mode 100644 AGENTS.md create mode 100644 CHANGELOG.md create mode 100644 Guidelines/Architecture/Redux.md create mode 100644 Guidelines/CICD.md create mode 100644 Guidelines/Documentation.md create mode 100644 Guidelines/Packages.md create mode 100644 Guidelines/Swift/Localization.md create mode 100644 Guidelines/Swift/Swift.md create mode 100644 Guidelines/Swift/SwiftLint.md create mode 100644 Guidelines/Swift/SwiftStyle.md create mode 100644 Guidelines/Swift/SwiftUI.md create mode 100644 Guidelines/Testing/UnitTesting.md create mode 100644 Guidelines/Xcode/MCP.md create mode 100644 Guidelines/Xcode/Security.md create mode 100644 LICENSE create mode 100644 README.md create mode 100644 Scripts/validate_guidelines.py create mode 100644 Templates/AGENTS.md create mode 100644 VERSION diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..4c01b13 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,21 @@ +name: CI + +on: + pull_request: + push: + branches: + - main + +permissions: + contents: read + +jobs: + validate: + name: Validate guidelines + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Validate + run: python3 Scripts/validate_guidelines.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ca0973 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.DS_Store + diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..e007fd3 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,38 @@ +# Agent Guidelines + +## Purpose + +This public repository is the versioned source of truth for reusable ThatFactory agent guidance. Keep it generic enough to apply to multiple applications and Swift packages. Product decisions, concrete project paths, and exceptions belong in each consumer repository. + +## Sources of truth + +- Use official Apple documentation for Apple APIs and Xcode behavior. +- Distill durable policy from Xcode-provided skills; do not copy exported Apple skills into this repository. +- Do not include private company information, credentials, personal absolute paths, or consumer-specific implementation details. +- When shared and consumer guidance differ, the consumer's nearest applicable `AGENTS.md` is the explicit specialization. + +## Documentation changes + +- Keep each rule in the narrowest relevant guide and link to it rather than duplicating it. +- Use physical folder terminology for Xcode projects. Do not call filesystem folders Xcode groups. +- Keep examples generic and concise. +- Use relative Markdown links inside this repository. +- Update `README.md` when adding, moving, or removing a guide. +- Update `CHANGELOG.md` and `VERSION` for a release. + +## Validation + +Run: + +```sh +python3 Scripts/validate_guidelines.py +``` + +Fix every validation failure before releasing a version. + +## Releases + +- Use semantic versioning. +- Create a Git tag and GitHub release matching `VERSION`. +- Consumer repositories adopt releases deliberately through Git subtree updates. + diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..7e24a78 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,12 @@ +# Changelog + +All notable changes to this project are documented in this file. + +## [0.0.1] - 2026-07-21 + +### Added + +- Initial shared guidelines for Redux, Swift, SwiftUI, SwiftLint, localization, testing, documentation, package maintenance, CI/CD, Xcode MCP, and Xcode security audits. +- A consumer `AGENTS.md` template and Git subtree installation workflow. +- Structural validation for links, the documentation catalog, version metadata, subtree instructions, and public-repository safety. + diff --git a/Guidelines/Architecture/Redux.md b/Guidelines/Architecture/Redux.md new file mode 100644 index 0000000..089528d --- /dev/null +++ b/Guidelines/Architecture/Redux.md @@ -0,0 +1,231 @@ +# Redux Architecture + +Use this guide for applications that explicitly adopt the ThatFactory Redux architecture. Do not apply it to reusable packages or repositories whose local instructions choose another architecture. + +## Principles + +- Keep one application store as the source of truth for durable application state. +- Views read state and dispatch actions; they do not mutate application state directly. +- Actions describe events or intent, not implementation steps. +- Reducers are pure and synchronous. +- Middleware performs asynchronous work and other side effects. +- Services wrap external frameworks, packages, persistence, clocks, APIs, and system capabilities. +- Selectors derive shared domain information from state. +- Render-ready view state and view-only projections live beside their consuming views. +- Every side-effect result returns to the store as an action before it changes state. + +## Data flow + +```text + await dispatch(Action) + +--------------+ --------------------------> +-----------+ + | SwiftUI view | | Store | + | | <-------------------------- | | + +--------------+ observable state | 1. Reducer| + | 2. Middle-| + | ware | + +-----+-----+ + | + | side effect + v + +--------------+ + | Service | + | package/API | + +------+-------+ + | + | Action? + v + Store again +``` + +The store reduces the original action first, then awaits middleware and sequentially dispatches returned follow-up actions. Keep ordering observable and deterministic. Do not start unstructured work inside reducers or hide state changes inside services. + +## Canonical physical folders + +These are filesystem folders, not Xcode groups. New single-application repositories use this structure by default: + +```text +/ +|-- App/ +|-- Model/ +|-- Redux/ +| |-- Action/ +| |-- Middleware/ +| |-- Reducer/ +| |-- Selector/ +| |-- State/ +| `-- Store.swift +|-- Services/ +|-- Tools/ +|-- View/ +| `-- / +`-- Resources/ + +Tests/ +|-- Mocks/ +|-- Model/ +|-- Redux/ +| |-- Action/ +| |-- Middleware/ +| |-- Reducer/ +| |-- Selector/ +| `-- State/ +|-- Services/ +|-- Tools/ +`-- View/ + `-- / +``` + +A multi-target application may use a shared source root such as `Shared/Redux/` and target-specific roots such as `/View/`. Its root `AGENTS.md` must provide a concrete path map: + +```markdown +| Role | Physical folder | +|---|---| +| Redux | `Shared/Redux/` | +| Models | `Shared/Model/` | +| Services | `Shared/Services/` | +| Views | `/View/` | +| Unit tests | `Tests/` | +``` + +Once mapped, use the same component layout beneath those roots. Never guess a destination or create a parallel folder spelling such as `Views/` when the project declares `View/`. + +## Placement rules + +### App + +Put application bootstrap, app delegates, scene definitions, store construction, environment wiring, and root configuration in `App/`. Do not place feature logic there. + +### Model + +Put reusable domain values in `Model/`. Keep each important type in a focused file. Do not hide response models, payloads, or domain values inside action or service files merely because only one caller currently uses them. + +### Action + +Put domain action enums in `Redux/Action/`. Use a root routing action that wraps focused feature actions: + +```swift +enum AppAction: Equatable { + case account(AccountAction) + case navigation(NavigationAction) +} +``` + +Name actions after what happened or what the user requested. Keep cases in the order required by the project's Swift style guide. + +### State + +Put the root state and domain sub-states in `Redux/State/`. Prefer focused value types with compiler-synthesized conformances. Add a new sub-state for a durable domain instead of folding unrelated values into an existing feature. + +State stores durable facts. Avoid storing values that are cheap, deterministic derivations unless caching is an explicit measured requirement. + +### Reducer + +Put reducer functions in `Redux/Reducer/`. A reducer receives state and an action and returns new state. It must not: + +- perform asynchronous work; +- call services or packages; +- read the clock or generate random values; +- access files, databases, network clients, or system APIs; +- dispatch actions; +- trigger UI behavior directly. + +Use the smallest state and action inputs that correctly express the transition. Root reducers compose domain reducers. + +### Middleware + +Put middleware in `Redux/Middleware/`. Middleware may call injected services and return a follow-up action. It must not mutate store state directly. + +Inject services, clocks, identifier generators, and providers through parameters so middleware tests remain deterministic. Register middleware in one root composition file such as `AppMiddlewares.swift`. + +Create a feature subfolder when a domain has multiple middleware files: + +```text +Redux/Middleware/Account/ +|-- AccountMiddleware.swift +|-- LoadAccountMiddleware.swift +`-- UpdateAccountMiddleware.swift +``` + +### Selector + +Put pure, reusable domain extraction in `Redux/Selector/`. A selector may answer questions such as the current signed-in account, whether a capability is enabled, or which domain items are visible. + +Do not put SwiftUI types, colors, images, localized display strings, or render-ready screen state in selectors. + +### Services + +Put focused external-boundary abstractions in `Services//`. Services wrap APIs, persistence, packages, frameworks, sensors, system features, and other impure operations. Middleware calls services; views and reducers do not. + +Prefer a protocol or otherwise injectable contract when a service must be replaced in tests. Keep transport-specific details behind the service boundary. + +### Tools + +Put genuinely cross-cutting implementation utilities in `Tools/`. This is not a miscellaneous folder. Feature-only formatters, helpers, constants, or factories stay beside that feature. Promote them to `Tools/` only after they have a clear cross-feature role. + +### View + +Put SwiftUI screens and components in `View//`. A new view belongs to the feature it renders, not in Redux. Reusable visual components may use `View/Generic/` or another explicitly declared shared-view folder. + +Render-facing view-state types and projections live beside the consuming view: + +```text +View/Account/ +|-- AccountView.swift +|-- AccountViewState.swift +`-- AccountViewStateProjection.swift +``` + +If a projection exists only to render one screen, it is view-layer code even when its input is `AppState`. + +### Resources + +Put catalogs, assets, preview assets, configuration resources, and test plans in `Resources/` or the concrete resource folders declared locally. Production targets must not depend on test fixtures. + +## File organization + +- Prefer one primary concern per file. +- When a feature has several files of one Redux component, introduce a feature subfolder under that component. +- Keep root routing and composition at the component root; keep feature implementations below it. +- File names match their primary type or clearly describe their primary pure function. +- Do not introduce artificial enum namespaces solely to satisfy filename lint rules. +- Mirror production organization in tests so components are easy to locate. + +## SwiftUI connection + +Create and inject the store at the application root. Views observe only the state they need and dispatch actions for application events. + +Keep view-local interaction state in private `@State` when it is not durable application state. Do not create an `@Observable` view model as a second source of truth for Redux-owned state. + +Prefer narrow view inputs or a focused view-state projection. This aligns SwiftUI invalidation with the smallest useful surface while Redux remains the durable source of truth. + +## Adding a feature + +| Step | Change | Default destination | +|---|---|---| +| 1 | Define domain models | `Model//` | +| 2 | Define feature state | `Redux/State/State.swift` | +| 3 | Add it to root state | `Redux/State/AppState.swift` | +| 4 | Define feature actions | `Redux/Action/Action.swift` | +| 5 | Route them through the root action | `Redux/Action/AppAction.swift` | +| 6 | Implement the reducer | `Redux/Reducer/Reducer.swift` | +| 7 | Compose the reducer | `Redux/Reducer/AppReducer.swift` | +| 8 | Add side effects if needed | `Redux/Middleware//` | +| 9 | Register middleware | `Redux/Middleware/AppMiddlewares.swift` | +| 10 | Add external boundaries if needed | `Services//` | +| 11 | Add shared domain selectors if needed | `Redux/Selector//` | +| 12 | Build the feature UI | `View//` | +| 13 | Mirror tests | `Tests/` | + +Skip components that provide no value. A state-only transition needs no middleware; a screen-only projection does not need a Redux selector. + +## Testing responsibilities + +- Reducer tests provide state plus an action and assert the returned state. +- Selector tests provide state and assert the derived domain result. +- Middleware tests inject mocks, execute an action, and assert the returned follow-up action. +- Service tests exercise the external boundary without involving views. +- View-state projection tests live under the matching `Tests/View//` folder. +- Test mocks and fixture data live under the test target's `Mocks/` folder. + +Follow [Unit testing](../Testing/UnitTesting.md) for framework and concurrency conventions. diff --git a/Guidelines/CICD.md b/Guidelines/CICD.md new file mode 100644 index 0000000..50322b5 --- /dev/null +++ b/Guidelines/CICD.md @@ -0,0 +1,39 @@ +# CI/CD + +## Workflow principles + +- Keep CI deterministic, reproducible, and aligned with the repository's supported Xcode, Swift, and platform versions. +- Treat warnings introduced by a change as failures even when the compiler does not. +- Prefer the smallest permissions required by each workflow and job. +- Pin third-party actions to an intentional version and review updates. +- Do not place secrets in workflow files, logs, fixtures, or command arguments that may be echoed. +- Keep release workflows separate from pull-request validation when their permissions differ. + +## Pull-request CI + +A typical Swift package validates: + +- package resolution; +- build; +- Swift Testing tests; +- DocC generation when the package publishes documentation; +- repository-specific lint or validation scripts. + +An Xcode application validates its declared scheme and test plan. Use the same project/workspace, configuration, and platform assumptions documented for local development. + +## Investigation + +1. Identify the first meaningful failing step rather than treating later cancellations as independent failures. +2. Reproduce locally with the closest supported toolchain when practical. +3. Separate infrastructure or dependency-resolution failures from code failures. +4. Fix the root cause in the narrowest appropriate layer. +5. Re-run the affected local validation before relying on remote CI. +6. Update durable CI documentation when the workflow or investigation process changes. + +## Releases + +- A release tag and GitHub release must match the intended semantic version. +- Release notes summarize user- or integrator-relevant changes since the previous release. +- Use a notes file for multiline CLI release descriptions. +- Do not publish a release from an unverified or dirty worktree. +- Follow the consumer's local instructions for deployment, signing, notarization, App Store, or documentation publishing steps. diff --git a/Guidelines/Documentation.md b/Guidelines/Documentation.md new file mode 100644 index 0000000..b988361 --- /dev/null +++ b/Guidelines/Documentation.md @@ -0,0 +1,35 @@ +# Documentation + +## Code-level documentation + +- Document structs, classes, enums, protocols, actors, and other significant types with focused `///` DocC comments. +- Update documentation when changing a documented API, parameter, behavior, or invariant. +- End documentation sentences with periods. +- Explain intent, contracts, units, side effects, isolation, and non-obvious constraints; do not restate syntax. +- Add a short Swift example when it materially clarifies correct use. +- Keep documentation close to the declaration it describes. + +## Project-level documentation + +- Keep durable architecture and cross-cutting guides in the consumer's declared documentation folder. +- Update a guide when a change alters the documented architecture, data flow, public API, persistence, navigation, localization process, testing workflow, or delivery workflow. +- Do not update broad guides for minor implementation changes already explained by code and DocC. +- Remove or rewrite stale documentation when its feature or workflow is removed. +- Keep investigations, temporary plans, and one-time spike notes out of durable documentation unless they become lasting guidance. +- Prefer ASCII diagrams in fenced code blocks when universal rendering matters. + +## Review checklist + +When reviewing a change, ask: + +- Does it alter a documented public API or invariant? +- Does it introduce a reusable architectural pattern? +- Does it change data flow, ownership, persistence, localization, testing, or delivery? +- Does it remove or supersede an existing guide? +- Are code comments and project guides consistent with the implementation? + +Flag missing documentation only when the change affects durable knowledge. Avoid documentation churn for small fixes. + +## Shared versus local guidance + +This repository owns reusable policy. Consumer documentation owns its product domain, concrete paths, package relationships, feature registries, and explicit exceptions. Link across those layers instead of copying shared prose locally. diff --git a/Guidelines/Packages.md b/Guidelines/Packages.md new file mode 100644 index 0000000..c21f43e --- /dev/null +++ b/Guidelines/Packages.md @@ -0,0 +1,48 @@ +# Swift Packages + +## Package boundaries + +- Keep a reusable package focused on one coherent capability. +- Prefer UI-agnostic domain APIs unless UI is the package's explicit purpose. +- Do not add application Redux, navigation, persistence, or product policy to a generic package. +- Keep public APIs minimal and stable. Prefer composing focused types over introducing umbrella abstractions before multiple consumers need them. +- Declare platform and Swift toolchain requirements explicitly in `Package.swift`. +- Put sources under `Sources//` and tests under `Tests/Tests/`. +- Keep resources in the target that owns them and use the package bundle for lookup. + +## Development workflow + +1. Read the package's local `AGENTS.md`, README, DocC, and public API before changing behavior. +2. Add or update tests in the package itself. +3. Update DocC and README examples when public behavior changes. +4. Run the focused tests, then `swift test` or the package's declared Xcode test workflow. +5. Integrate the package into a consumer locally only when consumer behavior must also be verified. +6. Avoid committing consumer-specific workarounds into the package when the behavior belongs in the consumer. + +## Local integration + +- Use Xcode's local-package workflow or an explicit temporary local dependency while developing package and consumer changes together. +- Do not commit machine-specific absolute package paths. +- Before release, restore the consumer to the tagged remote dependency unless its local instructions intentionally retain a monorepo relationship. +- Verify the final remote version resolves on a clean checkout. + +## Releases + +For ThatFactory packages, “release a new version” means: + +1. Choose a semantic version appropriate to compatibility. +2. Update public documentation and release notes. +3. Run the declared CI/test workflow. +4. Commit the release state. +5. Create and push the matching Git tag. +6. Create a GitHub release for that tag. +7. Use real multiline release notes and backticks around technical names and versions. + +When using a CLI, pass multiline notes through a file so GitHub renders line breaks correctly. + +## Consumer updates + +- Review package release notes and API changes before updating. +- Update one dependency relationship intentionally; do not rewrite unrelated resolved versions. +- Build and test the affected consumer behavior. +- Update the consumer's package integration documentation when roles, mappings, or workflows change. diff --git a/Guidelines/Swift/Localization.md b/Guidelines/Swift/Localization.md new file mode 100644 index 0000000..02725c1 --- /dev/null +++ b/Guidelines/Swift/Localization.md @@ -0,0 +1,43 @@ +# Localization + +Follow Apple's [Localizing your app using agents](https://developer.apple.com/documentation/xcode/localizing-your-app-using-agents) workflow and current Xcode localization tools. Consumer repositories declare their supported languages, catalog locations, key conventions, and generated-symbol policy locally. + +## Source artifacts + +- Use the consumer's existing String Catalogs (`.xcstrings`) as the source of truth. +- Do not create a parallel catalog or migrate an existing `.strings` setup unless the task includes that migration. +- An app target uses its main bundle by default. Swift packages and frameworks must resolve localized resources from their own bundle, using the current Apple-recommended bundle API. +- Keep one source of truth for translator context: either the source comment or the catalog comment. + +## User-facing values + +- Let SwiftUI's localized string initializers preserve localization context. +- Use `LocalizedStringResource` when a model, view state, notification, or other non-view value carries user-facing text that should resolve later. +- Use `String(localized:)` when a resolved localized `String` is genuinely required outside SwiftUI. +- Use `Text(verbatim:)` for intentional non-localized literals such as debug identifiers. +- Do not pass a runtime `String` to a localized initializer and expect Xcode to extract it as a catalog key. + +## Sentences and formatting + +- Interpolate values into one localizable sentence rather than concatenating translated fragments. +- Add translator comments for ambiguous language and describe interpolated placeholders by position and meaning. +- Use locale-aware `FormatStyle` APIs for dates, numbers, lists, measurements, and currencies. +- Avoid runtime case transformations for localized interface text; allow translations to choose appropriate casing. + +## Layout + +- Use leading and trailing instead of left and right for directional layout. +- Avoid fixed text frames that cannot accommodate translation length or script height. +- Prefer semantic text styles to fixed point sizes. +- Use the SwiftUI environment locale for view behavior that must respond to preview or subtree locale overrides. + +## Agent workflow + +1. Inspect the consumer's local localization instructions and catalogs. +2. Ask Xcode's current documentation or localization capability for the supported workflow. +3. Add or update source-language content and translator context. +4. Update only the languages in scope. +5. Build to validate catalog syntax, extraction, generated symbols, and bundle lookup. +6. Use previews or runtime visual verification for truncation, layout direction, and formatting when relevant. + +Do not invent translations from an unrelated project's conventions. Product vocabulary and tone remain consumer-specific. diff --git a/Guidelines/Swift/Swift.md b/Guidelines/Swift/Swift.md new file mode 100644 index 0000000..2f6305e --- /dev/null +++ b/Guidelines/Swift/Swift.md @@ -0,0 +1,35 @@ +# Swift + +## Language and SDK guidance + +- Use the Swift language and platform versions declared by the consumer repository. +- Use current official Apple documentation through Xcode documentation search when API behavior or availability matters. +- Use current `swift-collections` documentation when working with its collection types. +- Import the module that owns an API. For example, APIs specific to `OrderedCollections` require `import OrderedCollections`. +- Maintain a zero-warning policy for warnings introduced by the change. + +## Implementation + +- Prefer concise, readable, maintainable code over clever abstractions. +- Prefer structured concurrency with `async`/`await`, task groups, actors, and `Task` where appropriate. +- Do not introduce `DispatchQueue.async` as a substitute for structured concurrency. +- Respect strict concurrency and the repository's default actor isolation. +- Prefer compiler-synthesized `Codable`, `Equatable`, `Hashable`, and `Sendable` conformances when their semantics are correct. +- Write manual serialization, equality, or hashing only when a documented requirement prevents synthesis. +- Import the narrowest framework the file requires. Models should not import SwiftUI merely to gain transitive access to Foundation types. +- A new Swift file must contain at least one required import; use `import Foundation` when it otherwise needs no module. + +## State and isolation + +- Treat actor isolation as part of an API's contract. +- Mark UI-bound reference models `@MainActor` unless the target's default actor isolation already provides it. +- Avoid adding `@MainActor` to tests or domain types merely to silence a diagnostic. Resolve the actual isolation boundary. +- Use `Sendable` where values cross concurrency domains and their stored values support it. + +## C-family interoperability + +When a target exposes or consumes C, Objective-C, or C++ interfaces, use Xcode's current `adopt-c-bounds-safety` skill and official compiler documentation for that scoped work. Do not apply C bounds-safety rules to pure Swift targets. + +## Documentation + +Follow [Swift style](SwiftStyle.md) for source formatting and [Documentation](../Documentation.md) for DocC and project-level guidance. diff --git a/Guidelines/Swift/SwiftLint.md b/Guidelines/Swift/SwiftLint.md new file mode 100644 index 0000000..c37477b --- /dev/null +++ b/Guidelines/Swift/SwiftLint.md @@ -0,0 +1,8 @@ +# SwiftLint + +- Treat lint rules as readability and correctness tools, not as architecture. +- Fix warnings introduced by a change. +- Do not add enum namespaces, empty wrapper types, or other artificial structures solely to satisfy filename rules for pure-function files such as reducers, selectors, or middleware. +- Prefer a focused local disable with a short reason when a rule conflicts with the intended design. +- Do not disable a rule repository-wide to avoid fixing one occurrence. +- Keep the lint configuration aligned with the physical folder organization and generated-file exclusions of the consumer repository. diff --git a/Guidelines/Swift/SwiftStyle.md b/Guidelines/Swift/SwiftStyle.md new file mode 100644 index 0000000..49a5aed --- /dev/null +++ b/Guidelines/Swift/SwiftStyle.md @@ -0,0 +1,25 @@ +# Swift Style + +- Keep conditional, loop, and closure bodies on separate lines. +- Keep `guard` exits on separate lines. +- Prefer seconds-based duration APIs such as `Task.sleep(for: .seconds(10))` over nanosecond literals. +- Use `///` for documentation comments and end documentation sentences with periods. +- Use meaningful names of at least three characters. Widely established type-level conventions are allowed only when the consumer explicitly uses them. +- Keep enum cases alphabetical unless ordering communicates behavior or a local lint suppression documents the exception. +- Use `// MARK: -` to separate meaningful sections. +- Use `// MARK: - Private` when separating private implementation from non-private declarations in the same file. +- Do not add Xcode boilerplate filename, author, or creation-date headers. +- Prefer one primary type or concern per file. +- Match a type file's name to its primary type. + +Example: + +```swift +guard isEnabled else { + return +} + +withAnimation { + isPresented = true +} +``` diff --git a/Guidelines/Swift/SwiftUI.md b/Guidelines/Swift/SwiftUI.md new file mode 100644 index 0000000..4b39758 --- /dev/null +++ b/Guidelines/Swift/SwiftUI.md @@ -0,0 +1,61 @@ +# SwiftUI + +Use official Apple documentation and Xcode's current SwiftUI skills for API-specific behavior. This guide captures stable project policy rather than reproducing the current SDK's API catalog. + +## View structure + +- Keep a parent view focused on composition. +- Model meaningful sections such as headers, lists, metadata, sidebars, and footers as separate `View` types with narrow inputs. +- Do not extract sections into computed `some View` properties merely to shorten `body`; computed properties remain in the parent's invalidation boundary. +- Tiny fragments reused within one body may use a small helper when they have no independent state, input, or invalidation story. +- Keep view initializers cheap. Do not decode data, access files, build large structures, or allocate formatters in `init`. +- Avoid a single-child `Group` that adds no structure or behavior. + +## Data flow + +- Pass a view only the value-type fields it reads or forwards. +- Use private `@State` for state genuinely owned by the view. +- Use `Binding` when a child edits state owned by its parent. +- In non-Redux designs, prefer `@Observable` to `ObservableObject` for new shared reference models when platform support allows it. +- In Redux applications, keep durable app and domain state in Redux. Do not introduce an observable view model as a parallel source of truth. +- Make observable stored-property types `Equatable` when equality matches their semantics, allowing redundant assignments to avoid unnecessary invalidation. +- Isolate side effects in `.task`, `.onChange`, actions, or explicit async functions rather than hiding them in rendering logic. +- Use the current `.onChange(of:)` form and read the updated captured value when the previous value is unnecessary. +- Avoid closure-based bindings when a writable key-path binding expresses the same relationship. + +With SDKs where `@State` is a macro, do not give a state property a declaration default and then attempt to replace that value in `init`. Choose one initialization source and verify current compiler guidance when migrating existing code. + +## Collections and identity + +- Give `ForEach`, `List`, `Table`, and similar data-driven views stable, unique element identity. +- Prefer meaningful `Identifiable` conformance when the model has natural identity. +- Do not use collection indices, offsets, or transient UUIDs as identity for mutable collections. +- Do not sort, filter, or map large collections inline inside a frequently evaluated view body. Prepare the collection before rendering. +- Use a dedicated row `View` for meaningful rows and pass it narrow inputs. +- Avoid `AnyView` in collection rows. + +## Modifiers and environment + +- Preserve stable view identity. Prefer modifiers whose values change over conditionally adding and removing modifier branches. +- Do not place high-frequency values in the environment when explicit narrow inputs work. +- Avoid unstable environment defaults and freshly created closures that invalidate large subtrees. +- Do not hide unstable values behind fake `Equatable` implementations. + +## Modern APIs and scope + +- Do not introduce APIs that current Xcode documentation identifies as deprecated or soft-deprecated. +- When fixing a feature, modernize only the code directly required by the task unless the user requests a broader migration. +- For SDK-sensitive features, search current Apple documentation through Xcode rather than relying on remembered signatures. +- Apply the current Xcode SwiftUI skill when a new SDK changes source behavior, builder resolution, state initialization, or modifier availability. + +## Previews + +- Put previews at the end of the file under `// MARK: - Preview`. +- Use `#Preview`. +- Use `@Previewable` for interactive preview state when appropriate. +- Keep preview fixtures deterministic and lightweight. +- After UI changes, follow [Xcode MCP and visual verification](../Xcode/MCP.md) when runtime verification adds meaningful confidence. + +## Localization + +Follow [Localization](Localization.md) for user-facing text, layout direction, formatting, and package bundles. diff --git a/Guidelines/Testing/UnitTesting.md b/Guidelines/Testing/UnitTesting.md new file mode 100644 index 0000000..4bae316 --- /dev/null +++ b/Guidelines/Testing/UnitTesting.md @@ -0,0 +1,50 @@ +# Unit and Integration Testing + +## Framework choice + +- Use Swift Testing (`import Testing`) for new unit and integration tests. +- Keep XCTest for UI automation based on XCUIAutomation and for `measure`-based performance tests. +- Do not migrate unrelated tests while implementing a focused feature or fix. +- After removing XCTest, add direct imports such as Foundation when the test relied on XCTest's transitive exports. + +## Structure + +- Organize test intent with `// Given`, `// When`, and `// Then` where the phases are meaningful. +- Prefer `struct` suites. Use a reference type only when lifecycle or identity requires it. +- Use suite initialization and `deinit` only for genuine shared setup and cleanup. +- Keep each test focused on one behavior and name it in domain language. +- Mirror production physical folders under the test target. +- Put reusable mocks and fixtures under the test target's `Mocks/` folder. + +## Assertions and control flow + +- Use `@Test` for tests and traits. +- Use `#expect` for assertions that allow the test to continue. +- Use `#require` for prerequisites whose failure must stop the current test. +- Prefer exact thrown-error expectations when the particular error is part of the contract. +- Use confirmation APIs for callback or delegate behavior rather than hand-built counters and arbitrary delays. +- Record known failures with Swift Testing's known-issue support instead of silently disabling coverage. + +## Concurrency + +- Assume Swift Testing may run tests concurrently and on arbitrary tasks. +- Make tests independent by default. +- Use `.serialized` only when a suite has a real shared-state dependency that cannot reasonably be removed. +- Add `@MainActor` only when the system under test requires main-actor isolation. +- Prefer async test functions and structured concurrency over expectations combined with arbitrary sleeps. +- Inject clocks, services, identifier generators, and providers to make asynchronous behavior deterministic. + +## Repetition + +- Prefer parameterized tests when the same behavior is exercised with multiple inputs and expected outputs. +- Keep argument cases readable and give complex cases a small named model. +- Do not loop manually inside one test when individual parameterized cases would produce better failure reporting. + +## Execution + +- Prefer Xcode MCP for discovering and running the relevant test plan or test target. +- Use XcodeBuildMCP only when Xcode MCP is unavailable or fails to complete the workflow. +- Start with the smallest relevant test selection, then run the broader affected suite when risk justifies it. +- Report which tests ran and whether any relevant tests could not be executed. + +Follow [Xcode MCP](../Xcode/MCP.md) for build and runtime verification. diff --git a/Guidelines/Xcode/MCP.md b/Guidelines/Xcode/MCP.md new file mode 100644 index 0000000..bed3e38 --- /dev/null +++ b/Guidelines/Xcode/MCP.md @@ -0,0 +1,65 @@ +# Xcode MCP and Visual Verification + +Use Xcode as the primary source for Apple documentation, project knowledge, builds, tests, previews, simulator/device interaction, and diagnostics. + +Apple documents external agent access through [`xcrun mcpbridge`](https://developer.apple.com/documentation/xcode/giving-external-agents-access-to-xcode). Xcode must be open with the relevant project or package, and external-agent access must be enabled in Xcode settings. + +## Tool priority + +1. Use Xcode MCP for Apple documentation search and operations on an open Xcode project or package. +2. Use official Apple web documentation when Xcode documentation search is unavailable or an external reference is useful. +3. Use XcodeBuildMCP only when Xcode MCP is unavailable or cannot complete the required operation. + +Discover the tools exposed by the active Xcode server. Tool prefixes and exact names can vary by client; do not hardcode a server prefix when the active tool catalog can be inspected. + +## Documentation lookup + +- Search current Apple documentation before using an API whose signature, availability, behavior, or replacement may have changed. +- Prefer the documentation returned by the installed Xcode toolchain for SDK-sensitive work. +- Use Xcode-provided skills for specialized current workflows such as SwiftUI modernization, localization, security auditing, device interaction, and C bounds safety. +- Distill durable project policy into local documentation; do not copy an exported Apple skill into a repository. + +## Project operations + +- Prefer Xcode project-aware file, target, build-setting, issue, build, test, preview, and documentation tools when available. +- Build the smallest relevant target or scheme first. +- Read Xcode diagnostics and fix the first root failure before retrying broadly. +- Run focused tests before the full affected suite. +- Keep the project open and active throughout a multi-step Xcode MCP workflow. + +## SwiftUI previews + +After a meaningful SwiftUI change: + +1. Build the affected target. +2. Render or refresh the relevant preview when Xcode exposes preview tooling. +3. Inspect errors and warnings from the preview and build. +4. Verify representative states, localization, accessibility sizes, and appearances when relevant to the task. +5. If preview tooling is unavailable or insufficient, run the feature in a simulator or device session. + +## Build, run, and interaction + +Use runtime interaction when static compilation cannot establish that a user-visible workflow behaves correctly. + +1. Start or select an appropriate simulator/device session. +2. Build, install, and launch through Xcode tooling. +3. Prefer one-run launch arguments and environment variables to editing a shared scheme for temporary configuration. +4. Capture the accessibility or UI hierarchy before interaction. +5. Capture a screenshot when visual state matters. +6. Derive interaction targets from the hierarchy; do not guess coordinates when semantic information is available. +7. Perform the smallest interaction sequence that proves the behavior. +8. Capture the resulting hierarchy and screenshot. +9. Report both functional and visible defects. +10. End resource-heavy sessions when verification is complete. + +Retry a slow launch or interaction once when the application may still be settling. Do not add arbitrary waits as a default synchronization strategy. + +## Reporting + +State: + +- what target, scheme, preview, test, simulator, or device was used; +- what behavior was exercised; +- whether build and runtime diagnostics were clean; +- what visual evidence was inspected; +- what could not be verified and why. diff --git a/Guidelines/Xcode/Security.md b/Guidelines/Xcode/Security.md new file mode 100644 index 0000000..5817b01 --- /dev/null +++ b/Guidelines/Xcode/Security.md @@ -0,0 +1,35 @@ +# Xcode Security Audits + +Use this guide only for an explicitly requested security audit, hardening task, entitlement review, or a change that materially affects application security. Do not expand ordinary feature work into a repository-wide audit. + +## Source of truth + +- Use Xcode's current `audit-xcode-security-settings` skill and official Apple documentation for the detailed baseline. +- Prefer Xcode MCP project-aware tools for targets, build settings, entitlements, capabilities, privacy manifests, source searches, and file updates. +- Discover active tool names rather than hardcoding MCP server prefixes. + +## Audit scope + +Confirm the requested targets and configurations, then inspect only relevant areas: + +- deployment and compiler security settings; +- code-signing and entitlements; +- application capabilities; +- privacy manifests and required-reason APIs; +- network security configuration; +- debug-only behavior and diagnostics; +- sensitive data storage and logging; +- unsafe interoperability boundaries. + +## Changes + +- Explain the concrete risk and affected target before changing a setting or entitlement. +- Prefer Xcode-aware entitlement and project-setting tools over textual project-file manipulation. +- Preserve required capabilities and configuration-specific differences. +- Make narrow changes that can be reviewed and reverted. +- Build the affected target after project-setting changes. +- Exercise relevant runtime behavior when a change affects signing, capabilities, networking, storage, or system integration. + +## Report + +Separate findings from changes. Record the target/configuration, evidence, severity, remediation, and verification for each changed item. Do not claim a comprehensive security guarantee from a settings audit alone. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..42d8021 --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2026 ThatFactory + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/README.md b/README.md new file mode 100644 index 0000000..e0abdec --- /dev/null +++ b/README.md @@ -0,0 +1,129 @@ +

+ Xcode + Codex + License + CI +

+ +# Agent Guidelines + +`agent-guidelines` is ThatFactory's public, versioned source of truth for reusable instructions given to coding agents. It centralizes stable decisions about Swift development, Redux architecture, testing, documentation, packages, CI/CD, localization, and Xcode tooling while leaving product context and exceptions in each consuming repository. + +The repository contains documentation, not a Swift product. Consumers install a tagged release as a Git subtree at `AgentGuidelines/`, so every agent sees ordinary version-controlled files at predictable paths. + +## How it fits together + +```text + thatfactory/agent-guidelines + versioned GitHub repository + | + tagged release + e.g. 0.0.1 + | + git subtree add/pull + | + v ++---------------- Consumer project or package ----------------+ +| | +| AGENTS.md | +| |-- local product/package context | +| |-- concrete project paths | +| |-- local exceptions | +| `-- pointers to shared guidelines -----------------+ | +| | | +| AgentGuidelines/ | | +| |-- VERSION | | +| `-- Guidelines/ <----------------------------------+ | +| |-- Architecture/Redux.md | +| |-- Swift/SwiftUI.md | +| |-- Testing/UnitTesting.md | +| `-- Xcode/MCP.md | +| | +| Sources and project files | ++----------------------------+---------------------------------+ + | + reads instructions and project files + +----------+----------+ + v v + Codex Xcode agent + | + | Xcode MCP (`xcrun mcpbridge`) + v + Xcode +``` + +The subtree does not automatically import every guide into an agent's context. A consumer's root or folder-scoped `AGENTS.md` tells the agent which shared guides to read for the task. The nearest local `AGENTS.md` can specialize or override the shared baseline. + +## Guideline catalog + +- [Redux architecture and physical folder organization](Guidelines/Architecture/Redux.md) +- [Swift](Guidelines/Swift/Swift.md) +- [Swift style](Guidelines/Swift/SwiftStyle.md) +- [SwiftUI](Guidelines/Swift/SwiftUI.md) +- [SwiftLint](Guidelines/Swift/SwiftLint.md) +- [Localization](Guidelines/Swift/Localization.md) +- [Unit and integration testing](Guidelines/Testing/UnitTesting.md) +- [Documentation](Guidelines/Documentation.md) +- [Swift packages](Guidelines/Packages.md) +- [CI/CD](Guidelines/CICD.md) +- [Xcode MCP and visual verification](Guidelines/Xcode/MCP.md) +- [Xcode security audits](Guidelines/Xcode/Security.md) + +Only reference the guides that apply. A UI-agnostic package normally uses Swift, style, testing, documentation, packages, CI/CD, and Xcode guidance, but not Redux or SwiftUI guidance. + +## Add to a consumer + +From the consumer repository root, install a tagged release: + +```sh +git subtree add \ + --prefix=AgentGuidelines \ + https://github.com/thatfactory/agent-guidelines.git \ + 0.0.1 \ + --squash +``` + +Copy and adapt [the consumer template](Templates/AGENTS.md). Keep the consumer file small: describe the product or package, map its concrete physical folders, point to the applicable shared guides, and state only genuine exceptions. + +## Update a consumer + +Review the target release's changelog, then pull it deliberately: + +```sh +git subtree pull \ + --prefix=AgentGuidelines \ + https://github.com/thatfactory/agent-guidelines.git \ + \ + --squash +``` + +Confirm `AgentGuidelines/VERSION`, review the subtree diff, validate local `AGENTS.md` pointers, and run the consumer's relevant tests. Updates are intentionally not automatic: one guideline release cannot silently change every project. + +## Maintain the source of truth + +1. Export current Xcode skills to a temporary review location when a new Xcode release materially changes agent behavior: + + ```sh + xcrun agent skills export --output-dir + ``` + +2. Compare relevant guidance with this repository and official Apple documentation. +3. Bring over durable policy, not the exported skill text or an SDK API catalog. +4. Remove obsolete or conflicting rules instead of accumulating historical alternatives. +5. Run `python3 Scripts/validate_guidelines.py`. +6. Update `VERSION` and `CHANGELOG.md`, then create the matching tag and GitHub release. + +## Precedence + +For a consumer task, apply instructions in this order: + +1. The user's explicit request. +2. The nearest applicable consumer `AGENTS.md`. +3. The consumer root `AGENTS.md`. +4. The shared guides explicitly referenced by those files. + +Official Apple documentation remains authoritative for API behavior. A local convention can deliberately narrow a choice, but it must not rely on behavior contradicted by the current SDK documentation. + +## License + +Released under the [MIT License](LICENSE). diff --git a/Scripts/validate_guidelines.py b/Scripts/validate_guidelines.py new file mode 100644 index 0000000..145675e --- /dev/null +++ b/Scripts/validate_guidelines.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python3 +"""Validate the structure and public safety of the guideline repository.""" + +from __future__ import annotations + +import re +import sys +from pathlib import Path, PurePosixPath + + +ROOT = Path(__file__).resolve().parents[1] +README = ROOT / "README.md" +VERSION = ROOT / "VERSION" +CHANGELOG = ROOT / "CHANGELOG.md" + +MARKDOWN_LINK = re.compile(r"\[[^\]]+\]\(([^)]+)\)") +SEMVER = re.compile( + r"(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:[-+][0-9A-Za-z.-]+)?$" +) +FORBIDDEN = { + "/" + "Users" + "/": "personal absolute path", + "file" + "://": "local file URL", + "mobile-ios-" + "chauffeur": "work-repository identifier", + "black" + "lane": "work-repository identifier", +} + + +def text_files() -> list[Path]: + suffixes = {".md", ".py", ".yml", ".yaml", ".txt"} + files = [path for path in ROOT.rglob("*") if path.is_file() and path.suffix in suffixes] + files.extend(path for path in (ROOT / "VERSION", ROOT / "LICENSE") if path.is_file()) + return sorted(set(files)) + + +def resolve_link(source: Path, raw_target: str) -> Path | None: + target = raw_target.strip().strip("<>").split("#", maxsplit=1)[0] + if not target or target.startswith(("#", "http://", "https://", "mailto:")): + return None + + parts = PurePosixPath(target).parts + if "AgentGuidelines" in parts: + index = parts.index("AgentGuidelines") + return ROOT.joinpath(*parts[index + 1 :]).resolve() + + return (source.parent / target).resolve() + + +def validate_links(errors: list[str]) -> None: + for source in sorted(ROOT.rglob("*.md")): + for raw_target in MARKDOWN_LINK.findall(source.read_text(encoding="utf-8")): + resolved = resolve_link(source, raw_target) + if resolved is not None and not resolved.exists(): + relative_source = source.relative_to(ROOT) + errors.append(f"{relative_source}: missing link target {raw_target!r}") + + +def validate_catalog(errors: list[str]) -> None: + readme = README.read_text(encoding="utf-8") + for guide in sorted((ROOT / "Guidelines").rglob("*.md")): + relative = guide.relative_to(ROOT).as_posix() + if f"]({relative})" not in readme: + errors.append(f"README.md: guideline is not cataloged: {relative}") + + +def validate_version(errors: list[str]) -> None: + version = VERSION.read_text(encoding="utf-8").strip() + if not SEMVER.fullmatch(version): + errors.append(f"VERSION: invalid semantic version {version!r}") + + changelog = CHANGELOG.read_text(encoding="utf-8") + if f"## [{version}]" not in changelog: + errors.append(f"CHANGELOG.md: missing release heading for {version}") + + +def validate_readme_contract(errors: list[str]) -> None: + readme = README.read_text(encoding="utf-8") + required = { + 'alt="Xcode"': "Xcode badge alt text", + "thatfactory/agent-guidelines/actions/workflows/ci.yml": "CI badge repository", + "--prefix=AgentGuidelines": "subtree destination", + "https://github.com/thatfactory/agent-guidelines.git": "subtree remote", + "git subtree add": "subtree installation command", + "git subtree pull": "subtree update command", + } + for value, description in required.items(): + if value not in readme: + errors.append(f"README.md: missing {description}: {value!r}") + + +def validate_public_content(errors: list[str]) -> None: + for path in text_files(): + contents = path.read_text(encoding="utf-8") + relative = path.relative_to(ROOT) + for forbidden, description in FORBIDDEN.items(): + if forbidden.lower() in contents.lower(): + errors.append(f"{relative}: contains {description}: {forbidden!r}") + + +def main() -> int: + errors: list[str] = [] + validate_links(errors) + validate_catalog(errors) + validate_version(errors) + validate_readme_contract(errors) + validate_public_content(errors) + + if errors: + print("Guideline validation failed:") + for error in errors: + print(f"- {error}") + return 1 + + guide_count = len(list((ROOT / "Guidelines").rglob("*.md"))) + print(f"Validated {guide_count} guidelines for version {VERSION.read_text().strip()}.") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/Templates/AGENTS.md b/Templates/AGENTS.md new file mode 100644 index 0000000..ddfd5fb --- /dev/null +++ b/Templates/AGENTS.md @@ -0,0 +1,39 @@ +# Project Instructions + +## Context + +Describe the product or package, supported platforms, and durable constraints. Link to the project README or product documentation instead of duplicating it. + +## Shared guidelines + +Read only the guides relevant to the task: + +- [Swift](AgentGuidelines/Guidelines/Swift/Swift.md) +- [Swift style](AgentGuidelines/Guidelines/Swift/SwiftStyle.md) +- [SwiftUI](AgentGuidelines/Guidelines/Swift/SwiftUI.md) +- [SwiftLint](AgentGuidelines/Guidelines/Swift/SwiftLint.md) +- [Localization](AgentGuidelines/Guidelines/Swift/Localization.md) +- [Unit and integration testing](AgentGuidelines/Guidelines/Testing/UnitTesting.md) +- [Documentation](AgentGuidelines/Guidelines/Documentation.md) +- [Packages](AgentGuidelines/Guidelines/Packages.md) +- [CI/CD](AgentGuidelines/Guidelines/CICD.md) +- [Xcode MCP and visual verification](AgentGuidelines/Guidelines/Xcode/MCP.md) +- [Xcode security audits](AgentGuidelines/Guidelines/Xcode/Security.md) + +For an application that uses Redux, also read [Redux architecture](AgentGuidelines/Guidelines/Architecture/Redux.md). + +## Physical folder map + +Replace these examples with exact repository paths: + +| Role | Physical folder | +|---|---| +| Application sources | `/` | +| Redux | `/Redux/` | +| Views | `/View/` | +| Services | `/Services/` | +| Unit tests | `Tests/` | + +## Local specialization + +State only rules that specialize or override the shared baseline. Explain their scope and point to local source-of-truth documentation. diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..3ebea8c --- /dev/null +++ b/VERSION @@ -0,0 +1,2 @@ +0.0.1 + From c992b279c2a397601b5e22ae2007454b47573a14 Mon Sep 17 00:00:00 2001 From: Fernando Fernandes Date: Tue, 21 Jul 2026 14:04:45 +0200 Subject: [PATCH 2/6] Add package agent instructions --- AGENTS.md | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..5e02248 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,39 @@ +# ProgressionKit + +## Context + +ProgressionKit is a pure Swift package for deterministic XP, player levels, track mastery, and tier unlocks. Read [README.md](README.md) and the DocC catalog before changing public behavior. + +The package is content-, storage-, UI-, and application-architecture agnostic. Host applications decide what content, tracks, tiers, persistence, and presentation mean. + +## Shared guidelines + +Read only the guides relevant to the task: + +- [Swift](AgentGuidelines/Guidelines/Swift/Swift.md) +- [Swift style](AgentGuidelines/Guidelines/Swift/SwiftStyle.md) +- [SwiftLint](AgentGuidelines/Guidelines/Swift/SwiftLint.md) +- [Unit and integration testing](AgentGuidelines/Guidelines/Testing/UnitTesting.md) +- [Documentation](AgentGuidelines/Guidelines/Documentation.md) +- [Packages](AgentGuidelines/Guidelines/Packages.md) +- [CI/CD](AgentGuidelines/Guidelines/CICD.md) +- [Xcode MCP](AgentGuidelines/Guidelines/Xcode/MCP.md) +- [Xcode security audits](AgentGuidelines/Guidelines/Xcode/Security.md) + +Redux, SwiftUI, and application-localization guidance do not apply to the package target. + +## Physical folder map + +| Role | Physical folder | +|---|---| +| Package sources | `Sources/ProgressionKit/` | +| DocC catalog | `Sources/ProgressionKit/ProgressionKit.docc/` | +| Unit tests | `Tests/ProgressionKitTests/` | + +## Package specialization + +- Keep progression updates deterministic for the same profile, event, and configuration. +- Do not add storage, network, UI, Redux, or game-content dependencies. +- Host applications own mapping from their domain identifiers and outcomes into `PKEvent`. +- Preserve compiler-synthesized value semantics and serialization when evolving public models. +- Update tests, DocC, README examples, and release notes when public behavior changes. From 4eaa09667548aff9fe0e9dfe308c9b89b7dbd498 Mon Sep 17 00:00:00 2001 From: Fernando Fernandes Date: Tue, 21 Jul 2026 14:05:57 +0200 Subject: [PATCH 3/6] Squashed 'AgentGuidelines/' changes from f5e7da0..2bf029e 2bf029e Add tag-driven release workflow 3de0666 Add shared agent guidelines 0.0.1 fc44676 Initial commit REVERT: f5e7da0 Fix consumer template paths REVERT: 37a4aa4 Add shared agent guidelines 0.0.1 git-subtree-dir: AgentGuidelines git-subtree-split: 2bf029e08129489c3474806ba1d24da4b6d73541 --- .github/workflows/release.yml | 44 +++++++++++++++++++++++++++++++++++ CHANGELOG.md | 2 +- 2 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..8cfe119 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,44 @@ +name: Release + +on: + push: + tags: + - "*.*.*" + +permissions: + contents: write + +jobs: + release: + name: Create GitHub release + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Validate guidelines + run: python3 Scripts/validate_guidelines.py + + - name: Validate tag + run: | + version="$(tr -d '[:space:]' < VERSION)" + test "$GITHUB_REF_NAME" = "$version" + + - name: Prepare release notes + run: | + version="$(tr -d '[:space:]' < VERSION)" + awk -v version="$version" ' + index($0, "## [" version "]") == 1 { capture = 1; next } + capture && /^## \[/ { exit } + capture { print } + ' CHANGELOG.md > release-notes.md + test -s release-notes.md + + - name: Create release + env: + GH_TOKEN: ${{ github.token }} + run: | + gh release create "$GITHUB_REF_NAME" \ + --verify-tag \ + --title "$GITHUB_REF_NAME" \ + --notes-file release-notes.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e24a78..1f76f35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,4 +9,4 @@ All notable changes to this project are documented in this file. - Initial shared guidelines for Redux, Swift, SwiftUI, SwiftLint, localization, testing, documentation, package maintenance, CI/CD, Xcode MCP, and Xcode security audits. - A consumer `AGENTS.md` template and Git subtree installation workflow. - Structural validation for links, the documentation catalog, version metadata, subtree instructions, and public-repository safety. - +- A tag-driven GitHub release workflow that validates the tag against `VERSION` and publishes changelog notes. From 89480f481f47b385f24acae66f17c8860d7e96f4 Mon Sep 17 00:00:00 2001 From: Fernando Fernandes Date: Tue, 21 Jul 2026 16:12:24 +0200 Subject: [PATCH 4/6] Squashed 'AgentGuidelines/' changes from 2bf029e..112ac8e 112ac8e Standardize repository and review guidelines (#3) git-subtree-dir: AgentGuidelines git-subtree-split: 112ac8ecd6268edab8d345ae83c82b4ddeec5f68 --- .github/workflows/ci.yml | 6 ++-- .github/workflows/release.yml | 2 +- .gitignore | 3 +- AGENTS.md | 2 +- CHANGELOG.md | 16 ++++++++++ Guidelines/Architecture/Redux.md | 25 +++++++-------- Guidelines/CICD.md | 3 ++ Guidelines/Git/Repositories.md | 22 +++++++++++++ Guidelines/GitHub/PullRequests.md | 49 +++++++++++++++++++++++++++++ Guidelines/Packages.md | 32 +++++++++++++++++++ README.md | 12 +++---- Scripts/validate_guidelines.py | 7 ++++- Templates/AGENTS.md | 2 ++ Tests/test_validate_guidelines.py | 52 +++++++++++++++++++++++++++++++ VERSION | 3 +- 15 files changed, 209 insertions(+), 27 deletions(-) create mode 100644 Guidelines/Git/Repositories.md create mode 100644 Guidelines/GitHub/PullRequests.md create mode 100644 Tests/test_validate_guidelines.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4c01b13..5831117 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v7 - name: Validate - run: python3 Scripts/validate_guidelines.py + run: | + python3 -m unittest discover -s Tests + python3 Scripts/validate_guidelines.py diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8cfe119..20b4c8f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v7 - name: Validate guidelines run: python3 Scripts/validate_guidelines.py diff --git a/.gitignore b/.gitignore index 5ca0973..dff2f41 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .DS_Store - +__pycache__/ +*.py[cod] diff --git a/AGENTS.md b/AGENTS.md index e007fd3..aef307d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -35,4 +35,4 @@ Fix every validation failure before releasing a version. - Use semantic versioning. - Create a Git tag and GitHub release matching `VERSION`. - Consumer repositories adopt releases deliberately through Git subtree updates. - +- Follow [the pull-request review workflow](Guidelines/GitHub/PullRequests.md) before merging any release change. diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f76f35..fd1f0cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,22 @@ All notable changes to this project are documented in this file. +## [0.0.2] - 2026-07-21 + +### Added + +- Standard README badge conventions for ThatFactory projects and packages. +- Git repository guidance that defaults push-capable clones to SSH remotes. +- GitHub pull-request review and merge-gate guidance. +- Updated and Revision badges to the repository README. + +### Changed + +- Updated GitHub workflows to `actions/checkout@v7` and documented using current stable action versions in new workflows. +- Clarified the Redux side-effect loop and the canonical view-projection test path. +- Expanded and tested semantic-version validation to support prerelease plus build metadata and reject invalid numeric identifiers. +- Removed the redundant README license section while retaining the MIT license badge and root license file. + ## [0.0.1] - 2026-07-21 ### Added diff --git a/Guidelines/Architecture/Redux.md b/Guidelines/Architecture/Redux.md index 089528d..77b20f6 100644 --- a/Guidelines/Architecture/Redux.md +++ b/Guidelines/Architecture/Redux.md @@ -24,18 +24,17 @@ Use this guide for applications that explicitly adopt the ThatFactory Redux arch +--------------+ observable state | 1. Reducer| | 2. Middle-| | ware | - +-----+-----+ - | - | side effect - v - +--------------+ - | Service | - | package/API | - +------+-------+ - | - | Action? - v - Store again + +-----+-----+ <---------------+ + | | + | side effect | + v | + +--------------+ | + | Service | | + | package/API | | + +------+-------+ | + | | + | Action? | + +-----------------------+ ``` The store reduces the original action first, then awaits middleware and sequentially dispatches returned follow-up actions. Keep ordering observable and deterministic. Do not start unstructured work inside reducers or hide state changes inside services. @@ -225,7 +224,7 @@ Skip components that provide no value. A state-only transition needs no middlewa - Selector tests provide state and assert the derived domain result. - Middleware tests inject mocks, execute an action, and assert the returned follow-up action. - Service tests exercise the external boundary without involving views. -- View-state projection tests live under the matching `Tests/View//` folder. +- View-state projection tests live under the matching `Tests/View//` folder, or the consumer-mapped test root. - Test mocks and fixture data live under the test target's `Mocks/` folder. Follow [Unit testing](../Testing/UnitTesting.md) for framework and concurrency conventions. diff --git a/Guidelines/CICD.md b/Guidelines/CICD.md index 50322b5..a66886e 100644 --- a/Guidelines/CICD.md +++ b/Guidelines/CICD.md @@ -5,6 +5,9 @@ - Keep CI deterministic, reproducible, and aligned with the repository's supported Xcode, Swift, and platform versions. - Treat warnings introduced by a change as failures even when the compiler does not. - Prefer the smallest permissions required by each workflow and job. +- For a new workflow, use the latest stable major version of every GitHub Action available at the time of creation. +- Do not copy an older major version into a fresh workflow unless a documented compatibility constraint requires it. +- For existing workflows, review action release notes and update deliberately rather than allowing runtime deprecation warnings to accumulate. - Pin third-party actions to an intentional version and review updates. - Do not place secrets in workflow files, logs, fixtures, or command arguments that may be echoed. - Keep release workflows separate from pull-request validation when their permissions differ. diff --git a/Guidelines/Git/Repositories.md b/Guidelines/Git/Repositories.md new file mode 100644 index 0000000..a85949a --- /dev/null +++ b/Guidelines/Git/Repositories.md @@ -0,0 +1,22 @@ +# Git Repositories + +Use these rules when cloning repositories or configuring remotes. + +## SSH-first cloning + +Clone a repository over SSH when the working copy may be used to commit, push, or open a pull request: + +```sh +git clone git@github.com:/.git +``` + +- Prefer an SSH `origin` so command-line tools and Git clients such as Fork can reuse the machine's GitHub SSH authentication. +- Do not create a push-capable working copy with an HTTPS `origin` unless the user or environment explicitly requires HTTPS. +- After cloning for development, use `git remote -v` to confirm that fetch and push URLs are correct. +- If an existing development clone has an HTTPS `origin`, change it only when requested or when the task explicitly includes remote setup: + + ```sh + git remote set-url origin git@github.com:/.git + ``` + +HTTPS remains appropriate for deliberately read-only retrieval, ephemeral automation, or environments where SSH credentials are unavailable. A public Git subtree remote may also remain HTTPS because consumers fetch tagged content without pushing to the guideline repository. diff --git a/Guidelines/GitHub/PullRequests.md b/Guidelines/GitHub/PullRequests.md new file mode 100644 index 0000000..f073b47 --- /dev/null +++ b/Guidelines/GitHub/PullRequests.md @@ -0,0 +1,49 @@ +# GitHub Pull Requests + +Use this guide whenever creating, reviewing, updating, or merging a GitHub pull request. + +## Before opening + +- Review the complete diff and exclude unrelated changes. +- Follow the repository's pull-request template and local contribution instructions. +- Run the relevant local validation and document anything that could not be run. +- Open the pull request without auto-merge and keep it unmerged while automated or agent review is pending. Use draft state only when configured reviewers also run on drafts. + +## Review gate + +Opening a pull request starts review; it does not authorize merging it. + +1. Wait for the configured Codex review to finish. No review yet means pending, not approved. +2. Inspect all review summaries, inline threads, checks, and requested changes. +3. Assess each comment on its technical merits. +4. Implement valid feedback and rerun the affected validation. +5. If feedback should not be implemented, reply in the original thread with a concise technical reason. +6. Reply to implemented feedback with what changed and where. +7. Resolve a thread only after its concern has been addressed or explicitly declined. +8. Recheck the pull request immediately before merge for late comments and check-state changes. + +A thumbs-up or clean Codex review satisfies the agent-review step, but it does not replace any human approval required by the repository. Do not enable auto-merge before all review gates are satisfied. + +## Merge requirements + +Do not merge while any of the following is true: + +- Codex review is still pending; +- an actionable review comment is unanswered; +- a review conversation is unresolved; +- a required check is pending or failing; +- the branch is out of date when the repository requires an up-to-date branch; +- required human approval or explicit owner authorization is missing. + +If a review arrives after a premature merge, treat that as a process failure: assess the feedback, reply to every thread, and ship valid corrections through a follow-up pull request. + +## Repository protection + +Prefer GitHub rulesets or branch protection for the default branch. At minimum: + +- require changes to arrive through a pull request; +- require conversations to be resolved before merging; +- require the repository's mandatory status checks; +- prevent bypass except for an intentional emergency path. + +A formal one-approval rule works only when someone other than the pull-request author can submit an approving review. In a solo repository where the owner account also authors pull requests, use a bot or service account for authored changes before requiring owner approval; GitHub does not count self-approval. Until that separation exists, require explicit owner authorization operationally and keep conversation resolution enforced technically. diff --git a/Guidelines/Packages.md b/Guidelines/Packages.md index c21f43e..8bb04fa 100644 --- a/Guidelines/Packages.md +++ b/Guidelines/Packages.md @@ -1,5 +1,37 @@ # Swift Packages +## README badges + +Start a new ThatFactory project or package README with a centered HTML badge block: + +```html +

+ +

+``` + +Use only badges that describe the repository, in this order: + +1. Swift version. +2. Xcode version. +3. Supported platforms. +4. Relevant package manager, runtime, or ecosystem badges, such as SPM or NPM. +5. Relevant agent or tooling badges, such as Xcode MCP, Codex, or Claude. +6. Updated date. +7. Revision or latest release. +8. License. +9. CI. +10. Release, publishing, or documentation status when applicable. + +The common package baseline is Swift, Xcode, Platforms, License, and CI. Add optional badges only when they convey useful repository-specific information. Keep the order stable even when some positions are omitted. + +- Point CI, publishing, and documentation badges at workflows in the current repository; never copy another repository's badge URL unchanged. +- Use descriptive `alt` text. Preserve a repository's established Xcode badge convention when the label intentionally records the last verified Xcode version. +- Prefer dynamic Updated and Revision badges backed by repository history or releases so maintainers do not edit dates and versions by hand. +- Do not advertise a platform, integration, package manager, or agent that the repository does not support. +- Keep the repository's license in a root `LICENSE` file when reuse or redistribution is permitted. A README license heading is optional; the badge is a summary, not the license grant. +- Do not add a license to an existing repository without the owner's explicit choice of terms. + ## Package boundaries - Keep a reusable package focused on one coherent capability. diff --git a/README.md b/README.md index e0abdec..0fddd3e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@

Xcode Codex + Updated + Revision License CI

@@ -18,7 +20,7 @@ The repository contains documentation, not a Swift product. Consumers install a versioned GitHub repository | tagged release - e.g. 0.0.1 + e.g. 0.0.2 | git subtree add/pull | @@ -66,6 +68,8 @@ The subtree does not automatically import every guide into an agent's context. A - [Documentation](Guidelines/Documentation.md) - [Swift packages](Guidelines/Packages.md) - [CI/CD](Guidelines/CICD.md) +- [Git repositories and SSH-first cloning](Guidelines/Git/Repositories.md) +- [GitHub pull requests](Guidelines/GitHub/PullRequests.md) - [Xcode MCP and visual verification](Guidelines/Xcode/MCP.md) - [Xcode security audits](Guidelines/Xcode/Security.md) @@ -79,7 +83,7 @@ From the consumer repository root, install a tagged release: git subtree add \ --prefix=AgentGuidelines \ https://github.com/thatfactory/agent-guidelines.git \ - 0.0.1 \ + 0.0.2 \ --squash ``` @@ -123,7 +127,3 @@ For a consumer task, apply instructions in this order: 4. The shared guides explicitly referenced by those files. Official Apple documentation remains authoritative for API behavior. A local convention can deliberately narrow a choice, but it must not rely on behavior contradicted by the current SDK documentation. - -## License - -Released under the [MIT License](LICENSE). diff --git a/Scripts/validate_guidelines.py b/Scripts/validate_guidelines.py index 145675e..3b76c8a 100644 --- a/Scripts/validate_guidelines.py +++ b/Scripts/validate_guidelines.py @@ -15,7 +15,12 @@ MARKDOWN_LINK = re.compile(r"\[[^\]]+\]\(([^)]+)\)") SEMVER = re.compile( - r"(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:[-+][0-9A-Za-z.-]+)?$" + r"^(0|[1-9][0-9]*)\." + r"(0|[1-9][0-9]*)\." + r"(0|[1-9][0-9]*)" + r"(?:-((?:0|[1-9][0-9]*|[0-9]*[A-Za-z-][0-9A-Za-z-]*)" + r"(?:\.(?:0|[1-9][0-9]*|[0-9]*[A-Za-z-][0-9A-Za-z-]*))*))?" + r"(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$" ) FORBIDDEN = { "/" + "Users" + "/": "personal absolute path", diff --git a/Templates/AGENTS.md b/Templates/AGENTS.md index ddfd5fb..b28c118 100644 --- a/Templates/AGENTS.md +++ b/Templates/AGENTS.md @@ -17,6 +17,8 @@ Read only the guides relevant to the task: - [Documentation](AgentGuidelines/Guidelines/Documentation.md) - [Packages](AgentGuidelines/Guidelines/Packages.md) - [CI/CD](AgentGuidelines/Guidelines/CICD.md) +- [Git repositories and SSH-first cloning](AgentGuidelines/Guidelines/Git/Repositories.md) +- [GitHub pull requests](AgentGuidelines/Guidelines/GitHub/PullRequests.md) - [Xcode MCP and visual verification](AgentGuidelines/Guidelines/Xcode/MCP.md) - [Xcode security audits](AgentGuidelines/Guidelines/Xcode/Security.md) diff --git a/Tests/test_validate_guidelines.py b/Tests/test_validate_guidelines.py new file mode 100644 index 0000000..c17e130 --- /dev/null +++ b/Tests/test_validate_guidelines.py @@ -0,0 +1,52 @@ +"""Tests for the guideline repository validator.""" + +from __future__ import annotations + +import importlib.util +import unittest +from pathlib import Path + + +VALIDATOR_PATH = Path(__file__).resolve().parents[1] / "Scripts" / "validate_guidelines.py" +SPEC = importlib.util.spec_from_file_location("validate_guidelines", VALIDATOR_PATH) +assert SPEC is not None +assert SPEC.loader is not None +VALIDATOR = importlib.util.module_from_spec(SPEC) +SPEC.loader.exec_module(VALIDATOR) + + +class SemanticVersionTests(unittest.TestCase): + """Verifies the supported Semantic Versioning grammar.""" + + def test_valid_versions(self) -> None: + """Accepts core, prerelease, and build metadata forms.""" + versions = ( + "0.0.2", + "1.2.3-rc.1+build.5", + "1.0.0-alpha-beta", + "1.0.0+001", + ) + + for version in versions: + with self.subTest(version=version): + self.assertIsNotNone(VALIDATOR.SEMVER.fullmatch(version)) + + def test_invalid_versions(self) -> None: + """Rejects leading zeroes and incomplete identifiers.""" + versions = ( + "01.2.3", + "1.02.3", + "1.2.03", + "1.2.3-01", + "1.2.3-rc.01", + "1.2.3+", + "1.2.3-", + ) + + for version in versions: + with self.subTest(version=version): + self.assertIsNone(VALIDATOR.SEMVER.fullmatch(version)) + + +if __name__ == "__main__": + unittest.main() diff --git a/VERSION b/VERSION index 3ebea8c..4e379d2 100644 --- a/VERSION +++ b/VERSION @@ -1,2 +1 @@ -0.0.1 - +0.0.2 From 94201b06d364b2f0ef4f3d79c18dabbbbb6aad01 Mon Sep 17 00:00:00 2001 From: Fernando Fernandes Date: Tue, 21 Jul 2026 16:13:43 +0200 Subject: [PATCH 5/6] Reference Git and pull request guidelines --- AGENTS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 5e02248..5cc7679 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -17,6 +17,8 @@ Read only the guides relevant to the task: - [Documentation](AgentGuidelines/Guidelines/Documentation.md) - [Packages](AgentGuidelines/Guidelines/Packages.md) - [CI/CD](AgentGuidelines/Guidelines/CICD.md) +- [Git repositories and SSH-first cloning](AgentGuidelines/Guidelines/Git/Repositories.md) +- [GitHub pull requests](AgentGuidelines/Guidelines/GitHub/PullRequests.md) - [Xcode MCP](AgentGuidelines/Guidelines/Xcode/MCP.md) - [Xcode security audits](AgentGuidelines/Guidelines/Xcode/Security.md) From 67fc50adde7efdcdad8f8317ec14a02e7ef5c12a Mon Sep 17 00:00:00 2001 From: Fernando Fernandes Date: Tue, 21 Jul 2026 17:02:28 +0200 Subject: [PATCH 6/6] Squashed 'AgentGuidelines/' changes from 112ac8e..2958ce1 2958ce1 Document Codex review monitoring (#4) git-subtree-dir: AgentGuidelines git-subtree-split: 2958ce14e75f1392918b94d4fd871606fcf1c362 --- CHANGELOG.md | 6 +++ Guidelines/GitHub/PullRequests.md | 67 +++++++++++++++++++++++++++++++ README.md | 4 +- VERSION | 2 +- 4 files changed, 76 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd1f0cc..75a67e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ All notable changes to this project are documented in this file. +## [0.0.3] - 2026-07-21 + +### Added + +- A Codex review-monitoring workflow covering paginated processing reactions and review threads, clean reviews, inline feedback, replies, thread resolution, and CI checks. + ## [0.0.2] - 2026-07-21 ### Added diff --git a/Guidelines/GitHub/PullRequests.md b/Guidelines/GitHub/PullRequests.md index f073b47..5010a47 100644 --- a/Guidelines/GitHub/PullRequests.md +++ b/Guidelines/GitHub/PullRequests.md @@ -24,6 +24,73 @@ Opening a pull request starts review; it does not authorize merging it. A thumbs-up or clean Codex review satisfies the agent-review step, but it does not replace any human approval required by the repository. Do not enable auto-merge before all review gates are satisfied. +### Codex review monitoring + +Use GitHub review data, reactions, and checks together. An eyes reaction means Codex is processing the pull request; it is not an approval. A thumbs-up means the review completed without suggestions. A submitted review means its inline threads must be assessed individually. + +```text +PR opened + | + v +Codex adds eyes reaction + | + +--> thumbs-up ----------------> Clean review + | + `--> Review comments ----------> Assess each comment + | + fix or decline with reason + | + reply in original thread + | + resolve thread +``` + +When using the GitHub CLI, monitor all three surfaces: + +```sh +gh api --paginate repos///issues//reactions +gh pr view --repo / --json reviews,headRefOid +gh pr checks --repo / +``` + +Retrieve inline review threads and their resolution state through GraphQL; top-level pull-request comments do not include this information: + +```sh +gh api graphql --paginate \ + -f query='query($owner: String!, $repository: String!, $number: Int!, $endCursor: String) { + repository(owner: $owner, name: $repository) { + pullRequest(number: $number) { + reviewThreads(first: 100, after: $endCursor) { + nodes { id isResolved } + pageInfo { hasNextPage endCursor } + } + } + } + }' \ + -F owner= \ + -F repository= \ + -F number= +``` + +For every unresolved thread identifier returned above, retrieve its complete comment history with a second paginated query: + +```sh +gh api graphql --paginate \ + -f query='query($thread: ID!, $endCursor: String) { + node(id: $thread) { + ... on PullRequestReviewThread { + comments(first: 100, after: $endCursor) { + nodes { id author { login } body url } + pageInfo { hasNextPage endCursor } + } + } + } + }' \ + -F thread= +``` + +Continue polling while actively working on the pull request. Inspect every returned page for reactions, review threads, and thread comments. Do not treat missing comments, a pending reaction, truncated results, or elapsed time as review completion. + ## Merge requirements Do not merge while any of the following is true: diff --git a/README.md b/README.md index 0fddd3e..4375441 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ The repository contains documentation, not a Swift product. Consumers install a versioned GitHub repository | tagged release - e.g. 0.0.2 + e.g. 0.0.3 | git subtree add/pull | @@ -83,7 +83,7 @@ From the consumer repository root, install a tagged release: git subtree add \ --prefix=AgentGuidelines \ https://github.com/thatfactory/agent-guidelines.git \ - 0.0.2 \ + 0.0.3 \ --squash ``` diff --git a/VERSION b/VERSION index 4e379d2..bcab45a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.0.2 +0.0.3