AGENTS.md template
Copy-paste the project-local consumer AGENTS.md contract for SwiftUI and Apple-platform repos.
SwiftUI and other Apple-platform consumer repos that use Apple Development Foundation skills should have a root AGENTS.md. If yours is missing, copy the template below. If one already exists, preserve it and merge only with explicit authorization.
This contract is project-local. Paste it into <consumer>/AGENTS.md. Do not paste it into global ~/.codex/AGENTS.md.
How to install
- Copy/paste — Create
<consumer>/AGENTS.mdfrom the template on this page when the file is missing. - Initializer — From this foundation repo:
./Scripts/init-consumer-guidance.sh --target /path/to/consumer --dry-run ./Scripts/init-consumer-guidance.sh --target /path/to/consumer - Bootstrap —
$codex-bootstrap(via$apple-development-foundationwhen routing) may propose create or merge; it waits for authorization and never overwrites silently.
The initializer refuses this foundation repository and any existing AGENTS.md path. Details: Scripts · Bootstrap · Troubleshooting.
Customize before relying on it
Fill every <…> placeholder from checked-in project configuration. Do not invent schemes, destinations, or policy values.
| Fill in | Examples |
|---|---|
| Project or workspace | App.xcodeproj, App.xcworkspace |
| Scheme / configuration | scheme name, Debug |
| Platforms and min OS | iOS 17+, macOS 14+, or both |
| Destinations | exact simulatorId; macOS arch or n/a |
| Formatter / linter / checks | repo-native commands or not configured |
| Targeted and full tests | repo-native or MCP test scope |
| UI E2E contract | configured with the selected tool and real values or not configured / n/a when UI E2E is not in scope |
| Apple verification policy | XcodeBuildMCP CLI and raw xcodebuild/xcrun/simctl: keep require-approval unless you authorize allowed or denied |
Scoped AGENTS.md files in subdirectories refine this root contract for their trees; keep them when present.
Canonical source
The bootstrap skill asset is the source of truth:
.agents/skills/codex-bootstrap/assets/consumer-AGENTS.md.template
This page mirrors that file for website copy-paste. Prefer the skill asset when scripting installs.
Template
Copy everything inside the fence into <consumer>/AGENTS.md:
# Consumer Apple-platform engineering contract
This file governs work in this repository. Customize every value in angle
brackets before relying on project-specific build or test instructions. Preserve
more-specific `AGENTS.md` files in subdirectories; their instructions refine
this contract for files in their scope.
## Project configuration
- Project or workspace: `<PROJECT_OR_WORKSPACE_FILE>`
- Scheme: `<SCHEME>`
- Build configuration: `<CONFIGURATION>`
- Target platforms: `<IOS_MACOS_WATCHOS_TVOS_VISIONOS_OR_SWIFT_PACKAGE>`
- Minimum deployment versions: `<PLATFORM_VERSION_PAIRS>`
- Destination:
- iOS / simulator targets: `<EXACT_SIMULATOR_ID>` or project-local defaults in
`.xcodebuildmcp/config.yaml`
- macOS targets: `<MACOS_ARCH_OR_PROJECT_DEFAULT>` (enable the XcodeBuildMCP
`macos` workflow); leave as `n/a` when the repo is iOS-only
- Shared iOS + macOS: fill both of the above
- Formatter: `<REPOSITORY_NATIVE_FORMATTER_COMMAND_OR_NOT_CONFIGURED>`
- Linter: `<REPOSITORY_NATIVE_LINTER_COMMAND_OR_NOT_CONFIGURED>`
- Additional type or build checks:
`<REPOSITORY_NATIVE_CHECK_COMMANDS_OR_NOT_CONFIGURED>`
- Targeted tests: `<REPOSITORY_NATIVE_TARGETED_TEST_COMMANDS_OR_MCP_TEST_SCOPE>`
- Full tests: `<REPOSITORY_NATIVE_FULL_TEST_COMMANDS_OR_MCP_TEST_SCOPE>`
## UI inspection contract
For user-visible iOS/iPadOS UI, fill this section even when UI E2E is not
configured. For a project without iOS/iPadOS UI, set each value to `n/a`.
- Deterministic inspection routes or states:
`<ROUTES_STATES_DEEP_LINKS_OR_N_A>`
- UI-only launch arguments/environment (do not include secrets):
`<APPEARANCE_DYNAMIC_TYPE_FIXTURE_OR_OTHER_UI_ARGUMENTS_OR_N_A>`
- Risk-based evidence matrix: `<PRIMARY_ROUTE_AND_CONDITIONAL_SHEET_APPEARANCE_DYNAMIC_TYPE_SCENARIOS_OR_N_A>`
- Evidence procedure: for every selected scenario, use XcodeBuildMCP to capture
a screenshot, visually inspect it, and capture `snapshot_ui`; record manual-only
checks separately
- Artifacts: `<DEBUG_OUTPUT_SCREENSHOT_HIERARCHY_VIDEO_DESTINATION_OR_N_A>`;
preserve failure artifacts while redacting secrets and private user data
## UI E2E test contract
Optional. Fill this section only when the project uses a UI E2E tool for user
journeys. This may be Maestro, XCUITest, Appium, or another configured tool.
The contract is either `configured with the selected tool and real values` or
`not configured / n/a when UI E2E is not in scope`.
For a project without UI E2E—whether it is macOS-only, visionOS/watchOS, a
Swift package, or another target—set:
- UI E2E tool: `not configured` (or `n/a`)
and leave the remaining fields as `n/a`. Do not invent a destination,
tool-specific test directory, or onboarding flow when E2E is not in scope.
Agents must not treat an unconfigured contract as an executable UI E2E
destination.
When UI E2E **is** in use, document the deterministic app contract before
relying on journeys. Use fields that match the selected runner; do not assume a
specific directory, protocol, device type, identifier format, or onboarding
mechanism. Keep secrets out of this file, flow files, fixtures, and artifacts.
- UI E2E tool: `<E2E_TOOL_NAME_OR_NOT_CONFIGURED_OR_N_A>`
- UI E2E commands: `<E2E_RUNNER_COMMANDS_OR_N_A>`
- Application identifier (bundle ID, package ID, or other runner identifier):
`<APPLICATION_IDENTIFIER_OR_N_A>`
- Test location and naming: `<TOOL_SPECIFIC_ROOT_OR_AGREED_PATH_OR_N_A>`;
document journeys/tests `<JOURNEY_OR_TEST_NAME>` and reusable
subflows/helpers `<SUBFLOW_OR_HELPER_NAME>` using
`<NAMING_OR_TAGGING_CONVENTION_OR_N_A>`
- Deterministic routes or states/deep links: `<E2E_ROUTES_STATES_DEEP_LINKS_OR_N_A>`
- Risk-based evidence matrix: `<E2E_EVIDENCE_MATRIX_OR_N_A>`; align it with the
UI inspection contract when the selected runner supports the same scenarios
- Exact destination/configuration when required by the selected runner:
`<E2E_DESTINATION_OR_N_A>`, scheme `<SCHEME_OR_N_A>`, and build
configuration `<CONFIGURATION_OR_N_A>`; reuse project-defined values across
build, launch, and E2E commands when applicable
- E2E-only launch arguments/environment beyond the UI inspection contract:
`<LAUNCH_ARGUMENTS_OR_N_A>` and `<ENVIRONMENT_VARIABLES_OR_CONFIG_SOURCE_OR_N_A>`;
inject secrets locally or in CI rather than committing them
- Reset and seed strategy: `<RESET_OR_FRESH_INSTALL_PROCEDURE_OR_N_A>` and
`<SEED_COMMAND_OR_FIXTURE_OR_N_A>`; state what persists across relaunch and
when app data, keychain, permissions, or backend state must be reset
- Onboarding state: `<FIRST_RUN_AND_COMPLETED_STATE_OR_N_A>`; specify how tests
enter each state and whether onboarding is required, conditional, or a
dedicated subflow
- Fixtures and test accounts: `<DETERMINISTIC_FIXTURE_SOURCE_OR_N_A>` and
`<NON_PRODUCTION_TEST_ACCOUNT_NAMES_OR_N_A>`; define ownership, cleanup, and
account reset behavior
- E2E artifact location: `<E2E_ARTIFACT_LOCATION_OR_N_A>`; preserve failure
artifacts while redacting secrets and private user data
- Accessibility-ID conventions: when E2E is configured, use stable
`<ACCESSIBILITY_ID_PREFIX>.<SEMANTIC_NAME>` selectors on actionable elements,
keep human-readable accessibility labels, and document any native-control
exception; otherwise `n/a`
## Apple verification policy
Fill these before relying on fallback behavior. Shell access or an installed
binary is never permission by itself.
- XcodeBuildMCP CLI fallback: `require-approval`
(allowed values: `require-approval` | `allowed` | `denied`)
- Repository-native raw `xcodebuild` / `xcrun` / `simctl`: `require-approval`
(allowed values: `require-approval` | `allowed` | `denied`)
Interpret as:
- `allowed` — the matching ladder step may run without asking again
- `require-approval` — ask the user before that step when MCP tools cannot
complete the needed action
- `denied` — never use that step; report blocked when MCP cannot complete it
Do not guess missing values. Inspect checked-in project configuration and scripts,
then ask before choosing among materially different targets or workflows. Keep
machine-specific simulator IDs and Mac destinations in project-local configuration
only when the team intentionally shares them.
## Engineering lifecycle
Use an inspect → implement → verify → handoff lifecycle, scaled to the task.
### Inspect
- Read every `AGENTS.md` from the repository root through the files in scope.
- Inspect `git status` and relevant diffs before editing. Treat existing changes
as user-owned and preserve unrelated work.
- Read relevant manifests, project settings, package definitions, task runners,
and repository scripts. Prefer documented repository commands.
- Identify the smallest coherent file and target scope that satisfies the task.
### Implement
- Make the smallest cohesive change that satisfies the request. Avoid unrelated
cleanup and preserve established architecture unless the task changes it.
- Use Swift 6.2 or later for new Swift code. If an existing target is not configured for
Swift 6.2, report the compatibility constraint and request authorization before
changing project-wide language settings. Prefer structured concurrency,
explicit state ownership, native observation, and initializer or environment
dependency injection. Do not introduce a view model without a state-ownership
or testability reason.
- Do not add, remove, or upgrade dependencies, change lockfiles, or run data
migrations unless explicitly authorized.
- Do not deploy, publish, push, create a pull request, cut a release, or change
external systems unless explicitly authorized.
- Never use destructive Git operations or blanket staging. Stage only explicit
paths when a commit is requested or otherwise authorized by repository policy.
### Verify
- Start with the narrowest relevant formatter, linter, build, and tests from the
project configuration above. Broaden verification according to risk.
- Treat failures as work to investigate. Do not silently ignore a failed or
unavailable check.
- Do not modify code merely to make unrelated pre-existing failures disappear.
### Handoff
- Summarize what changed and why.
- Report every verification command or MCP action and its outcome.
- Report the active project/workspace, scheme, configuration, platform, and exact
destination (simulatorId and/or macOS) used.
- Identify skipped or failed checks, remaining risks, and preserved unrelated
working-tree changes.
## XcodeBuildMCP workflow
Use XcodeBuildMCP first for Apple-platform builds, tests, and runs. Do not
silently fall back to raw `xcodebuild`, `xcrun`, or `simctl`. Branch by the
**Target platforms** value above — do not use iOS simulator tools for a
macOS-only app, and do not skip the `macos` workflow when macOS is in scope.
1. Before the first build, run, or test action in a session, call
`session_show_defaults`. Report the active project/workspace, scheme,
configuration, and platform destination.
2. If defaults are missing or incorrect, use `session_set_defaults`; use project
discovery only when the correct path is not already known.
3. **iOS (simulator) targets:**
- Prefer one exact `simulatorId` over name-only or `OS=latest` destinations.
- Reuse an already-booted simulator. For a manual launch, use `build_run_sim`;
do not separately build, boot, install, and launch for the same operation.
- Use `test_sim` as the complete simulator test workflow. Do not build
immediately before it unless a separate compile-only build was requested.
- Before simulator tests, check for another active `xcodebuild`, `xctest`, or
project test-runner process. Wait rather than starting a concurrent run for
the same project.
- Run simulator tests serially with
`extraArgs: ["-parallel-testing-enabled", "NO"]` unless the project
explicitly requires and has verified parallel workers.
- Optional: `screenshot` / `snapshot_ui` within test workflows when the `ui-automation` workflow is
enabled (iOS simulator only). This does not relax the UI inspection contract above, which still requires per-scenario captures for user-visible iOS/iPadOS work.
4. **macOS targets:**
- Enable and use the XcodeBuildMCP `macos` workflow.
- Prefer `build_run_macos` for a launch smoke.
- Use `test_macos` when a test target exists; default
`extraArgs: ["-parallel-testing-enabled", "NO"]`.
- If neither launch smoke nor `test_macos` runs, require at least
`build_macos` so the target is compiled.
- Do **not** call `build_run_sim`, `test_sim`, or ui-automation
screenshot/hierarchy tools for macOS — those are iOS-simulator-only.
- If no test target exists yet, report that `test_macos` was skipped and the
residual risk only after `build_run_macos` or `build_macos` succeeds.
5. **Shared iOS + macOS:** verify each platform with its branch above.
6. If an MCP capability is unavailable, apply **Apple verification policy**
above for XcodeBuildMCP CLI. Use CLI only when that policy is `allowed`, or
when it is `require-approval` and the user has just approved this step. If the
policy is `denied`, skip CLI and evaluate the next ladder step.
7. Use repository-native raw `xcodebuild`, `xcrun`, or `simctl` only when the
raw-tooling policy is `allowed`, or `require-approval` with fresh user
approval. Preserve the same project/workspace, scheme, configuration, exact
destination, serialized execution, and test scope. For macOS fallbacks, state
destination architecture explicitly (for example `platform=macOS,arch=arm64`).
8. If no authorized path exists, report blocked with the exact unavailable
capability, policy value in force, checks not run, next action, and residual
risk.
For Swift packages without an Xcode project, prefer the XcodeBuildMCP Swift
package workflow when available, then use configured repository-native commands
only when active policy authorizes them, with the same inspect and reporting discipline.
## Accessibility, privacy, and security
- SwiftUI must support Dynamic Type, VoiceOver, keyboard access where applicable,
sufficient contrast, Reduce Motion, and Differentiate Without Color.
- Give every icon-only control a descriptive accessibility label. Preserve native
controls and platform conventions unless a custom interaction is justified and
equivalently accessible.
- Request only necessary entitlements and permissions. Explain user-data impact
when changing persistence, imports/exports, permissions, or file access.
- Never log credentials, tokens, private content, raw imported data, complete
sensitive paths, or security-scoped URLs. Redact diagnostics and keep secrets
out of source control, fixtures, screenshots, and handoff text.