Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
bin/
graphify-out/
dist/
Tui-design-ins/
248 changes: 184 additions & 64 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,91 +1,211 @@
# atlas-cli

A headless Atlas for servers: a Go binary that signs in like the Atlas desktop
app, binds a folder to an organisation and a cloud Project, and gives every
coding agent run in that folder **session capture** and **shared memory**,
byte-compatible with the desktop's on-disk formats. The agents keep their own
UIs: Atlas plugs into their hooks (ADR-0013).
<p align="center">
<img src="docs/assets/banner.png" alt="atlas: shared memory and session capture for coding agents" width="100%">
</p>

<h1 align="center">atlas</h1>

<p align="center">
<b>Shared memory and session capture for coding agents, from the terminal.</b><br>
Claude Code, Codex, Cursor, Copilot, OpenCode, Droid, Antigravity and Pi keep their own UIs;<br>
Atlas records every session and gives every agent the same memory of the project.
</p>

<p align="center">
<a href="https://github.com/tryatlas/atlas-cli/releases/latest"><img src="https://img.shields.io/github/v/release/tryatlas/atlas-cli?color=000000&labelColor=000000&style=flat-square" alt="Latest release"></a>
<img src="https://img.shields.io/badge/go-pure%2C%20no%20cgo-000000?labelColor=000000&style=flat-square" alt="Pure Go">
<img src="https://img.shields.io/badge/macOS%20·%20Linux-000000?labelColor=000000&style=flat-square" alt="macOS and Linux">
<a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache--2.0-000000?labelColor=000000&style=flat-square" alt="Apache-2.0"></a>
</p>

<p align="center">
<a href="#install">Install</a> ·
<a href="#quick-start">Quick start</a> ·
<a href="#shared-memory">Shared memory</a> ·
<a href="#session-capture">Session capture</a> ·
<a href="#agents">Agents</a> ·
<a href="#commands">Commands</a>
</p>

---

`atlas` is the headless Atlas: one Go binary that signs in like the Atlas
desktop app, binds a folder to an organisation and a cloud Project, and plugs
into the hooks of the agents you already use. It writes the same files the app
writes, byte for byte, so a folder works the same whether it is open in the app,
in a terminal on a server, or both.

## Install

Linux (amd64, arm64) and macOS (Apple silicon, Intel):
macOS (Apple silicon, Intel) and Linux (amd64, arm64):

```sh
curl -fsSL https://github.com/tryatlas/atlas-cli/releases/latest/download/install.sh | sh
```

It verifies the archive's sha256 and installs `atlas` to `~/.local/bin`
(`ATLAS_INSTALL_DIR` to change it, `ATLAS_VERSION=v1.2.3` to pin). From
source: `make build` (pure Go, no cgo).
The installer verifies the archive's sha256 and puts `atlas` in `~/.local/bin`
(`ATLAS_INSTALL_DIR` changes it, `ATLAS_VERSION=v0.4.0` pins it). Later,
`atlas update` does the same in place. From source: `make build` (pure Go, no
cgo).

## Use
## Quick start

