For any AI agent, model, or tool working in this repository. Read this file fully before starting any task. It is the authoritative source of rules, workflow expectations, and memory conventions.
Before using any value that changes on a regular or unpredictable schedule, always perform a web search rather than relying on training knowledge. This includes but is not limited to:
- CI runner tags and OS versions (e.g.
macos-latest,macos-26,ubuntu-latest) - Xcode and Swift toolchain version strings
- GitHub Actions action versions (e.g.
actions/checkout@v4) - Homebrew formula versions or tap names
- Apple SDK / deployment target version numbers
- Any third-party dependency version that may have had releases
Training data has a cutoff and will silently be wrong about these. A web search takes seconds; a wrong version can waste hours.
Run scripts/bootstrap before opening the project. It installs tooling, resolves Swift packages, and creates Configurations/Signing.local.xcconfig from the committed example file. Open that file and replace YOUR_TEAM_ID_HERE with your 10-character Apple Team ID — Xcode resolves signing automatically after that.
Configurations/Signing.local.xcconfig is gitignored. Do not commit it.
BrewUI is Homebrew's official macOS GUI — a native macOS application that makes Homebrew approachable for users who prefer graphical interfaces over Terminal, while maintaining complete transparency about underlying operations.
Mission: Enable CLI-averse users to safely discover, install, update, and manage Homebrew packages through a native SwiftUI interface that never hides what Homebrew is doing.
Stack: Swift 6.0 · SwiftUI · Swift Package Manager · macOS Tahoe 26+ (also Sequoia 15, Sonoma 14)
See ARCHITECTURE.md for full design detail.
- Read before writing. Before editing any file, understand its current state and purpose. If your change touches structure or design, check
ARCHITECTURE.mdand.ai/memory.mdfor prior decisions and constraints. - Update memory when context changes. If you learn something important about the project (a decision, a pattern, a constraint), add it to
.ai/memory.mdbefore ending the session. - Track local progress as needed. Use local
.ai/progress.mdnotes for active session continuity; keep PRs focused on product and project-documentation changes. - Respect existing conventions. Consult
CONVENTIONS.mdbefore introducing new patterns, file structures, or naming schemes. - Document significant decisions. Any non-obvious architectural or design decision should be captured in
.ai/memory.md(append a dated entry with context and rationale). - Do not guess at intent. If requirements are ambiguous, note the ambiguity in
.ai/scratchpad.mdand surface it to the user rather than making assumptions silently. - Stay in scope for the current deliverable. Check active roadmap docs/issues and local progress notes before implementation. Do not implement features from later phases. Each deliverable should be independently useful before the next begins.
- Work in small, focused stories. Each task should be a single user story or feature. After completing one, run the quality gates before starting the next (see Workflow).
- Prefer small, focused commits. Each change should do one thing and have a clear commit message.
- Never remove or overwrite durable memory files.
.ai/memory.mdis append-and-update. Do not wipe its history.
| File | Purpose | When to update |
|---|---|---|
.ai/memory.md |
Long-term project knowledge, decisions, constraints | When you learn something durable about the project |
.ai/progress.md (gitignored) |
Local per-developer session notes | Optional; update at meaningful milestones |
.ai/scratchpad.md |
Transient working notes | During a session; contents may be cleared between sessions |
- Start of session: Read
.ai/memory.md; also read local.ai/progress.mdif present. - During work: Use
.ai/scratchpad.mdfor working notes. ConsultARCHITECTURE.mdand.ai/memory.mdfor structure and prior decisions. - After each story/feature: Run quality gates before marking it complete and moving on:
- Unit tests pass
- UI tests pass
- Manual pre-merge checklist reviewed
- PR/review ready
- End of session: Update local
.ai/progress.mdif useful for continuity. If anything belongs in long-term shared memory, update.ai/memory.md.
When you change Swift sources or anything that affects Swift formatting or linting (.swiftlint.yml, .swiftformat, Mintfile, Brewfile, scripts/pre-commit, scripts/bootstrap), run the same commands as .github/workflows/swift_quality.yml from the repo root after scripts/bootstrap / mint bootstrap (so Mint resolves tools from Mintfile):
mint run swiftformat --lint .mint run swiftlint lint --strict- BrewUILint (matches CI; first build is slow because it compiles
swift-syntax):swift build --package-path Tools/BrewUILint -c release --enable-experimental-prebuilts"$(swift build --package-path Tools/BrewUILint -c release --show-bin-path)/BrewUILint" $(find Brew Sources -name '*.swift')- BrewUILint lints
Brew+Sources(the whole production tree, all packages);Testsis excluded. It must run over all files in one pass — thenonisolated-extension rule needs to see everynonisolatedtype declaration to flag a bad extension on it. - Keep
Tools/BrewUILint/.buildbetween runs; deleting it forces a full rebuild (~2+ minutes).
The pre-commit hook formats and lints staged Swift files (SwiftFormat/SwiftLint) and additionally runs BrewUILint over the whole tree on every commit; these manual commands validate the whole tree like CI and catch drift in unstaged paths.
scripts/test runs swift test for both packages — BrewKit (root Package.swift) and BrewUILint (Tools/BrewUILint/Package.swift) — matching what .github/workflows/pr_build_test.yml runs in CI.
Agents must run scripts/test and confirm it exits 0 at both of these points:
- Before any
git commityou make. Tests are intentionally not enforced by the pre-commit git hook (too slow to run on every staged-file commit during interactive work), so the responsibility moves to the agent. Ifscripts/testfails, fix it before committing — do not commit with failures, and do not skip the run. - Before reporting a code-changing turn complete to the user, when that turn modified Swift sources under
Sources/,Tests/,Brew/, orTools/BrewUILint/, or changedPackage.swift/Package.resolved/.github/workflows/pr_build_test.yml. For turns that only touch docs, YAML unrelated to tests, or other non-Swift files, the run is optional.
If a test failure surfaces a real regression that's out of scope for the current turn, surface it to the user rather than silently skipping it — never paper over a red test with .disabled or --filter exclusions without flagging.
.github/workflows/pr_build_test.yml runs Periphery (pinned in Mintfile) after the Xcode build, reusing that build's index store (--index-store-path DerivedData/Index.noindex/DataStore --skip-build) so it adds no second build. It scans the Xcode project (config in .periphery.yml) so the Homebrew/ app counts as a consumer of the SwiftPM modules — this reports unused code across the whole program, including dead public API, which a package-only scan cannot.
The check is baseline-gated: it fails a PR only on dead code not already recorded in .periphery-baseline.json (via --strict --baseline). This grandfathers the existing tail so only newly introduced dead code blocks a merge.
- Seeding / regenerating the baseline: it can't be generated in the agent sandbox (needs a working
xcodebuildapp build). If.periphery-baseline.jsonis absent, the CI step writes one and uploads it as theperiphery-baselineartifact without gating — download it, commit it, and the gate activates. To refresh it intentionally (after a deliberate change to the unused set), regenerate on a machine/CI where the app builds: buildBrew-Unitwith-derivedDataPath DerivedData, thenmint run periphery scan --index-store-path DerivedData/Index.noindex/DataStore --skip-build --write-baseline .periphery-baseline.json. - Known-implicit usage is already retained via
.periphery.yml(retain_swift_ui_previews,retain_codable_properties,retain_assign_only_properties). For a genuine one-off that Periphery still can't see, annotate the declaration with// periphery:ignore(or// periphery:ignore:allfor a type and its members) rather than widening the baseline.
AGENTS.md ← you are here; rules for all agents
CLAUDE.md ← Claude-specific extensions (thin)
.cursor/rules/ ← Cursor-specific rule files (thin, scoped)
CONVENTIONS.md ← code style, naming, patterns
ARCHITECTURE.md ← high-level system design (structure; brief context only when unusual)
.ai/
memory.md ← long-term persistent knowledge
progress.md ← local current work state (gitignored)
scratchpad.md ← ephemeral working notes (gitignored)
When guidance conflicts, resolve in this order:
- Explicit user request in the current conversation
- Nearest nested
AGENTS.mdto the file being edited - Root
AGENTS.md - Tool-specific overlays (
CLAUDE.md,.cursor/rules/*)
Use executable checks (CI workflows and git hooks) as the source of truth for mandatory enforcement.
- Do not modify
LICENSE. - Do not commit secrets, API keys, or credentials.
- Do not contradict
ARCHITECTURE.mdor durable decisions recorded in.ai/memory.mdwithout explicitly flagging the conflict. - Do not implement features from a future deliverable phase while the current one is incomplete.
- Do not hard-code file paths — use
ProcessInfoorFileManagerto locatebrew. - Do not hide errors from the user — surface them appropriately.