Contributing to Atlas
On this page
This guide covers building Atlas, checking a change and preparing a pull request. Atlas works with real input, windows and accounts. The architecture guide explains where each behavior belongs and which boundaries to preserve.
By taking part you agree to follow the Code of Conduct. Report security problems privately, as SECURITY.md explains, not in an issue.
Before you start
- Bugs: open an issue with the bug report form. Include
atlas --version, your macOS version and the output ofatlas doctor --verbose. - Ideas and bigger changes: open an issue first, so we can agree on the approach before you spend time on it.
- Small fixes (typos, clear one-line bugs): a pull request on its own is fine.
Set up
You need a Mac with:
- macOS 14 or later
- Xcode 26 or later (Swift 6.2)
- Rust (
rustup;rust-toolchain.tomlpicks the version) - Node 24
git clone https://github.com/InsaneArts/atlas.git
cd atlas
cargo build # the Rust library and atlas command
swift build --package-path app # the AtlasApp executable
npm ci # Node tests and repository checksThese commands compile development executables. They do not package, sign or notarize Atlas.app. The helper daemon must run from Atlas's Developer ID-signed app; do not substitute an unsigned or ad-hoc signed build.
Follow Getting started to install the signed release and
set up the helper, then run target/debug/atlas against that installation. Native
helper testing requires an appropriately signed Atlas installation.
You can still run the automated checks below without starting a helper.
Release packaging lives in xtask/. cargo xtask dist --sign IDENTITY requires a
Developer ID signing identity that satisfies Atlas's identity checks; replace
IDENTITY with that signing identity. The optional --notarize PROFILE selects a
notarytool keychain profile for notarization. A successful local
compile is not evidence that the packaged helper passes macOS consent checks.
Where things live
| Path | What it holds |
|---|---|
src/bin |
the atlas command |
src/lib/daemon |
the helper daemon and its protocol |
src/lib/native |
capture, accessibility, input and the held-input journal |
src/lib/environment |
copies into the helper and their rollback |
src/lib/setup |
the helper's launchd jobs and their repair |
app/ |
Atlas.app in Swift 6: AtlasApp and its Packages/ |
agents/ |
bundled skills, MCP registration and supported host integrations |
scripts/ |
repository checks and live checks against a real helper |
tests/ |
integration tests and the native test fixture |
xtask/ |
release builds (cargo xtask dist) |
See Architecture for the process model, Rust responsibilities and Swift package dependencies. Public user guides live in docs/.
Check your change
CI runs these on every pull request. Run them first:
cargo fmt --all --check
cargo clippy --all-targets -- -D warnings
cargo test
npm run format:check
npm test
node scripts/check-swift.mjs # swift test and swift format lint, app/ and app/Packages/*Passing tests are not enough for anything that changes input, windows, screenshots or setup. Check it on a real helper too:
- Exercise the changed behavior with the CLI (
atlas click,atlas type,atlas screenshot) and look at the screenshots. - For the viewer and input paths, run the live checks in
scripts/(check-input.mjs,check-control.mjs,check-recovery.mjs). - Say in the pull request what you ran and what you saw.
Unit tests, DOM fixtures and rendered previews do not prove that macOS displayed a native window or accepted input. Distinguish those checks from native desktop evidence, including real Save/Open dialogs.
Never test on your own desktop: everything Atlas does belongs in the helper. Locking the screen, sleeping, logging out and switching accounts affect everyone using the Mac, so check with them first.
Rules the code keeps
These hold everywhere; a change that needs to break one needs an issue first.
- Input goes only to the helper's session event tap. Never fall back to global HID input, and keep the user, session, off-screen and display checks before every action.
- Normal macOS consent. Never modify privacy (TCC) settings, store passwords or type them for the person.
- Unknown outcomes stay pending. An action whose result is unknown is
reported as
uncertainand blocks further actions until recovery. Never retry or replay it. unsafeis denied crate-wide. Prefer safe bindings (nix,objc2). FFI without one lives in a module or function markedallow(unsafe_code)with its reason, and everyunsafeblock has aSAFETY:note.- Swift follows
app/'s layout: the domain packages underapp/Packages(AtlasService, AtlasCommands, AtlasControl, AtlasStatus, AtlasOnboarding) hold rules and the service client, AtlasUI holds views and never imports them, AtlasApp holds the AppKit windows. Use the design tokens, one type per file, a///line on every declaration other code can reach, and name tests as sentences. - Plain words in every message a person or agent reads: short, specific, no jargon.
AGENTS.md holds the full list. AI coding agents working on this repository should read it first.
Pull requests
- Keep each pull request to one change, with tests where they make sense.
- Write commit subjects as one scoped line in the present tense, for example
fix(viewer): release held keys when control ends. No body is needed. - Keep public documentation in
docs/. Keepinternal/,runs/and local config (atlas.local.toml) out of the commit. - Update the affected public guide when user-facing behavior changes. Keep bundled agent instructions usable without a repository checkout.
- Fill in the pull request template, including how you tested on screen.
License
By contributing, you agree that your contributions are licensed under the MIT License.