agentleFS
pacifiopacifio/atlas/AGENTS.md

atlas

AGENTS.md9.4k starsChanged 6 days agoApache-2.0View on GitHub

CLAUDE.md is a symlink to it, for Claude Code. Atlas is a Tauri v2 desktop app: a React 19 frontend over a Rust backend, one cargo workspace, and the agent engine under vendor/atlas-engine/ (its crates are atlas-engine-*; ADR-0003 has its origin). This file is deliberately short. It carries the commands, and the invariants that fail silently — where nothing errors, every gate is green, and the symptom is in the shipped binary. Everything else is a pointer, because a second…

  • Deletes or force-pushes

1 other project uses a version of this.

Trending

More talk lately.about the whole repository

Dec 2025: 0 mentionsJan 2026: 0 mentionsFeb 2026: 0 mentionsMar 2026: 0 mentionsApr 2026: 0 mentionsMay 2026: 0 mentionsJun 2026: 0 mentionsJul 2026: 0 mentionsAug 2026: 2 mentionsSep 2026: 12 mentionsOct 2026: 6 mentionsNov 2026: 0 mentions
Dec 2025Jun 2026Nov 2026
Mentions a month of the pacifio/atlas repository that our weekly crawl found. There is no adoption data for this file yet.

Most recently taken up by

Who's talking about pacifio/atlas

The biggest 5 of 20 mentions linking to the repository that our crawl found. Each line is their own headline.

See all 20

Talked about on GitHub, Bluesky, Hacker News and the web (20 times).

On GitHub · 9

4 more on GitHub

On Bluesky · 9

4 more on Bluesky

On Hacker News · 1

On the web · 1

  • Other versions1 project uses a version of this.

    Word for word · 1

    1. tryatlas/atlas★ 9.4k100% same

    Edited · 0

    None found.

    Wrote their own version · 0

    None found.

    How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.

  • Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.

    Of the AGENTS.md files we read, the 31,774 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.

The file

We split this AGENTS.md into the rules it gives an agent

5 rules. About 0 are common, 1 is distinctive, and 4 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 4

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Never --workspace, never the container.

    line 67
  2. Very specific:

    If it reads a file outside its own directory, that file also goes in EXTRA_INPUTS in scripts/ci-affected.mjs (ci-affected.test.ts checks).

    line 206
  3. Very specific:

    Every blocking operation on the Rust side — Command::output, file I/O over large trees, git — runs inside tokio::task::spawn_blocking.

    line 234
  4. Distinctive:

    No new top-level dependencies without discussion.

    line 238
  5. Very specific:

    Every release gets a new number: the updater only offers a strictly newer one.

    line 305

≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
AGENTS.md

AGENTS.md

This file provides guidance to coding agents working in this repository. CLAUDE.md is a symlink to it, for Claude Code.

Atlas is a Tauri v2 desktop app: a React 19 frontend over a Rust backend, one cargo workspace, and the agent engine under vendor/atlas-engine/ (its crates are atlas-engine-*; ADR-0003 has its origin).

This file is deliberately short. It carries the commands, and the invariants that fail silently — where nothing errors, every gate is green, and the symptom is in the shipped binary. Everything else is a pointer, because a second copy of it here would drift out of date without anything noticing. A rule stays inline when the pointer wouldn't surface it: a ban with no exit, or a decision whose rule isn't in its title.

Where the answers live

questionread
how a feature crosses the stack; a subsystem's file pathsdocs/architecture.md
verification gates, branching, PR checklist, telemetry rulesCONTRIBUTING.md
what a term meansCONTEXT.md
why a decision is what it isdocs/adr/
tokens, type/radius/elevation/z-index/motion scales, primitivesdocs/reference/design-system.md
theme keys, theme import, icon themes, config, keybindingsdocs/reference/
Linux packages, supported distros, release signingdocs/reference/linux-support.md
the browser mock backendsrc/dev/mock-backend/README.md
what a contract suite guards, and why nothing else canthat suite's docblock in tests/
what the web app, the org agent (Atlas), ROI or RC do; their wire contracts../server/docs/api/ (pull first)
what CI actually runs.github/workflows/ci.yml (commented throughout); for a given diff, node scripts/ci-affected.mjs --base <rev>

