Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
8e544c8
feat(tui): ctrl+n opens a new terminal window running atomic-agent
plombeer31 Aug 19, 2026
1fe88d3
fix(tui): keep the editor live during a turn and queue what you type
plombeer31 Aug 19, 2026
2afd589
feat(llm): more cloud providers and a refreshed model catalog
Aug 19, 2026
ec0316a
feat(config): llm.runMode block — local | cloud | fusion with a fusio…
Aug 19, 2026
42d2909
feat(tui): start page adapts to terminal size
plombeer31 Aug 19, 2026
d67f090
feat(runtime): mid-turn steering — reach the turn that is already run…
plombeer31 Aug 19, 2026
d07be40
fix(tui): reject an empty API key on the provider wizard key screen
plombeer31 Aug 19, 2026
664ddb4
feat(sidecar,http): steering API so hosts can redirect a running turn
plombeer31 Aug 19, 2026
06192c9
Merge branch 'valeryb/tui-type-while-running' into valeryb/tui-steer-…
plombeer31 Aug 19, 2026
2657e7f
fix(tui): point the wizard screen at the shared provider-target helpers
plombeer31 Aug 19, 2026
028e5a7
feat(tui): verify a cloud API key is active and funded before saving it
plombeer31 Aug 19, 2026
8cc31a9
feat(llm): add the cloud credential check module
plombeer31 Aug 19, 2026
5ddb849
feat(models): ranked multi-term model search, in the TUI and the CLI
Aug 19, 2026
3df0e1f
feat(agent): fusion routing — cloud orchestrator, local executor, com…
Aug 19, 2026
7c86277
feat(tui): run the key check from the wizard and first-run onboarding
plombeer31 Aug 19, 2026
966413e
feat(tui): route the wizard cancel through the LLM panel modal too
plombeer31 Aug 19, 2026
3bc6f69
feat(tui): choose whether Enter steers the running turn or queues beh…
plombeer31 Aug 19, 2026
ef5aa75
feat(tui): wire the cancel callback and print an unverified-key notice
plombeer31 Aug 19, 2026
36c0cf1
docs: document the pre-save cloud credential check
plombeer31 Aug 19, 2026
0b2a2b1
docs(serve): list the steer route in --help
plombeer31 Aug 19, 2026
47e4dac
feat(tui): Run submenu — Local · Cloud · Fusion with a fusion share dial
Aug 19, 2026
78a8bc0
feat(tui): mouse support — click the nav bar, panels, selectors and t…
Aug 19, 2026
b6d3eb4
config: parse userModels, promptCache and providerPreferences on llm …
Aug 19, 2026
c571d37
fix(tui): Esc returns to Run from Observe tabs instead of quitting
plombeer31 Aug 19, 2026
6d0fed4
fix(tui): Esc leaves the Import tab instead of being swallowed
plombeer31 Aug 19, 2026
21b77ff
fix(tui): Esc aborts a running turn again
plombeer31 Aug 19, 2026
2eebb34
fix(tui): Esc in the chat editor clears the draft instead of quitting
plombeer31 Aug 19, 2026
e6e77d0
feat(llm): drive a Claude Code subscription through its own CLI (no A…
Aug 19, 2026
3d35833
feat(llm): add the OpenAI Codex subscription to subscription-cli
Aug 19, 2026
46b49cc
refactor(tui): one menu registry — the slash palette becomes a projec…
plombeer31 Aug 19, 2026
ac5e287
feat(tui): ctrl+p operator menu, and ctrl+g chords to jump straight t…
plombeer31 Aug 19, 2026
d4cdc36
merge: PR #150
plombeer31 Aug 19, 2026
f693f28
merge: PR #151
plombeer31 Aug 19, 2026
3c2ec7f
merge: PR #154
plombeer31 Aug 19, 2026
cb5ef42
merge: PR #155
plombeer31 Aug 19, 2026
af5a558
merge: PR #158
plombeer31 Aug 19, 2026
82edf16
merge: PR #159
plombeer31 Aug 19, 2026
7f360c2
merge: PR #160
plombeer31 Aug 19, 2026
1823c35
merge: PR #163
plombeer31 Aug 19, 2026
c2e61a5
merge: PR #164
plombeer31 Aug 19, 2026
60320f2
fix(tui): make the menu a real overlay — it floats, nothing reflows
plombeer31 Aug 19, 2026
97e255c
merge: PR #165
plombeer31 Aug 19, 2026
f13837c
merge: PR #166
plombeer31 Aug 19, 2026
f73d0c5
merge: PR #167
plombeer31 Aug 19, 2026
f50f936
merge: PR #168
plombeer31 Aug 19, 2026
d8952e9
merge: PR #169
plombeer31 Aug 19, 2026
ede6b02
merge: PR #171
plombeer31 Aug 19, 2026
267ed50
test(providers): pick the openrouter row explicitly — row 0 is now a …
plombeer31 Aug 19, 2026
3e6ba4a
atomic-agent: integration release v0.3.0 (PRs #150–#171)
plombeer31 Aug 19, 2026
3229cfd
feat(tui): status bar shows where you are, not a menu of where to go
plombeer31 Aug 19, 2026
38f88c0
integrate: run modes in the ctrl+p menu
plombeer31 Aug 19, 2026
5ab9586
merge: PR #172 (run modes in the ctrl+p menu; menu becomes a real ove…
plombeer31 Aug 19, 2026
ec57872
fix(config): read a newer config version instead of refusing every co…
plombeer31 Aug 19, 2026
c065957
fix(tui): scale one brand mark instead of hand-drawing each size
plombeer31 Aug 19, 2026
4252e97
feat(tui): the menu is a centred modal, and every visible control tak…
plombeer31 Aug 19, 2026
c561a33
test(tui): follow #172's breadcrumb, and fix the two drifted assertio…
plombeer31 Aug 19, 2026
2bdd69e
feat(tui): the left rail becomes the app frame; top bar removed
plombeer31 Aug 19, 2026
bff2786
fix(tui): a narrow terminal keeps its chrome
plombeer31 Aug 19, 2026
4ee7921
fix(config): resolve asset dirs relative to the module, not the cwd
plombeer31 Aug 19, 2026
e05b1e5
merge: asset-dir resolution no longer depends on the working directory
plombeer31 Aug 19, 2026
3336ba4
fix(tui): lay the task table out for the width the panel actually has
plombeer31 Aug 19, 2026
13fdc02
feat(tui): the composer becomes a framed field with Send and file but…
plombeer31 Aug 19, 2026
7128941
merge: framed composer with send and file buttons
plombeer31 Aug 19, 2026
55994ac
fix(tui): budget the whole Tasks table, not just its rows
plombeer31 Aug 19, 2026
70ecf56
fix(tui): the add-provider wizard stops painting over its own rows
plombeer31 Aug 19, 2026
52f1d21
fix(tui): a refused key says so on the screen that refused it
plombeer31 Aug 19, 2026
ad7265b
fix(tui): stop telling an empty task queue to check its filter
plombeer31 Aug 19, 2026
d162cb2
tui: per-message copy button + honest answer to mouse text selection
plombeer31 Aug 19, 2026
d128c9f
merge: copy buttons, clipboard, and a selection escape hatch
plombeer31 Aug 19, 2026
7d18c1f
merge: tasks list fits the panel it is given
plombeer31 Aug 19, 2026
c6a62c1
fix(tui): make Enter in the /run overlay actually apply the mode
plombeer31 Aug 19, 2026
4ba416c
merge: provider wizard fits, key refusal is visible, Enter applies a …
plombeer31 Aug 19, 2026
08ab36f
feat(tui): rail lockup, composer and menu follow the second round of …
plombeer31 Aug 19, 2026
958818f
feat(tui): [try again] re-runs a user message through the Enter path
plombeer31 Aug 19, 2026
cc533bf
feat(tui): a run-mode switch moves the composer's model, or opens the…
plombeer31 Aug 19, 2026
1d77df4
fix(tui): /model arrives focused, and its rows take a click
claude Aug 19, 2026
68b8448
feat(tui): esc on the Run screen opens the operator menu
plombeer31 Aug 19, 2026
2faf90c
merge: round-4 fix (f)
plombeer31 Aug 19, 2026
e8fd9ab
merge: round-4 fix (g)
plombeer31 Aug 19, 2026
84f3acf
merge: round-4 fix (h)
plombeer31 Aug 19, 2026
05e8dd8
merge: round-4 fix (i)
plombeer31 Aug 19, 2026
32e9d37
fix(llm): stop concatenating a streamed tool-call name into itself
plombeer31 Aug 19, 2026
f23e8a6
fix(llm): stop the tool-name de-dup from truncating a real name
Aug 19, 2026
faabd9a
fix(config): actually preserve the top-level keys a newer build wrote
Aug 19, 2026
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
181 changes: 178 additions & 3 deletions AGENTS.md

Large diffs are not rendered by default.

119 changes: 117 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ The installer downloads the release archive, verifies the checksum, and installs
atomic-agent
```

> [!TIP]
> Need a second agent? Press **Ctrl+N** (or run `/window`) inside the TUI — it opens a new terminal window with a fresh atomic-agent in the same directory.

> [!TIP]
> Coming from Hermes or OpenClaw? Run `/import` in the TUI for a one-shot migration: sessions, cron jobs, and optionally your provider keys.

Expand Down Expand Up @@ -194,7 +197,7 @@ Atomic Agent drives a full desktop tool surface. Dangerous actions are routed th
| **Skills** | View and run Markdown skill playbooks (scripts are approval-gated), install more from ClawHub. Ships with 17 starter skills (Docker, GitHub, Notion, Obsidian, PDF, and more), auto-installed on first run. |
| **Vision** | Optional `vision.describe` for multimodal models with `mmproj`, kept outside the text transcript. |
| **MCP** | Connect external MCP servers; their tools, resources, and prompts join the same registry. |
| **Providers** | Local `llama-server` by default; OpenAI-compatible, OpenRouter, and AI/ML API providers when configured, with live model catalogs and mid-session switching. Reasoning-only completions from reasoning models are recovered instead of failing the turn. |
| **Providers** | Local `llama-server` by default; OpenAI-compatible, OpenRouter, AI/ML API, and Gemini providers when configured, with live model catalogs and mid-session switching. Your existing **Claude Code and OpenAI Codex subscriptions** work too, driven through their own signed-in CLIs with no API key. Reasoning-only completions from reasoning models are recovered instead of failing the turn. |
| **Telegram** | Single-user remote control with owner pairing, inline approval buttons, and opt-in result reports from scheduled tasks. |

### Memory That Grows Outside the Prompt
Expand Down Expand Up @@ -226,10 +229,41 @@ atomic-agent task list
atomic-agent trace list --limit 10
```

Handy slash commands: `/help` lists every command, `/tools` lists the built-in tool families, `/model` jumps to the LLM panel and reopens the model picker for the active cloud provider, `/privacy` shows what leaves the machine (`/privacy analytics off` turns analytics off). The chat log scrolls with PgUp / PgDn (fn+arrows on macOS).
Handy slash commands: `/help` lists every command, `/tools` lists the built-in tool families, `/run` switches run mode, `/model` jumps to the LLM panel and reopens the model picker for the active cloud provider, `/privacy` shows what leaves the machine (`/privacy analytics off` turns analytics off). The chat log scrolls with PgUp / PgDn (fn+arrows on macOS).

**Mouse.** The TUI is clickable: the Run / Observe / Manage bar and its sub-tabs, sidebar sessions and tasks, every list row (skills, tasks, memory, MCP, models, providers), the session / theme / slash pickers, approval buttons, tool cards, and the prompt itself — clicking in the input places the caret. A click selects a row, a second click on the selected row opens it, and the wheel scrolls the chat or walks the focused panel.

While mouse reporting is on the terminal hands clicks to the app, which means its own drag-to-select is unavailable (iTerm2, GNOME Terminal and Windows Terminal let you hold Shift to bypass; Apple Terminal does not). Turn it off whenever you want to select text: `/mouse off` in the app, `atomic-agent tui --no-mouse` for one run, or `"tui": { "mouse": false }` in `<stateDir>/config.json`. With mouse off, wheel scrolling still works through the terminal's alternate-scroll mode, exactly as before.

Cloud provider setup pulls each provider's full live model catalog, hundreds of models, instead of a short hardcoded list; OpenAI-compatible servers are asked for their own `/v1/models`. The picker filters as you type, and `/model` switches models mid-session.

A cloud key is checked before it is saved. The key screen refuses an empty key, and finishing the wizard asks the provider for a one-token completion from its cheapest model: a key that is rejected, or attached to an account with no balance, never reaches `.env` and never becomes the active provider. A provider that cannot be reached at all still saves, with a line saying the key went unverified — an offline or proxied machine stays configurable. Local servers have no account to check and are left alone.

</details>

<details>
<summary><b>Run modes: Local, Cloud, Fusion</b></summary>

A strip under the status bar shows which pair of models the next turn will use, and `Ctrl+R` cycles it:

- **Local** — your llama-server model only.
- **Cloud** — your cloud provider only.
- **Fusion** — the cloud model orchestrates, the local model executes.

Fusion exists because the two halves of a turn have different needs. Planning the work and reconciling a pile of tool output is where a big model earns its price; the mechanical middle of a turn — read a file, edit it, read the next one — mostly does not. Fusion sends the first step of every turn to the cloud, scores each following step, and keeps the cheap ones local.

```
/run # open the picker
/run local # switch directly
/run fusion 60 # switch and set the cloud share
```

The **cloud share** is a dial, not a quota. It does not promise that 60% of steps go to the cloud; it lowers the bar a step has to clear to get there, using a score built from how full the context is, how deep into the turn you are, how much tool output the step is carrying, and whether the model just tripped the loop detector. `0` behaves exactly like Local and `100` exactly like Cloud.

Health still wins over the split: if the cloud provider starts failing mid-turn, the usual fallback chain takes over and the turn finishes locally. Background memory work (reflection, distillation, query rewriting) stays local by default, since it is cold-path JSON that would multiply cost for no visible gain.

Selecting a mode you cannot run — Cloud or Fusion with no cloud provider configured — leaves you where you are and says so, rather than failing on the next message.

</details>

<details>
Expand All @@ -256,6 +290,17 @@ Managed mode downloads the backend, pulls GGUF models, selects the active model,

The managed chat daemon stops when the last session exits, freeing the RAM and VRAM the model was holding; set `localModels.managed.stopOnExit: false` in `config.json` to keep the model warm between sessions. Daemons started standalone with `models start` are never touched.

Cloud models are searchable from the same command — by id, vendor, or capability, across every configured cloud provider:

```bash
atomic-agent models search claude vision
atomic-agent models search free tools --json
atomic-agent models search "1m cache" --provider openrouter --limit 10
atomic-agent models search kimi --refresh # pull live /models lists first
```

Every term has to match (`claude vision` is not a substring of any id), results are ranked best-first, and the same query works in the TUI Cloud pane — press `f`.

</details>

<details>
Expand Down Expand Up @@ -423,6 +468,7 @@ Local-first bounds where control lives, not where packets go. Network egress hap
- an HTTP tool calls a requested endpoint;
- a web search provider answers a query;
- a configured cloud LLM or embedding provider receives its request;
- a `subscription-cli` provider is active and the vendor CLI (`claude` or `codex`) receives your prompt on its stdin, then sends it on under its own account;
- an MCP server receives a tool call you routed to it;
- the Telegram channel is enabled and the bot exchanges messages with your paired chat, including opt-in scheduled task reports;
- you install a skill from ClawHub;
Expand Down Expand Up @@ -467,6 +513,24 @@ Useful environment variables:
- `ATOMIC_AGENT_BROWSER_EXECUTABLE_PATH`: explicit Chromium-family executable path.
- `ATOMIC_AGENT_BROWSER_CDP_URL`: attach to an already-running browser via CDP.

The run mode (Local / Cloud / Fusion) is stored under `llm.runMode`, alongside the providers it names:

```json
{
"llm": {
"activeTextProvider": "openrouter",
"runMode": {
"mode": "fusion",
"localProvider": "local-llama",
"cloudProvider": "openrouter",
"fusion": { "cloudShare": 40, "subRunners": "local" }
}
}
}
```

`localProvider` / `cloudProvider` are optional — the legs default to the first `llama-server`-kind provider and the first non-`llama-server` provider. `cloudShare` is the 0-100 dial described above. `subRunners` (`local` | `cloud` | `follow`) decides where background memory work runs. `activeTextProvider` remains authoritative: change it by hand and the mode follows it, so the two can never disagree.

Secrets for skills and channels belong in `<stateDir>/.env`, not in `config.json`:

```text
Expand All @@ -481,6 +545,57 @@ Shell-exported variables win over `.env`. The built-in parser intentionally supp

</details>

<details>
<summary><b>Claude Code / OpenAI Codex subscriptions</b> (no API key)</summary>

Drives a vendor CLI you are already signed into, so a flat-rate subscription can power the agent with no API key and no per-token billing. Two are supported: `claude` (Claude Code) and `codex` (OpenAI Codex).

**Prerequisite:** the CLI installed and signed in — `claude` then `/login`, or `npm i -g @openai/codex` then `codex login`. Atomic only spawns the binary; it never reads, copies, or replays its OAuth tokens or keychain entries.

In the TUI: **Providers → `n` →** pick the subscription row, then type a model. For Claude that is `sonnet`, `opus`, `haiku`, `fable`, or a pinned id like `claude-sonnet-5`; **for Codex leave it blank** — under a ChatGPT login Codex rejects explicit model ids (`not supported when using Codex with a ChatGPT account`) and resolves one itself. There is no API-key screen, because there is no key. Equivalent `config.json`:

```json
{
"llm": {
"activeTextProvider": "claude-cli",
"providers": [
{
"id": "claude-cli",
"kind": "subscription-cli",
"defaultChatModel": "sonnet",
"subscriptionCli": { "cli": "claude" }
}
]
}
}
```

Optional keys inside `subscriptionCli`: `binPath` (absolute path when the CLI is not on `PATH`), `extraArgs` (appended verbatim — e.g. `["--effort", "high"]`), `streaming` (set `false` to buffer), `maxBudgetUsd`.

Swap `"cli": "claude"` for `"cli": "codex"` to drive Codex instead, and drop `defaultChatModel`.

Each completion spawns the CLI fresh with the prompt on **stdin** (a two-zone prompt exceeds the 128 KiB argv limit). For `claude` it runs `claude --print` with these flags, which are load-bearing rather than cosmetic:

- **`--tools ""`** — disables Claude Code's own Bash/Edit/Write. Without it a second agent would act on your machine outside Atomic's approval ladder.
- **`--strict-mcp-config`** with no config — keeps your MCP servers out of what should be a stateless completion.
- **`--system-prompt`** — replaces Claude Code's coding-agent prompt, which would otherwise compete with the prompt Atomic already built.
- **`--no-session-persistence`** — Atomic owns session state; CLI-side history would double-count context.
- **`--bare` is never passed.** Its own docs say OAuth and keychain are never read under it, which would defeat the whole feature.

For `codex` it runs `codex exec --json` with `--ephemeral`, `--skip-git-repo-check`, `--ignore-user-config` and `-s read-only`. Three differences are worth knowing, because Codex is a more opinionated agent than Claude's headless mode:

- **There is no `--tools ""` equivalent.** `-s read-only` confines Codex's own tools to reading; it cannot remove them. Left to itself, Codex will try to *perform* the request with its own tools instead of emitting Atomic's tool-call protocol — in testing it answered "I can't find `probe.txt`" after looking in its own working directory. The fix is an explicit completion-engine instruction prepended to the prompt (Codex has no system-prompt flag). It works — verified turns drive `os.fs.read` → `reply` and `os.fs.read` → `os.fs.write` → `reply` with no parse retries — but it is a prompt-level guarantee, not a structural one like `--tools ""`.
- **Codex exits 0 even when the turn fails.** A bad model id, an expired login and a rate limit all produce a clean exit with a `turn.failed` event, so the adapter treats a missing `turn.completed` as a failure rather than trusting the exit code.
- **No streaming.** `codex exec --json` emits the answer in one `item.completed`, with no incremental text events, so this provider buffers instead of pretending to stream.

Not supported on either CLI: vision, embeddings (they stay on the local daemon), and the sampling knobs `temperature` / `top_p` / `top_k` / `seed` / `stop` / `maxTokens` — neither CLI exposes a flag for them, so they are dropped rather than silently approximated. Reconfiguring `binPath` or `extraArgs` means editing `config.json`; the model is changeable from the LLM tab.

Two things worth knowing before you switch a long-running agent onto either: each completion pays roughly 0.8 s of process startup, and subscription plans have session and weekly caps that an autonomous multi-step agent reaches much faster than interactive use. When a cap is hit, the CLI's own message is surfaced verbatim.

> [!NOTE]
> Whether driving a subscription CLI from another agent is acceptable use is the vendor's call, not this project's. Atomic uses the officially documented headless mode and nothing else; the decision to use it is yours.
</details>

<details>
<summary><b>Qwen / Tinker tagged tool calls</b> (opt-in compatibility provider)</summary>

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "atomic-agent",
"version": "0.2.2",
"version": "0.3.0",
"description": "Lightweight local operator agent (browser + OS) runtime for Tauri apps. Connects to an external llama.cpp server via HTTP and exposes a sidecar NDJSON protocol plus a debug CLI.",
"license": "MIT",
"type": "module",
Expand Down
Loading