Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
da49c88
docs: ADR-0003 + Codex-port spec (gateway revision) + research
Ukaykhingmarma28 Aug 27, 2026
291e0a4
docs: port spec, research, and gateway reference (un-ignore shipped d…
Ukaykhingmarma28 Aug 27, 2026
acbe75b
#38: adopt the root cargo workspace
Ukaykhingmarma28 Aug 27, 2026
330c453
#39: unify rusqlite and tree-sitter with the engine's pins
Ukaykhingmarma28 Aug 27, 2026
34d5498
#40: record the Phase 0 verification findings in the spec
Ukaykhingmarma28 Aug 27, 2026
25d4003
#41: correct D14's premise — the Atlas account surface already exists
Ukaykhingmarma28 Aug 27, 2026
67fb707
#42: vendor the Codex engine closure, quarantined
Ukaykhingmarma28 Aug 27, 2026
988a9a3
#41: reconcile D14 against the gateway doc, ratify the storage exception
Ukaykhingmarma28 Aug 27, 2026
0f16c4c
#43: rip the phone-home paths out of the vendored engine
Ukaykhingmarma28 Aug 27, 2026
a48547e
#44: put the Apache-2.0 obligations in force
Ukaykhingmarma28 Aug 27, 2026
340fc59
#45: ADR-0004 and the open-question-3 trace
Ukaykhingmarma28 Aug 27, 2026
c5823a7
#45: link the engine behind the switch, with config assembly and the …
Ukaykhingmarma28 Aug 28, 2026
a630f48
#45: rewire the seam over the in-process app-server client
Ukaykhingmarma28 Aug 28, 2026
adb8d30
#46: cancel, retry, and stop reasons at the seam
Ukaykhingmarma28 Aug 28, 2026
f9e3f0c
#47: permission modes and the effort knob, against the engine
Ukaykhingmarma28 Aug 28, 2026
693da6a
#47: share one request-id counter across a connection's controls
Ukaykhingmarma28 Aug 28, 2026
aef4614
#47: tool approvals round-trip through the existing dialog
Ukaykhingmarma28 Aug 28, 2026
0a38f8d
#46: cancel kills the running command, and a retry does not re-run it
Ukaykhingmarma28 Aug 28, 2026
a237fbd
#48: search_memory on the ported engine; the dead Cersei call sites go
Ukaykhingmarma28 Aug 28, 2026
ed26581
#49: history continuity across the engine swap, and the answer that w…
Ukaykhingmarma28 Aug 28, 2026
c04539b
#50: the D13 error-classification arm for the Atlas gateway
Ukaykhingmarma28 Aug 28, 2026
7db3bdf
#50: the gateway Chat Completions dialect, and the retry the D13 arm …
Ukaykhingmarma28 Aug 28, 2026
8cc8f2a
#50: wire the dialect into the engine, and give the D13 arm a caller
Ukaykhingmarma28 Aug 28, 2026
224b5b5
#50: the static catalogue, and four things the review caught
Ukaykhingmarma28 Aug 28, 2026
34ac769
#51: the native agent authenticates with the user's Atlas account
Ukaykhingmarma28 Aug 28, 2026
9a10209
#52: the three gateway UX policies (D15)
Ukaykhingmarma28 Aug 28, 2026
61277ab
#54: unwire the Cersei path — the ported engine is the native agent
Ukaykhingmarma28 Aug 28, 2026
f6ffabc
#55: rename to Atlas Agent, and the trademark scrub the licence requires
Ukaykhingmarma28 Aug 28, 2026
16a4297
#54: remove the unwired Cersei path from disk
Ukaykhingmarma28 Aug 28, 2026
1f82a35
#54: drop the deleted crate from the CI matrix
Ukaykhingmarma28 Aug 28, 2026
194a0d5
Atlas Agent tells the app what it can do
Ukaykhingmarma28 Aug 28, 2026
614795c
The frontend stops treating the native agent as the BYOK agent it no …
Ukaykhingmarma28 Aug 28, 2026
11d48ea
The registrations #54 silently disabled, and the lint that makes it i…
Ukaykhingmarma28 Aug 28, 2026
2175528
Every gateway request names the org that pays for it
Ukaykhingmarma28 Aug 28, 2026
71fb02f
The registrations must not touch AuthState before Tauri manages it
Ukaykhingmarma28 Aug 28, 2026
1675da6
The slash commands survive a resume, the picked model reaches the tur…
Ukaykhingmarma28 Aug 28, 2026
02a5d6a
A reopened native-agent session shows its whole conversation, and the…
Ukaykhingmarma28 Aug 29, 2026
b992a18
A reopened session replays its whole conversation, under its own id
Ukaykhingmarma28 Aug 29, 2026
91ced74
Streamed replies apply in bursts, not per token
Ukaykhingmarma28 Aug 29, 2026
630a935
/undo, /goal, /review, skills, /fork and /queue — the command set gro…
Ukaykhingmarma28 Aug 29, 2026
939e31b
The stop button must never take the app down, and /compact must be se…
Ukaykhingmarma28 Aug 29, 2026
733cda0
The engine's tool calls reach the thread — and with them, Artifacts c…
Ukaykhingmarma28 Aug 29, 2026
24ee88d
Merge upstream/0.3.1 into the Codex-port branch
Ukaykhingmarma28 Aug 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
The diff you're trying to view is too large. We only load the first 3000 changed files.
22 changes: 15 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,11 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
# One cargo workspace since #38: the lockfile and the target dir both
# live at the repo root, so that is what the cache keys off.
- uses: Swatinem/rust-cache@v2
with:
workspaces: src-tauri
workspaces: .
- name: Configure git identity for test repos
run: |
git config --global user.name "CI"
Expand All @@ -87,10 +89,14 @@ jobs:
run: cargo test

crates:
# Every crate is a standalone package with its own Cargo.lock, so each gets
# its own job and its own cache. Adding a crate here is a one-line change,
# and `tests/ci-coverage.test.ts` fails the build if a new crate is left
# out of this list.
# Every crate gets its own job so a failure names the crate rather than the
# workspace. Adding a crate here is a one-line change, and
# `tests/ci-coverage.test.ts` fails the build if a new crate is left out of
# this list.
#
# Since #38 all of these except `atlas-kb-server` are members of the root
# workspace: `cargo test` inside a member directory still selects only that
# package, but the lockfile and target dir are the root's.
#
# `clippy: true` marks the crates that are currently warning-clean under
# `-D warnings`. The rest are not yet; flip the flag as each is cleaned up
Expand All @@ -117,7 +123,6 @@ jobs:
- crate: atlas-agent-wire
clippy: true
- crate: atlas-bus
- crate: atlas-cersei
- crate: atlas-checkpoint
clippy: true
- crate: atlas-codeindex
Expand All @@ -138,9 +143,12 @@ jobs:
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy
# Workspace members share the root lockfile and target dir;
# `atlas-kb-server` is excluded from the workspace (it keeps its own
# profile and is built on demand at runtime) and so keeps its own cache.
- uses: Swatinem/rust-cache@v2
with:
workspaces: crates/${{ matrix.crate }}
workspaces: ${{ matrix.crate == 'atlas-kb-server' && 'crates/atlas-kb-server' || '.' }}
# Several suites build real git repositories in a tempdir, and `git
# commit` refuses to run without an identity. Set for every crate so
# adding such a test to another crate doesn't fail mysteriously.
Expand Down
16 changes: 13 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@ Thumbs.db
.env
.env.local

# Tauri
src-tauri/target/

.claude/
.atlas/
.agents/
Expand All @@ -41,6 +38,9 @@ skills-lock.json
!CODE_OF_CONDUCT.md
!CONTEXT.md
!docs/adr/*.md
!docs/atlas-agent-codex-port-spec.md
!docs/research/*.md
!docs/reference/*.md
graphify-out/
# Local-only working folders (plans/specs + helper scripts)
plans/
Expand All @@ -49,3 +49,13 @@ scripts/release-macos.sh

# Stakpak session files
.stakpak/session*

# The vendored Codex engine is committed verbatim (#42). Without this, the
# broad `*.md` rule above silently drops the engine's baked system prompts
# (`core/*_prompt.md`), its guardian policy templates and its skill samples —
# 35 paths, most of them `include_str!`d at compile time. The tree would build
# from a working copy and fail from a fresh clone, which is the worst shape a
# vendoring bug can take.
!vendor/codex/**
# ...except build output, if anyone ever builds in-tree there.
vendor/codex/**/target/
4 changes: 2 additions & 2 deletions .lintstagedrc.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"*.{js,jsx,mjs,cjs,ts,tsx,mts,cts}": ["oxfmt --write", "oxlint"],
"*.{json,css}": "oxfmt --write"
"{src,tests,scripts}/**/*.{js,jsx,mjs,cjs,ts,tsx,mts,cts}": ["oxfmt --write", "oxlint"],
"{src,tests,scripts}/**/*.{json,css}": "oxfmt --write"
}
6 changes: 3 additions & 3 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ Deltas return over the single `atlas:agents` channel, payload-typed by `kind`.