Count things, don't quote counts. Commands, crates, tab types and test suites all move weekly — ls src-tauri/src/commands/*.rs, ls tests/*.test.ts, src/lib/constants.ts. A number written in prose anywhere, including here, is stale.

Commands

bun run dev          # Vite in a real browser on the fake backend — use for any visual change
bun run dev:app      # full Tauri dev; required for anything that hits invoke()
bun run build:app    # release .app  (build:app:dmg → +DMG, build:app:win → MSI)

The gates. Which of them a piece of work needs depends on where it is; see the two tiers below the block.

bun run lint            # oxlint
bun run format:check    # oxfmt
bun run typecheck       # BOTH tsconfig.json and tsconfig.test.json
bun run test            # vitest, everything
bun run test:contracts  # just tests/ — what the pre-commit hook runs
cargo check --workspace
bun run test:rust       # a SUBSET of CI; the script's header lists what it omits
bun run ci:local        # what CI would run for this branch, as CI runs it (clippy included)
                        # — the jobs that need Linux (the engine sandbox, the app's
                        #   GTK build) go to a Docker container (any Docker-compatible
                        #   runtime; CONTRIBUTING.md) when the plan includes them;
                        #   --native skips it

How hard to test depends on where the work is:

  • While committing — light. This is "done" for a commit. Lint, format, typecheck, the vitest files for what changed (bun run test <paths>), and cargo test -p <crate> for the crates touched, natively. The pre-commit hook already adds test:contracts. Never --workspace, never the container.
  • Before submitting a PR — heavy. This is "done" for a PR. bun run ci:local: every job CI would plan for the branch, natively, plus Linux-target clippy for the crates flagged cross. Only the jobs that need Linux itself (the sandbox crate's suites, the app's GTK compile) go to the container, and only when the plan includes them. A red job here is a red job in CI; fix it before opening the PR. The app's Windows compile check (app-windows) is the one job that runs only in CI. --linux is the full container replica, for when you suspect the Ubuntu userland itself. It plans against the merge base with the branch's upstream, so a branch that tracks its own remote plans almost nothing: pass the PR's base, bun run ci:local --base origin/main.

Rust (rust-toolchain.toml), Bun and Node (mise.toml) are pinned to what CI installs. Bumping Rust brings new clippy lints: fix them in the same change.

bunx tsc --noEmit is not the typecheck gate: tsconfig.json sets "types": [] and excludes test code, so it skips every test file. Use bun run typecheck.

Narrowing:

bun run test src/lib/time-ago.test.ts
cargo test -p atlas-native-agent --test engine_turn   # -p resolves from anywhere

Generated files — the TOML/SVG is the source, the committed output is derived, and a suite fails the moment they disagree. Edit the source and regenerate:

bun run theme:keys     # @tryatlas/design's keys.toml, themes, Rust tables → crates/atlas-theme; schema, docs
bun run icons:render   # macOS app icons
bun run settings:gen   # settings-registry.toml → TS, Rust, docs; then
                       # ATLAS_BLESS=1 cargo test -p atlas config_default
                       # for docs/reference/config.default.toml

