Contributing
Thank you for helping with Atlas. This page is the long version of CONTRIBUTING.md. By taking part you agree to the Code of Conduct. Atlas is released under the MIT license, and your contributions are too.
Ways to help#
- Report a bug or ask for a feature in the issue tracker. Include
atlas version, your OS, the steps and the relevant lines of.logs/<service>.log(redact secrets). - Improve the docs. Every page on the website has an Edit on GitHub link; the source is
docs/*.md. - Send a fix or a feature. For anything bigger than a small fix, open an issue first so we can agree on the shape before you spend time on it.
- Security issues do not go in public issues. See SECURITY.md.
Set up#
You need rustup, bun and, for the desktop app, the Xcode command line tools. gh is optional.
git clone https://github.com/codeatlasdev/atlas.git
cd atlas
scripts/setup.sh # idempotent: checks tools, installs frontend deps, cargo-tauri and cargo-deny
The Rust toolchain is pinned in rust-toolchain.toml; rustup installs it on the first cargo command. Workspace lints apply to every crate: fix warnings, do not add global allows.
The gate#
bun run check
bun run check is the only gate and the one CI runs. It chains, in order:
cargo fmt --all -- --checkcargo clippy --workspace --all-targets --locked -- -D warningscargo test --workspace --lockedcargo deny check(licenses, advisories, duplicate and banned crates)scripts/check-skills.sh(validatesskills/*/SKILL.mdagainst the Agent Skills spec)bun run desktop:check(svelte-check, prettier andbun testfor the frontend)
Run it on its own and read the exit code before you push. A pull request should pass it.
Also useful:
| Command | Use |
|---|---|
bun run dup | jscpd duplication report; keep it at or below 1.5% |
cargo test -p atlas-cli --test mcp | the MCP integration suite (real binary, live headless run; needs python3) |
cargo test -p atlas-tui --release -- --ignored --nocapture bench_one_million | the log pipeline benchmark |
cargo test -p atlas-term --release -- --ignored --nocapture screen_bench | the terminal renderer benchmark |
Build and run your changes#
cargo build -p atlas-cli # builds the `atlas` binary (atlas-tui alone is only a library)
codesign -f -s - target/debug/atlas # macOS: ad-hoc sign or Gatekeeper kills it
atlas link # symlink ~/.atlas/bin/atlas to the debug build
atlas unlink # restore the release binary
Develop the desktop app#
bun run desktop:dev # hot reload: Vite + the Tauri shell; Rust changes rebuild
atlas link --desktop # make /Applications/Atlas.app your debug bundle
While linked, the app shows a Dev build badge and refuses to update over your build.
Debug builds run a bridge on ~/.atlas/desktop-debug.sock, so you (or an AI agent) can inspect the app without the mouse:
atlas desktop debug info
atlas desktop debug logs --level csp # console, errors, CSP violations
atlas desktop debug eval 'return await window.__TAURI_INTERNALS__.invoke("projects_list")'
atlas desktop debug shot /tmp/x.png
Debug builds also expose the live stores as window.__atlas (ws, store, agents, worktrees, api, host); use them from debug eval instead of import(), which creates separate module instances. Check CSP and IPC on the bundled build (tauri://localhost), not only on Vite. After a hot reload, reload the webview before trusting socket behavior.
Code layout#
See Architecture for the crates and how the processes talk to each other. Where things go:
| Change | Where |
|---|---|
a new atlas subcommand | crates/atlas-cli/src/commands/ |
| config fields, validation, the JSON Schema | crates/atlas-tui/src/config/ |
| scheduling, health, restarts, actions | crates/atlas-tui/src/runtime/manager/ |
| TUI widgets and keys | crates/atlas-tui/src/tui/ (the key table is keymap.rs) |
| MCP tools, resources, prompts | crates/atlas-tui/src/mcp/ |
| terminals, exec, files | crates/atlas-host/ |
| terminal rendering | crates/atlas-term/ |
| desktop backend | crates/atlas-desktop/src/ |
| desktop UI | apps/desktop/src/ |
| agent skills | skills/<name>/SKILL.md (embedded at build time) |
Conventions#
- Tests. Prefer behavior tests: boundaries, failures and state transitions over getters. Manager tests live in
runtime/manager/tests.rsand are wired by#[cfg(test)] mod tests;inmod.rs; when you split modules, check the test count does not drop. Integration tests drive the real binary. - Docs move with code. A change that alters a flag, a key, a config field or a behavior updates the page that documents it, in the same pull request. The TUI help and footer are generated from one keymap table; the desktop shortcuts are
DEFAULT_KEYMAPinapps/desktop/src/lib/keys.ts. - Changelog. User-visible changes get a line under
## [Unreleased]inCHANGELOG.md. Release notes are built from it. - Formatting.
.editorconfigapplies: tabs in TypeScript, Svelte and shell; 4 spaces in Rust; 2 spaces in YAML, Markdown and JSON. - Commits. Short imperative subject, conventional prefixes (
feat:,fix:,docs:,chore:) as in the history. Explain why in the body when it is not obvious. - Dependencies. Prefer the standard library and what is already in the tree. A new crate or package needs a reason in the pull request;
cargo deny checkmust pass.
Runtime rules that came from real incidents#
Keep these when you touch the runtime (Architecture):
- Orphan cleanup uses only the
.pidsfile and exact PIDs; neverlsofport-kill or negative PIDs. - Never run
docker compose downor restart the docker daemon from Atlas. - Children:
setsid,stdin(null),sh -cfor commands. - TUI: event-stream input, dirty-flag rendering, non-blocking startup.
- Desktop: child webviews make the main window multi-webview; use
get_window("main")for window operations andget_webview("main")for the app’s own webview. Never put a secret in content loaded into the embedded browser.
Pull requests#
- Fork, branch from
main. - Make the change with its tests and doc updates.
- Run
bun run check. - Open a pull request using the template; link the issue it closes.
A maintainer will review it. Small, focused pull requests get merged faster than large ones.
CI and releases#
CI and releases are local only: both workflows are workflow_dispatch and are run on a maintainer’s machine through act (bun run ci:act, bun run release). Do not expect hosted Actions on your pull request; the maintainer runs the gate. See Releasing.