## Crates (`crates/`)

All wired in as `path` dependencies from `src-tauri/Cargo.toml`. **There is no `[workspace]`** the ported stack pins `agent-client-protocol` 2.0 with its schema crate pinned exactly, and no single Cargo resolution could hold that alongside the old stack's exact `=1.4.0` pin. That collision is why the port had to land as one change rather than gradually, and why the repo still resolves each crate on its own.
All wired in as `path` dependencies from `src-tauri/Cargo.toml`, and all members of the **root `[workspace]`** bar one (`atlas-kb-server`, below). The repo went without one for a long time, for a real reason: the ported stack pins `agent-client-protocol` 2.0 with its schema crate pinned exactly, and no single Cargo resolution could hold that alongside the old stack's exact `=1.4.0` pin. That collision is why the port had to land as one change rather than gradually. With the old stack gone the collision is gone, and the workspace landed (issue #38) so the vendored Codex engine resolves against the same graph as the app. Consequences worth knowing: one `Cargo.lock` and one `target/` at the repo root, and `[patch.crates-io]` plus every `[profile.*]` live in the root `Cargo.toml` — cargo honors both only there. `crates/atlas-kb-server` is deliberately excluded (it is built on demand at runtime under its own profile).

### The ported ACP stack

Expand Down Expand Up @@ -297,9 +297,9 @@ atlas/
│ ├── bin/, resources/ bundled helper scripts (atlas-cli.sh, nvm.sh)
│ ├── build.rs build script
│ ├── tauri.conf.json bundle config, CSP, window
│ └── Cargo.toml path deps + [patch.crates-io] + release profile
│ └── Cargo.toml path deps (patches + profiles live at the root)
├── crates/ Rust crates (path deps; no [workspace])
├── crates/ Rust crates (workspace members)
│ ├── atlas-acp-thread session model + the AgentConnection seam
│ ├── atlas-agent-servers external ACP transport + launcher + host env
│ ├── atlas-agent-store where an agent comes from (Marketplace)
Expand Down
73 changes: 71 additions & 2 deletions CONTEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,77 @@ Glossary of domain terms as this project uses them. Decisions with lasting conse