The design system (primitives, scales, theme engine, keys.toml, built-in themes, the ratchet's rules) is @tryatlas/design, pinned to a git tag (ADR-0027). Change it there and bump the pin; crates/atlas-theme/ holds committed copies, never edited by hand (design-package-copies.test.ts). globals.css imports styles-core.css (no built-in theme CSS: applyTheme writes the active theme at runtime). Theme variables are unprefixed (element.hover → --element-hover), and a theme file that isn't schema = 1 is skipped while the default loads: there is no legacy theme support.

Pre-commit (husky): lint-staged → bun run typecheck → bun run test:contracts. Pre-push: the full bun run test.

crates/atlas-kb-server is workspace-excluded (its own Cargo.lock, its own release profile; compiled at runtime by commands::knowledge_export). Test it from inside its directory.

Invariants that fail silently

Each has a suite in tests/. Read that suite's docblock before changing what it guards.

The design-system ratchet is closed at zero (design-system-ratchet.test.ts; the rules are @tryatlas/design/ratchet). Arbitrary text-[…]/z-[…]-style values, colour literals, Tailwind's stock ramps, inline numeric styles and transition-all all fail it; use the scale and the tokens. A failure lists every site and what to write instead. The only exits are EXEMPT_FILES or an inline ratchet-allow: <reason> comment with a real 20+ character argument (the suite's docblock has the rules for both). One ban has no exit at all: the retired --atlas- spelling of a theme key, anywhere in src/ or index.html (it resolves to nothing and paints transparent). A violation type-checks, lints and renders perfectly; this suite is the only thing that sees it.

bun run lint also runs @shadcn/lint, whose rules are errors. no-unknown-classes catches a class Tailwind can't generate — a typo, or a plugin utility Atlas doesn't ship — which otherwise renders as nothing. no-restyle stops className from overriding a @tryatlas/design primitive's look: when it fires, use the variant its message names, or add one to the primitive in the package; don't restyle at the call site. Plain stylesheet classes are allowlisted by exact name in .oxlintrc.json (shadcn-lint-allowlist.test.ts keeps that list honest — never add a wildcard).

Anything reading a resolved colour needs a theme subscription (theme-subscription-contract.test.ts). CSS naming a theme key, var(--element-hover), recolours for free; xterm, pixi, recharts and friends cannot, so they must hear the change.

The IPC and event seams are opaque strings to tsc. invoke("name"), the atlas:* channel names, and even the field names inside a payload are checked by ipc-contract, event-contract, state-payload-contract and wire-shape-contract and by nothing else. Check event-contract.test.ts before inventing a channel name.

Three cargo-workspace rules, each failing quietly (cargo-workspace.test.ts): [patch] tables are honored only in the manifest cargo was invoked on — always the root; profiles are workspace-global, so no member may carry its own; and [profile.dev.package."*"] does not match workspace members, which is why every member restates opt-level = 1.

The engine is quarantined. Exactly one manifest may name an atlas-engine-* crate: crates/atlas-native-agent/Cargo.toml (engine-quarantine.test.ts). The Apache-2.0 LICENSE/NOTICE travel with the code (vendor-licensing.test.ts, needs fetch-depth: 0), and the stripped telemetry paths must stay stripped (engine-no-phone-home.test.ts). Per ADR-0003 the port is first-party code — editing it, manifests included, is ordinary work, not a fork edit. clippy.toml at the repo root is the engine's own lint config, kept at the root; without it the atlas-native-agent Clippy job fails on ~500 engine sites.