```
atlas login # device grant against the Atlas auth server
```sh
atlas login # sign in (the same account as the desktop app)
cd ~/work/backend
atlas init # org + cloud Project, writes .atlas/ (--local: no cloud)
atlas agents add claude-code # the agents you use here (atlas agents list shows all eight)
atlas agents add codex cursor
claude # …or codex, cursor-agent, opencode: work as usual
atlas status # sessions captured, commits linked, sync
atlas init # organisation → Project → agents → background sync
claude # …or codex, cursor-agent, opencode, copilot: work as usual
atlas status # what was captured, what synced, what agents remember
```

`atlas agents add` writes two things into the agent's own config in the
Project: its **hook**, which runs `atlas hooks <agent> <event>` at session
start, each prompt, each turn end and session end; and the **`atlas_memory`
MCP server**, so the agent can read and write shared memory. It also installs a
git `post-commit` hook that links sessions to the commits that carry their
work. Nothing is wrapped and no environment variable changes; remove it all with
`atlas agents remove <agent>`.

Agents run their project hooks only for a project you trust: Codex, Copilot
and Pi each ask once in their own UI. Keep `atlas` current on PATH, including
`~/.local/bin`, which some agents put first.

At each turn end the hook reads the agent's transcript from where the turn
started, diffs `git status`, and records the prompt, the reply, the tool calls
with the files they wrote, token usage and the model. The hook writes to the
store itself, or hands the turn to a running `atlas serve`, or spools it when
the desktop app has the folder open. A hook never fails the agent: errors go to
`.atlas/cli-hooks.log` and `atlas status`.
`atlas init` is a guided flow on a terminal:

| step | asks |
|---|---|
| 1 · Organisation | which organisation the folder belongs to (skipped when you have one) |
| 2 · Project | the cloud Project: the one matching this repository first, the others, or a new one |
| 3 · Agents | which agents found on this machine to hook, with an **All agents** row |
| 4 · Background sync | keep a listener running so every event reaches the cloud at once |
| 5 · Memory search | download the local search model (87 MB, once) when it is missing |

`--local` binds without a cloud. In scripts, flags answer instead: `--org`,
`--project | --create`, `--agents claude-code,codex | --all-agents`,
`--sync on|off`.

`atlas settings` changes any of it later on one screen: account, capture and
memory, each agent, background sync, the local model, updates.

## Shared memory

Every agent in the project reads and writes one memory, through the
`atlas_memory` MCP server that `atlas agents add` registers in the agent's own
config. Nothing is ever injected into a prompt: agents pull what they need.

| tool | what an agent gets |
|---|---|
| `memory_briefing` | at session start: the active **plan**, recent file changes, decisions, facts, failures, architecture, conventions, and the previous session's handoff |
| `memory_search` | memories ranked by **meaning and words**, plus the project's **documents** (CLAUDE.md, AGENTS.md, notes, captured sessions) |
| `memory_remember` | save a decision, fact, failure, architecture note or preference; near-duplicates merge |
| `memory_changes` | what other sessions recorded since this one last looked |
| `memory_get` · `memory_history` · `memory_why` | one memory, its earlier wordings, and the sessions behind a file or commit |
| `memory_forget` · `memory_feedback` · `memory_list` | remove, rate and list |

- **Search by meaning.** A small local model (MiniLM, the one the app uses) runs
in pure Go on your machine; nothing is sent anywhere. Ask "how do we rotate
tokens" and find "signing keys rotate every week". Without the model, search
falls back to words.
- **Plans are captured, not typed.** When an agent writes its to-do list
(`TodoWrite`, `update_plan`, `todowrite`, Claude's tasks and plan mode, …),
it becomes the project's plan, and the next session, or another agent, sees
it in its briefing.
- **Memories write themselves.** Decisions an agent states in its reply, and
what the extractor distils from long sessions, land as memories; at session
end a handoff note tells the next session where things stand.
- **One record with the app.** `.atlas/memory/` holds the app's exact files:
`memory.sqlite` (with its vectors), `corpus.sqlite`, `memory.snapshot.sqlite`
(a daily backup, restored automatically if the record is damaged) and
`extract-state/`.

```sh
atlas memory browse # entries by kind, search, history
atlas memory index # embed every memory, index the project's documents
```

## Session capture

Capture happens per event, as the agent works:

1. **The prompt** opens the turn the moment you submit it.
2. **Each tool call** lands as the agent's post-tool hook fires, with the files it
wrote, including files a shell command changed.
3. **The reply** closes the turn at the agent's stop hook, with token usage and
the model, read from the transcript the agent names.
4. **Commits** an agent makes get their checkpoint: a git `post-commit` hook
links each commit to the session and turn that wrote it.

Every event reaches the cloud Project within seconds: the hook writes the store
and syncs, or hands the event to `atlas serve`, or spools it while the desktop
app has the folder open. A hook never fails the agent; problems go to
`atlas status`.

```sh
atlas sync on # a background listener your agents' hooks keep alive
atlas serve # the same in the foreground, with a live feed of hook events
```

## Agents

`atlas agents add <agent>` writes the hook and the memory server into the
agent's own config in the project; `atlas agents remove` takes them out.
Nothing is wrapped and no environment variable changes.

| agent | hook written to | memory server written to |
|---|---|---|
| `claude-code` Claude Code | `.claude/settings.local.json` | `.mcp.json` (+ approved in the local settings) |
| `codex` Codex | `.codex/hooks.json`: the first interactive `codex` here asks "Hooks need review"; choose **Trust all and continue** (`codex exec` cannot ask) | `.codex/config.toml` (trusted projects) |
| `cursor` Cursor CLI and IDE | `.cursor/hooks.json` (`cursor-agent -p` fires no turn hooks; such a session is captured at its end) | `.cursor/mcp.json` (Cursor asks to approve it once) |
| `copilot` GitHub Copilot CLI | `.github/hooks/atlas.json`: loaded once the folder is trusted (the first interactive `copilot` asks; `copilot -p` does not) | `.github/mcp.json` (same trust) |
| `claude-code` Claude Code | `.claude/settings.local.json` | `.mcp.json`, approved in the local settings |
| `codex` Codex | `.codex/hooks.json`: choose **Trust all and continue** once | `.codex/config.toml` |
| `cursor` Cursor CLI and IDE | `.cursor/hooks.json` | `.cursor/mcp.json`, approved once in Cursor |
| `copilot` GitHub Copilot CLI | `.github/hooks/atlas.json`, once the folder is trusted | `.github/mcp.json` |
| `opencode` OpenCode | `.opencode/plugins/atlas.ts` | `opencode.json` |
| `droid` Factory Droid | `.factory/settings.json` | `.factory/mcp.json` |
| `antigravity` Antigravity (`agy`) | `.agents/hooks.json` (run `agy` with an absolute `--add-dir`) | `.agents/mcp_config.json` |
| `pi` Pi | `.pi/extensions/atlas/index.ts`: loaded once the project is trusted in Pi (`pi --approve` for one run) | `.pi/mcp.json` (same trust) |
| `antigravity` Antigravity (`agy`) | `.agents/hooks.json` | `.agents/mcp_config.json` |
| `pi` Pi | `.pi/extensions/atlas/index.ts`, once the project is trusted | `.pi/mcp.json` |

Keep `atlas` current on `PATH`, including `~/.local/bin`, which some agents put
first.

## Commands

Every command draws its own screen on a terminal (the Atlas palette: monochrome,
colour only for status) and prints plain text to pipes and scripts.

| command | what |
|---|---|
| `atlas agents add \| remove \| list \| sessions` | install or remove the hook and memory entry per agent; list agents and the sessions seen |
| `atlas serve [--daemon \| --stop]` | the Project's listener: memory server, sync drain, receiver of hook turns while it holds the store |
| `atlas status` | sign-in, Project, gates, capture health, commits linked, sync, memory, agents and hook errors |
| `atlas memory browse \| list \| verify \| export \| import` | shared memory (this machine only) |
| `atlas capture sync \| retry \| link` | cloud sync now, retry failed rows, link sessions to commits by hand |
| `atlas mcp-bridge --project <dir> --agent <id>` | the stdio MCP entry the agents' configs hold (serves memory with or without `atlas serve`) |
| `atlas` | the overview: logo, commands by group |
| `atlas login` · `logout` · `whoami` | sign in with the device grant; the session file is the only secret kept (mode 0600) |
| `atlas org list \| use \| create` | organisations |
| `atlas init` | bind the folder, hook the agents, choose background sync and memory search |
| `atlas settings` | everything on one screen |
| `atlas status` | sign-in, Project, capture health, commits linked, sync, memory, agents |
| `atlas agents add \| remove \| list \| sessions` | the hooks and memory entry per agent; the sessions seen |
| `atlas sync [on \| off]` | background sync |
| `atlas serve` | the Project's listener: memory server, sync drain, receiver of hook events |
| `atlas memory browse \| list \| index \| verify \| export \| import` | shared memory |
| `atlas memory enable \| disable` | the shared-memory gate for this repository |
| `atlas capture enable \| disable \| sync \| retry \| link` | the capture gate; sync now, retry failed rows, link commits |
| `atlas update [--check] [--version vX.Y.Z]` | replace this binary with a release, checksum verified |

## What lives where

| path | what |
|---|---|
| `.atlas/` | the app's per-project files only: `sessions.db`, `blobs/`, `memory/`, `project.json` |
| `~/.local/state/atlas-cli/projects/<hash>/` | the CLI's own: hook state, `hooks.log`, the listener's run file, preferences |
| `~/Library/Application Support/dev.atlas.ide/models/` | the local search model, shared with the app (`~/.local/share/…` on Linux) |

The ACP path of v0.1 (`atlas run <agent>` with Atlas's own chat screen, the
registry installs) is parked under the hidden `atlas acp` group (ADR-0013 §8).
## Development

## Where things are
```sh
make build # ./bin/atlas
make test # go test ./...
make lint # golangci-lint
```

| path | what |
| doc | what |
|---|---|
| `docs/atlas-reference/README.md` | index of the hand-off folder copied from the desktop repo: read first |
| `docs/atlas-reference/SPEC.md` | the specification; §1.2 holds the locked decisions D1–D20 |
| `docs/atlas-reference/evidence-*.md` | desktop-side facts with `file:line` citations into the desktop repo |
| `docs/research/entire-cli.md` | how the Entire CLI captures agents through hooks; the per-agent facts this CLI's integrations follow |
| `docs/adr/` | this repo's own ADRs; `0013` is the hook-based capture of native agent UIs and supersedes `0009`/`0012` as the product |
| `docs/RELEASE.md` | how to release, and the acceptance checklists |
| `docs/progress.md` | what was built, what was verified live, what was not |
| `docs/adr/` | decisions; `0013` is capture through agents' hooks |
| `docs/research/entire-cli.md` | the per-agent hook facts the integrations follow |
| `docs/atlas-reference/` | the desktop app's specification and file formats |
| `docs/RELEASE.md` | how to release, and the acceptance checklists |

Ground rules: a hook reads only the transcript file the agent's own payload
names, from the turn's offset, while the hook runs, and never scans an agent's
folders; memory is never injected into prompts; an `Authorization` header is
never logged; every stored text passes the redactor; no secret persists except
the session token file.

The ACP path of v0.1 (`atlas run <agent>`) is parked under the hidden
`atlas acp` group.

## License

Ground rules that are not negotiable: a hook reads only the transcript file
the agent's own payload names, from the turn's offset, while the hook runs
(never a scan of an agent's directories); never inject memory into prompts;
never log an `Authorization` header; every stored text passes the redactor
first; and no secret persists except the session token file (mode 0600).
[Apache-2.0](LICENSE)
Loading
Loading