## Adjacent subsystems

- **Cersei** — Atlas's native agent. Its threads live in the same thread-metadata store as external agents', distinguished only by agent id.
- **Atlas Agent** — the native agent: the single first-party agent that ships with Atlas rather than being installed from the Marketplace. Its engine is a one-time port of Codex that lives in this repo and is maintained by us (ADR-0003). Exactly one native agent exists at a time; every other agent is an ACP agent. "Native agent" and "Atlas Agent" are synonyms from cutover onward. Its threads live in the same thread-metadata store as external agents', distinguished only by agent id — and that stored agent id remains the literal string `"cersei"`: it is a **storage key**, not a name. Every recorded thread resolves through it, so it was deliberately kept stable across the engine swap and outlived the retirement of the name it came from. Changing it is a data migration, not a rename.
- **Timeline / checkpoint** — the per-workspace observational record (`atlas-checkpoint`). Separate from the thread-metadata store; its importer may read CLIs' transcript files under its own contract, which the history model explicitly preserves.
- **Marketplace / registry** — where agents are installed from; the installed-agents map is what import enumerates.
- **Installed-agents map** — the one record of which ACP agents exist. Installing writes an entry, uninstalling removes it, and nothing else makes an agent runnable. A fresh install has an empty map and offers only Cersei. See ADR-0002.
- **Installed-agents map** — the one record of which ACP agents exist. Installing writes an entry, uninstalling removes it, and nothing else makes an agent runnable. A fresh install has an empty map and offers only the native agent. See ADR-0002.
- **Detection** — an agent found on the user's `PATH` that Atlas has *not* installed. An offer, never a spawn candidate: **accepting a detection** is a user action that writes an installed-agents-map entry pointing at their own binary, downloading nothing. Finding a binary installs nothing by itself.