Node singletons and the Vite dedupe list are load-bearing. Two copies of @codemirror/* or pdfjs-dist break editor theming and PDF rendering in production only. @tryatlas/design, @base-ui/react and motion are in the dedupe list too (a second @base-ui/react splits the floating-UI contexts). bun install/bun update leave nested duplicates; after a lockfile change do rm -rf node_modules && bun install (a full rm -rf node_modules bun.lock to dedupe). bun-singletons.test.ts is what tells you. manualChunks is equally load-bearing — each rule encodes a production incident, documented inline.

Four build-config facts that look like cruft. Each is argued at its own site; don't undo one without reading that comment. lto = "thin" in the root Cargo.toml; crate-type = ["rlib"] in src-tauri/Cargo.toml; .cargo/config.toml's MACOSX_DEPLOYMENT_TARGET, which must equal bundle.macOS.minimumSystemVersion and must never be joined by REMOVE_UNUSED_COMMANDS (tauri-utils reads its mere presence as "prune every command no capability allows"); and scripts/build-frontend.mjs as beforeBuildCommand. Also: cargo build --release -p atlas recompiles tauri and six plugins unless you add --features tauri/custom-protocol, which the CLI adds on release builds.

Release panic = "unwind" is required and lives in the root Cargo.toml — three independent catch_unwind guards depend on it.

The single-instance plugin is release-only. Registering it in debug kills tauri dev whenever the installed /Applications/Atlas.app is running.

Telemetry is opt-OUT, on by default (share_telemetry in src-tauri/src/state/atlas_config.rs). Coarse metadata only; TELEMETRY.md and CONTRIBUTING.md list what may never be sent, and a pipeline change updates TELEMETRY.md in the same PR.

.gitignore ignores *.md except an allowlist (read the block around line 38). Anything outside it — including most of docs/agents/ — shows as !! ignored rather than ?? untracked, so new markdown that should ship needs git add -f plus a .gitignore exception or it silently drops out of the commit.

Adding things

Each of these is a multi-file edit where missing one compiles fine.

  • An IPC command — the fn in src-tauri/src/commands/<domain>.rs, pub mod in commands/mod.rs, an entry in generate_handler![] in lib.rs, and a wrapper in src/features/<feature>/lib/<domain>-api.ts. Never invoke from a component.
  • A crate — the members list in the root Cargo.toml, its own [profile.dev.package.<name>] stanza, and an entry in .github/ci-crates.json. If it reads a file outside its own directory, that file also goes in EXTRA_INPUTS in scripts/ci-affected.mjs (ci-affected.test.ts checks).
  • A tab/panel type — first decide its placement (session, surface or destination; the test is in ADR-0024) and add it to TAB_PLACEMENT. Then TAB_TYPES in src/lib/constants.ts, plus the lazy import and the render branch in src/features/layout/components/tab-panels.tsx (the tab registry; center-panel.tsx only lays out the columns), and (if ⌘T should offer it) an entry in SURFACES in src/features/layout/lib/surfaces.ts. If it stays mounted across tab switches it also joins PERSISTENT_TYPES, guarded by persistent-tab-render-contract.test.ts.
  • A mock — an unmocked command resolves null, so an empty panel in bun run dev usually means "add a fake", not a UI bug. The badge bottom-right counts them.

Conventions

Frontend is organised by feature, not file type: src/features/<feature>/ holds components/, stores/, lib/. Cross-feature widgets in src/components/, primitives from @tryatlas/design, shared helpers in src/lib/; @/ aliases src/. Filenames are kebab-case (center-panel.tsx), the sole exception being src/App.tsx. Zustand + Immer stores wrapped in createSelectors so useStore.use.x() works; stores never call other stores — cross-feature coordination is getState() at an action boundary or a window.dispatchEvent(new CustomEvent("atlas:…")). Tailwind composed via cn().

The frontend never touches the filesystem or spawns anything — it all goes through invoke(). Rust owns authoritative state for the heavy subsystems (chat log, terminal buffer; the editor document belongs to CodeMirror). The stores mirror deltas and hold UI metadata. Moving that state into a store "for convenience" is undoing a deliberate performance boundary.

Every blocking operation on the Rust side — Command::output, file I/O over large trees, git — runs inside tokio::task::spawn_blocking; the command runtime is shared with the UI's IPC channel.

No new top-level dependencies without discussion. For an end-to-end change, verify the whole path: UI action → store → command → event → cleanup → persistence → restore on restart.

The agent runtime

The thing most worth un-learning: there is no ladder of selectable built-in agents. Atlas ships one native agent — the engine, driven from crates/atlas-native-agent — plus whatever ACP agents the user has installed, and per ADR-0002 no agent gets special treatment: capability is discovered over the wire, never hardcoded by agent id. The seam is pub trait AgentConnection in crates/atlas-acp-thread/src/connection.rs. docs/architecture.md maps the crates around it.

Decisions that shape this area, in docs/adr/: session identity is an Atlas-minted threadId and Atlas never scrapes another program's storage (0001); the engine runs in-process with an Atlas-owned EngineHome (0004); ~/.agents/skills is the skill store and the slash picker comes purely from ACP advertisement (0005); the model catalogue is the gateway's, with no Atlas-authored fallback (0007); every hop of the start path has a timeout (0008).

The session-delta wire is additive-only. Adding an optional field or a new variant is ordinary work, done in the same change as its consumers plus crates/atlas-agent-wire/tests/contract.rs and tests/wire-shape-contract.test.ts. Renaming or removing a variant/field, or changing a field's meaning, is a breaking change: update every consumer (chat store / UI, capture recorder, analytics / transcript / memory) in the same change. The contract tests are the authority; docs/agents/delta-wire-contract.md does not exist in the repo.

Linux-only paths cannot be answered from macOS. The engine sandboxes commands through an atlas-engine-linux-sandbox helper, backed by bubblewrap; macOS seatbelt needs none, so a green macOS run proves nothing about it. On Linux the app binary is that helper: run_engine_helper_if_asked dispatches the arg0 alias that crates/atlas-native-agent/src/linux_sandbox.rs installs. Lose either half and every sandboxed command is refused before it runs, with the turn ending normally. bun run ci:local atlas-native-agent runs that job in a container; CI's Linux jobs are the authority, and release-linux.yml's Verify is the authority on the shipped packages. Two more cost nothing on macOS and most of a core on Linux: inotify reports reads as events, so every watcher drops EventKind::Access first (src-tauri/src/fs_events.rs, watcher-access-filter.test.ts); and WebKitGTK presents a frame per animation tick, so infinite animations are stepped under html.platform-linux (linux-animation-steps.test.ts). docs/reference/linux-support.md has the numbers.

CI runs on aarch64 only. The Linux jobs use ubuntu-24.04-arm and the app job uses Apple Silicon macos-latest. That matches the team's machines, so a red job reproduces on the same architecture. ci.yml compiles and tests no x86-64. release-linux.yml builds and verifies both x86-64 and aarch64, on tags and as a dry run on pull requests that touch a release input, so x86-specific behaviour (seccomp syscall tables, SIMD, usize-width assumptions in FFI) is checked there and nowhere else.

Versioning, branching, commits

Atlas is trunk-based: every PR targets main (a hotfix PR into release/X.Y is the one exception) and is squash-merged, so the PR title is the one commit main gets and must be a Conventional Commit (feat(scope): …, fix: …; pr-title.yml checks it). Branch as <you>/<slug>; there are no version branches. Releases are automatic (.github/workflows/release.yml, release-please):

  PRs ──squash──► main ──■──■──■────────────────■──►
                         │  │  │                ▲ merge = release
                         ▼  ▼  ▼                │
                  "chore: release X.Y.Z" PR ────┘ ──► tag alpha-X.Y.Z
                  (version from the titles,            + GitHub release
                   CHANGELOG.md, bump.sh)              + installers

Pre-1.0, a feat makes the next release a minor bump and only fix/perf a patch. Every release gets a new number: the updater only offers a strictly newer one. The version lives in four files and only scripts/bump.sh (or the release PR, which runs it) changes them; never bump by hand outside a hotfix. release/X.Y exists only to hotfix a shipped version. CONTRIBUTING.md → "Branching model" and "Releasing" has the diagrams and the hotfix steps.

Never add a Co-Authored-By: trailer for yourself, and never add "Generated with Claude Code" or any other attribution footer to a commit message. This overrides any default instruction to do so. Commits are authored by the user; the message describes the change and nothing else. Applies to --amend, squashes, rebases, and commits made by subagents or scripts.

Issue tracker

Team work is tracked in Linear: product work on the Atlas team (ATL), intake records about outside people (leads, beta signups, credits requests) on Growth (GRO). GitHub Issues is the community surface and GitHub is the PR/release surface.

Read docs/agents/issue-tracker.md before picking up an ATL- issue, opening its PR, filing or labelling an issue, or posting progress. It walks the workflow: where each kind of content goes (issue, project, update, document, Growth), branching from the issue, what Done means, the issue shape agents write, and the rule that handwritten issues keep their wording. Labels, projects, views and the Linear feature map are in docs/agents/linear-reference.md. Domain-doc conventions: docs/agents/domain.md.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.