Imported from 4LAU/codex-profile-switcher (
AGENTS.md). Install upstream withnpx skills add 4LAU/codex-profile-switcher. Copyright stays with the author.
Repository Guidelines
Project Structure
Package.swift # SwiftPM targets and products
Sources/
CodexProfileCore/ # Shared auth, path, config, and switch transaction code
Auth/ # Auth token model and auth vault implementations
Profiles/ # Config, path, validation, and profile switching services
Support/ # Shared file/system helpers
Usage/ # Usage/RPC clients and profile selection
CodexProfileSwitcherApp/ # SwiftUI menu bar app, usage polling, settings
CodexProfileCLI/ # CLI helper (login, app switch, status, doctor)
build.sh # Dev build (loose binaries to ~/.local/bin/)
version.env # Marketing version + build number
CodexProfileSwitcher.entitlements # App Hardened Runtime entitlements
CodexProfileHelper.entitlements # CLI helper entitlements
appcast.xml # Sparkle update feed (generated by release script)
Makefile # build, test, check, format, install-cli targets
Scripts/
package_app.sh # .app bundle creation + signing (embeds Sparkle)
release_app.sh # DMG + notarization + Homebrew cask + appcast
generate_homebrew_cask.sh # Cask formula generator
fetch_sparkle.sh # Downloads Sparkle 2.x framework
setup_sparkle_keys.sh # One-time EdDSA key generation
keychain_signed_smoke.sh # Manual Keychain validation
Tests/
run-tests.sh # All tests
run-swift-tests.sh # SwiftPM unit tests
run-integration-tests.sh # Integration tests
AuthBlobTests/ # Auth model tests
LogRedactorTests/ # Log redaction tests
ProfileSelectorTests/
ProfileStoreEnvironmentTests/
assets/ # Menu bar icons, screenshot
docs/ # Public documentation (incl. committed plan docs in docs/plans/)
Build, Test, Run
# Dev build (installs to ~/.local/bin/)
./build.sh
# Run tests
make test # all tests
make test-unit # Swift unit tests only
make test-integration # shell integration tests only
# Full check (tests + build)
make check
# App bundle (for signing/packaging)
Scripts/package_app.sh
# Run the app
codex-profile-switcher
Coding Style
- Swift with system frameworks (Cocoa, SwiftUI, Security, Foundation) plus Sparkle 2.x for auto-updates
- Sparkle is the only external dependency — fetched via
Scripts/fetch_sparkle.sh(not a SwiftPM dependency) - 4-space indentation;
make formatruns swiftformat (config in.swiftformat) - Prefer short functions (max ~30 lines)
- No comments unless the WHY is non-obvious
Project Rules
- Preserve existing user data under
~/.codex/and~/.codex-switcher/ - Never commit credentials, auth files, logs, or local machine artifacts
- Keep macOS behavior native and predictable
- Menu bar interactions should stay quick and quiet
- Integration tests are hermetic: temporary home, fake binaries, file-backed vault
- Never add automated tests that touch the real macOS Keychain
- Sparkle update checks only exist in packaged
.appbuilds. The loose dev binary from./build.shwill not show Check for Updates... - Public releases must include a committed
appcast.xmlupdate fromScripts/release_app.sh; pushing that file tomainis what publishes the Sparkle feed
Plan File Location
Save working plans to .plans/ (gitignored), not to any planning skill's default location. Plan or manifest docs that are meant to ship with a feature go in docs/plans/ (tracked); everything else in docs/ is public documentation.
Open Source Hygiene
This is a public open source project. Before committing:
- Use conventional commits:
feat:,fix:,chore:,docs:,test:,ci:— short imperative subject line, no body needed for small changes - Never commit internal planning docs, AI tooling config, or credentials
- Keep git history clean — no WIP commits on main
- Update CHANGELOG.md (Unreleased section) for user-visible changes
- Version lives in three places that must stay in sync (CI enforces):
version.env,Sources/CodexProfileSwitcherApp/AppInfo.swift, andSources/CodexProfileCLI/CodexProfileCLI.swift(private static let version)
Release Credentials
- Use
NOTARY_KEYCHAIN_PROFILE=notary-apikeyfor Apple notarization (profile holds the App Store Connect API key; the oldnotarytoolprofile is defunct).
Pull Requests
Before opening a PR:
- Run
make check - Sanity-check profile switching and menu rendering if your change affects them
- Update documentation when user-visible behavior changes
- Include a screenshot for UI changes
Open an issue before large changes so the direction is agreed first.
Agent Notes
- Always rebuild before testing (
./build.sh) - SwiftPM source membership is the build source of truth. Do not add root Swift files or script-only source lists.
- The app reads
~/.codex-switcher/config.jsonand stores auth in macOS Keychain - Use
CODEX_PROFILE_HOMEand file-backed vaults for isolated testing - The CLI helper is at
~/.local/bin/codex-profileafter a dev build - Smoke-test Sparkle with
/Applications/CodexProfileSwitcher.app, not~/.local/bin/codex-profile-switcher
By submitting a contribution, you agree that your work will be licensed under the repository's MIT license.