## Talking to a model (Atlas Agent)

- **Atlas gateway** — Atlas's own LLM broker (`docs/reference/atlas-ai-api.md`), an
OpenAI-Chat-Completions-compatible front door to Google Vertex. It is the *only* provider the
native agent talks to: it holds the provider credentials, meters usage, and enforces the spend
cap, so no provider key is ever on the device. Not to be confused with **BYOK**, which is a
user's own key for a *non-native* agent and is untouched by any of this.
- **Wire dialect** — the request-and-response grammar a provider speaks. The engine was forked
speaking exactly one, the **Responses** dialect; the port authors a second, **Chat Completions**
against the gateway contract (`codex_api::atlas_chat`, spec D3). The two share the engine's
internal item and event vocabulary and nothing below it — different route, different body,
different stream grammar, different error table. A green suite on one says nothing about the
other.
- **Spend cap** — the ceiling on what an account may spend, denominated in weighted tokens and
reserved *before* the provider is called. A filled cap answers `402`, deliberately not `429`,
because stock SDKs auto-retry `429` and a monthly ceiling cannot clear for weeks.
- **Disposition** — what the client should do about a gateway error, as decided from its status
and `error.code` (`codex_api::atlas_gateway`, spec D13): stop, wait a stated interval, refresh
the credential and try once, or retry cautiously. Deliberately not a boolean — "retryable"
collapses three behaviours the gateway keeps apart.

## Vendored engine licensing (Apache-2.0)

`vendor/codex/` is a hard fork of OpenAI Codex under **Apache-2.0** (ADR-0003). Atlas's own
code is **MIT** (`LICENSE`). The two do not merge: Apache-2.0 code stays Apache-2.0 however it
is bundled, so its obligations travel with every build rather than being absorbed by Atlas's
licence. `tests/vendor-licensing.test.ts` enforces what follows; **D11 blocks all rename work
until it is green**, because doing the attribution first makes every later rename commit
trivially compliant.

- **Ship the licence and the notice (§4(a), §4(d)).** `vendor/codex/LICENSE` and
`vendor/codex/NOTICE` are bundled into the app at `Contents/Resources/licenses/`, alongside
Atlas's own. The obligation runs to *recipients*, so a file that only exists in the repo does
not discharge it. The NOTICE keeps its Ratatui lines even though the TUI is dropped — §4(d)
would permit removing them, simplicity favours leaving them — and travels **verbatim**,
including the U+00A0 non-breaking spaces upstream put in it.

- **Mark what you changed (§4(b)).** Every vendored file Atlas modifies carries this line, first
line of the file, before any module docs:

```
// Modified by Atlas from upstream OpenAI Codex (Apache-2.0). See CONTEXT.md.
```

`<!-- … -->` in Markdown; a root `"$comment"` in JSON. Add it in the same commit as the edit —
the test computes the modified set from git, so it notices on the next run either way.
*(Caveat: `core/config.schema.json` is generated by schemars, and regenerating it drops the
`$comment`. Re-add it if that ever happens.)*

- **Never strip attribution (§4(c)).** Copyright and attribution notices inside vendored sources
are **not** touched by rename sweeps. The rule is: rename product branding, keep attribution.
The Phase 5 sweep is exactly the operation that would violate this, which is why the rule is
written down before that sweep runs.

- **Trademarks are a removal, not a preference (§6).** Apache-2.0 grants no trademark licence, so
the rebrand *must* drop "Codex" and "OpenAI" as product-facing names — including the baked
system prompt and the catalog `instructions_template` strings that self-identify as Codex.
Required by the licence, not merely by taste. **Done (#55).** Two prompts reach a shipped
turn — `models-manager/prompt.md` and `protocol/src/prompts/base_instructions/default.md` —
and both now say Atlas Agent. Their §4(b) notices are HTML comments on line 1, **stripped when
the file is read**: the notice must be in the file, and must not be in the model'''s context.
The model-specific GPT-5 prompts under `core/` are left untouched: Atlas'''s catalogue serves
no GPT-5 row, so they reach no user-facing surface, and §4(c) says leave what you do not need
to change.

- **Atlas may claim its own modifications (§4).** Permitted, and it is not the same act as
stripping upstream's — an added Atlas copyright line sits beside upstream's, never replacing
it.
27 changes: 18 additions & 9 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,21 +161,30 @@ bun run lint # oxlint on src/
bun run format:check # oxfmt --check on src/
bun run typecheck # frontend typecheck (app + test code)
bun run test # frontend and cross-cutting tests
bun run test:rust # every standalone Rust crate + src-tauri --lib
cd src-tauri && cargo check # Rust typecheck, including every crates/* dependency
bun run test:rust # every Rust crate + src-tauri --lib
cargo check --workspace # Rust typecheck: every workspace member + the app
```

Rust tests run offline and need no API keys. Each crate under `crates/` is its own standalone package (its own `Cargo.lock`, not a workspace member of `src-tauri`), so tests run from inside the crate's own directory — not with `-p <crate>` from `src-tauri`:
Rust tests run offline and need no API keys. Every crate under `crates/` except
`atlas-kb-server` (see below) is a member of the root cargo workspace, sharing
one `Cargo.lock` and one `target/` at the repo root, so `-p <crate>` works from
anywhere — as does running from inside the crate's own directory, which is what
CI does:

```bash
cd crates/atlas-cersei && cargo test # the native agent
cd crates/atlas-cersei && cargo test --test tools_eval # a single file
cd crates/atlas-acp && cargo run --example smoke # ACP transport smoke test
cargo test -p atlas-cersei # the native agent
cargo test -p atlas-cersei --test tools_eval # a single file
cd crates/atlas-cersei && cargo test # same thing, from the crate
```

Run `cargo test` from inside the directory of any crate you touched.
Run `bun run test:rust` from the repository root to test every standalone crate
and the Tauri library in one pass; it stops at the first failure.
Run `bun run test:rust` from the repository root to test every crate and the
Tauri library in one pass; it stops at the first failure.

The exception, `crates/atlas-kb-server`, is a template binary the
knowledge-export command compiles on demand at runtime under its own release
profile. Profiles are workspace-global, so joining the workspace would rebuild
it under the app's — hence it stays out, keeps its own `Cargo.lock`, and is
built with `--manifest-path`.

Frontend tests run under Vitest:

Expand Down
Loading
Loading