# Axel, every docs page in one file Generated from https://axel.md/docs. Commands are exact; `axel --help` has the flags. # Introduction > Agent orchestration, designed for Rex. Axel is agent orchestration designed for [Rex](https://www.superlogical.com/rex). You type what you want done and press Enter. A named agent picks it up and works on it in a thread, in your terminal, on this machine or another one on your tailnet. ```text › fix the flaky auth test @terra terra · api ``` It runs the agents you already use (Claude Code, Codex, OpenCode, Goose, Cursor and more) as their real CLIs, and adds the layer around them: who each agent is, what it may do, what it's working on, what it costs, and where it runs. ## What we learned, back in the terminal The past year of agent tools taught us what works. Axel keeps those ideas and brings them home to the terminal: **Threads, from the Codex app and T3 Code.** The unit of work is a thread, not a chat tab: an intent and everything done about it, outliving the agent's process, the pane and the machine. Run several at once, come back tomorrow, resume, settle. [More on threads](https://axel.md/docs/threads). **Named agents, from Buzz and skills.sh.** Instead of one assistant that knows everything, a team of specialists. `terra` builds with a few skills for your stack; `opus` reviews with a different model and a review skill. Each has its own Ed25519 key, permissions and budget, and they can ask each other for help within limits you set. [More on agents](https://axel.md/docs/agents). **The terminal, from Rex.** Those tools rebuilt the terminal inside an app because the old terminal couldn't keep work alive, show who's waiting on you, reach your other machines, or even scroll a long conversation without a TUI or tmux mangling it. Rex can: durable sessions, a status protocol the terminal understands, Tailscale built in, real scrollback, and an API programs can drive. That's the foundation Axel is built on. [Why Rex](https://axel.md/docs/why-rex). ## And because it's built that way - **Your agents can run elsewhere.** `@terra@mini` runs terra on your Mac mini, in its Rex session, over your tailnet. Its key never leaves your laptop. Close the lid; the work comes home when you reconnect. - **No babysitting.** Routine permissions follow each agent's mode; a guard refuses irreversible commands; budgets cap spend. When an agent does need you, Rex shows it on the tab. - **No screen scraping.** Status comes from Claude Code hooks, Codex notify, the Agent Client Protocol, or `axel status`, mirrored to Rex. ## For agents and language models The site is readable without a browser: [`/llms.txt`](https://axel.md/llms.txt) is the map and [`/llms-full.txt`](https://axel.md/llms-full.txt) every page in one file. There is also an [Agent Skill](https://agentskills.io) that teaches an agent to install, set up and use Axel on your behalf, published at [`/.well-known/agent-skills/`](https://axel.md/.well-known/agent-skills/index.json): ```bash npx skills add https://axel.md ``` All three are generated from these pages at every deploy, so they never fall behind. ## Where to go next - [Installation](https://axel.md/docs/installation): Rex, Axel and a harness. - [Quick start](https://axel.md/docs/quick-start): Your first agent and thread. - [Why Rex](https://axel.md/docs/why-rex): The foundation, and what Axel builds on it. - [Remote hosts](https://axel.md/docs/remote-hosts): Run agents on another machine. - [Getting the most out of Axel](https://axel.md/docs/tips): Review by turn, undo, a small team on different models. - [Tokens and cost](https://axel.md/docs/usage): What each agent spends, and how much of your plan is left. # Installation > Rex, Axel, and the harness your agents run. ## Requirements - **macOS** (Linux works for the CLI; the floating panes need Rex). - **[Rex](https://www.superlogical.com/rex)**, the terminal Axel lives in. Outside Rex, Axel runs the same interface inline in your terminal. - **A harness**, installed and logged in: [Claude Code](https://claude.ai/code), [Codex](https://openai.com/codex), [OpenCode](https://opencode.ai), or one of the [others](#harnesses). ## Install Axel ```bash curl -fsSL https://axel.md/install | sh axel ``` The script downloads the latest release for your Mac, checks its sha256 and puts `axel` in `~/.local/bin` (set `AXEL_INSTALL_DIR` to choose another place). Every commit on `main` that passes CI is released. Run `axel update` to update using the same script, or pass a version: `curl -fsSL https://axel.md/install | sh -s -- 0.3.80`. The composer checks for releases in the background, sharing a six-hour cache across threads. It suggests `axel update` when a release is more than ten patches ahead, or at least one minor or major version ahead. Checking never blocks typing. ### With Homebrew ```bash brew install scarce/taps/axel ``` `brew upgrade` then brings the newest build. Use the full name: Homebrew core has an unrelated `axel`. ### From source With Rust and [`just`](https://github.com/casey/just): ```bash git clone https://github.com/scarce/axel && cd axel just install # release build, linked into ~/.local/bin and ~/.cargo/bin ``` `~/.local/bin` usually comes before Homebrew on your `PATH`, so a source build wins over the Homebrew one until you remove `~/.local/bin/axel`. ## First run The first time, `axel` runs **`axel setup`** before anything else: - it checks this machine: Rex, git, and which harnesses and ACP adapters are installed, and offers to install a missing adapter; - it creates your first agent: a name, its harness, a few skills, a colour and a runtime mode; - for Claude Code on autopilot, it offers to accept Claude Code's one-time bypass prompt; - then it opens the launcher. It also creates your **owner key** (an Ed25519 key kept in the macOS keychain) and the local database at `~/.axel/axel.db`. Run `axel setup` again any time to add another agent, and `axel doctor` to check everything is in order. ## Managed sessions (recommended) Axel drives agents best over the [Agent Client Protocol](https://agentclientprotocol.com): you then work in Axel's own thread view, and permissions are decided by your policies rather than by a dialog in some pane. - **Claude Code:** nothing to install. Axel's adapter is built in and drives the `claude` CLI directly; no Node or npm needed. - **Codex:** nothing to install either. Axel's adapter drives your `codex` through `codex app-server`, so it always runs your Codex version, config and login. - **OpenCode:** ACP is built into OpenCode itself (`opencode acp`). - **The others** speak ACP themselves, or through an adapter you install next to them. ## Harnesses | Harness | Name | Axel runs | Install | |---|---|---|---| | Claude Code | `claude` | built-in adapter | `curl -fsSL https://claude.ai/install.sh \| bash` | | Codex | `codex` | built-in adapter | `npm i -g @openai/codex` | | OpenCode | `opencode` | `opencode acp` | `npm i -g opencode-ai` | | Goose | `goose` | `goose acp` | [goose-docs.ai](https://goose-docs.ai/docs/getting-started/installation/) | | Cursor | `cursor` | `cursor-agent acp` | `curl https://cursor.com/install -fsS \| bash` | | Pi | `pi` | `pi-acp` | `npm i -g @earendil-works/pi-coding-agent pi-acp` | | Oh My Pi | `omp` | `omp acp` | [omp.sh](https://omp.sh) | | Devin | `devin` | `devin acp` | [docs.devin.ai/cli](https://docs.devin.ai/cli) | | Grok Build | `grok` | `grok agent stdio` | [docs.x.ai](https://docs.x.ai/build/overview) | | Kimi Code | `kimi` | `kimi acp` | [kimi.ai](https://kimi.ai/download) | | Amp | `amp` | `amp-acp` | `npm i -g @sourcegraph/amp amp-acp` | | Hermes Agent | `hermes` | `hermes-acp` | [hermes-agent.nousresearch.com](https://hermes-agent.nousresearch.com) | | OpenClaw | `openclaw` | `openclaw acp` | [docs.openclaw.ai](https://docs.openclaw.ai/start/getting-started) | Name it when you create an agent, with its model after a `/` if you like: `axel agent new gus goose`, `axel agent new opus claude/opus`. `AXEL_ACP_` replaces the command Axel runs (`AXEL_ACP_PI="npx pi-acp"`). Skills are installed for Claude Code, Codex and OpenCode; the others get your `AXEL.md` in their prompt. Without an adapter, an agent runs as its normal CLI in a Rex pane, and reports its status through hooks that Axel installs at launch. ## A key binding Bind Axel to a key in Rex: append [`docs/rex-init.lua`](https://github.com/lgalabru/axel/blob/main/docs/rex-init.lua) to `~/.config/rex/init.lua`, then run `rex config reload`. ## Claude Code's autopilot prompt Agents run on **autopilot** by default: Claude Code starts with bypass permissions, and Axel's guard hook still refuses irreversible shell commands. Claude Code asks you to accept that mode once per machine. Accept it the first time, or set it ahead of time in `~/.claude/settings.json`: ```json { "skipDangerousModePermissionPrompt": true } ``` See [Permissions and budgets](https://axel.md/docs/policies) for the other modes. # Quick start > Create an agent, give it something to do, and follow along. ## 1. Run axel ```bash axel ``` The first time, Axel walks you through setup: it checks your machine, then creates your first agent. Name it (say `terra`), pick its harness, a few skills, a colour and a mode. That generates its key, stores it in your keychain, and signs an attestation that you own it. Later agents: `axel setup` again, or `axel agent new`. ## 2. The launcher Setup ends in the launcher. From then on, run `axel` in any Rex terminal (or press your [key binding](https://axel.md/docs/installation#a-key-binding)). Two panes float over the window: ```text ╭ why not today? ────────────────────────────────────────────────────╮ │ › What are we building? terra · api │ ├ threads ───────────────────────────────────────────────────────────┤ │ › type to filter 4 open · 2 settled │ │ ○ Rate-limit the public API terra api 3 41k 2h ago │ │ ● Migrate billing to Stripe opus vega billing 5 120k 12m ago │ ╰────────────────────────────────────────────────────────────────────╯ ``` The window takes the project's name. Run `axel` again to close both panes. ## 3. Type, press Enter ```text › add retries to the webhook sender @terra ``` Enter launches straight away with what the right of the prompt shows: the agent you used last (or the one an `@name` picks) working **in place** in the current directory. A name you put first is dropped from the prompt (`@terra add retries…` sends "add retries…"). Want something else? Press **Tab** for the full form: which projects (several, or none for a scratch thread), which agent, and whether to work in place or in a new git worktree. ## 4. Follow the thread The prompt pane becomes the **thread view**: the conversation above, a composer below. - Write to steer the agent. While it's mid-turn, your message goes into its turn, and it reads it at its next step. Until then you can still edit it (**Option+↑**). **Ctrl+S** interrupts the agent instead. - Tool calls fold into one line; **Space** expands them, a click opens them in a pane. - Under a turn that changed files, `↗ 3 files +42 −7`: click it to read the diff, leave notes the agent gets as a review, or undo the turn. - Questions and permission requests appear inline. Answer with **Enter**, or **1–9** to pick. - Mention another agent, `@opus can you review this?`, to bring it onto the thread. - The pane beside the composer shows what each agent is spending, as it spends it. ## 5. Come back later Run `axel` and press **↓** to move into the recent threads. Type to filter, **Enter** to reopen one. When a thread is finished, **Ctrl+S** settles it: it stays listed, dimmed, under the open ones. **Ctrl+X** archives it and **Ctrl+D** (twice) deletes it. From the command line: ```bash axel thread ls # open threads axel thread resume # a new session that continues the last conversation axel thread done # settle it ``` ## Next - [Agents and identity](https://axel.md/docs/agents): profiles, keys, and runtime modes. - [Agents working together](https://axel.md/docs/messaging): `send`, summons and replies. - [Remote hosts](https://axel.md/docs/remote-hosts): run terra on your Mac mini and close the laptop. # Why Rex > The foundation. What Rex changes about the terminal, and what Axel builds on it. Axel is agent orchestration designed for [Rex](https://www.superlogical.com/rex), the terminal multiplexer by Superlogical. That isn't a detail of how it's packaged. It's the thesis. ## The detour through apps The agent tools of the past year found the ideas that matter: **threads** as the unit of work, **named agents** with their own skills, agents that keep going on another machine. To deliver them, they each rebuilt the terminal around the agent: their own windows and tabs, their own status lights, their own "keep it running when my laptop is closed". They had to. The terminal they started from couldn't: - keep work alive when you disconnect, close the window or switch devices; - tell you, reliably, that a program is waiting on *you*; - reach your other machines without opening them up to the internet; - be arranged by a program, so a tool could lay out the panes it needs; - scroll. An agent's conversation in a full-screen TUI redraws over itself, and inside tmux you're in copy mode, scrolling a screen that was never meant to be scrolled. A long session's history is junk the moment you scroll up. So the agent ended up in an app, and you ended up with one more window that isn't your terminal. ## What Rex changes Superlogical's starting point is that the missing layer is "a durable session around the work itself", one that can "be driven by software while remaining visible and controllable by people". Rex is that session layer, built from scratch, starting with the terminal. ### Sessions that outlive you A Rex session keeps every block (pane) and window alive across disconnects. The Rex server runs on each machine; the Mac app is a client, and you can connect to any of your servers from it. Agents run in a session, not in a window you might close. **Axel builds on it:** every managed agent runs in a Rex block, so its raw log, its environment and its process survive your laptop going to sleep. On a remote host, agents run in that host's own `axel` Rex session. ### Status the terminal understands Rex's [Program Status Protocol](https://www.superlogical.com/rex/docs/build/program-status.md) is an escape sequence, `OSC 7501`, that lets the program which knows its state report it: `idle`, `working` (with progress), `done`, `blocked` (on a `permission`, a `question` or `auth`) or `error`. Rex shows it on unfocused tabs and in the session picker, and lets Lua scripts react to it. Desktop notifications fire once and forget; window titles are unstructured. This keeps a current picture of every program. **Axel builds on it:** every hook, every ACP frame, every `axel status` is mirrored to `OSC 7501`. Rex's tab indicators and Axel's dashboard always agree, and you see which agent is blocked on you without opening Axel. ### Tailscale, built in A Rex server can join your tailnet as its own device, reachable at `https://..ts.net`, and by default only the Tailscale user who owns it gets in. Rex trusts a caller by how they connect, and Tailscale supplies the identity. Nothing is exposed to the internet, and the machine doesn't even need Tailscale installed. **Axel builds on it:** your Mac mini at home is a Rex host your laptop already knows (`rex -S mini`). `@orion@mini` starts orion in the mini's Rex session, and you can watch its pane from anywhere on your tailnet. See [Remote hosts](https://axel.md/docs/remote-hosts). ### Scrollback that's the terminal's In Rex each block keeps its own scrollback, and Rex is the terminal: no multiplexer layer in between turning your wheel into arrow keys, no copy mode. **Axel builds on it:** a thread's conversation streams into its pane as plain terminal output, not a full-screen redraw, so a day of agent work scrolls, selects and searches like any other output. The composer lives in its own small pane below it. ### A terminal programs can drive Everything Rex does is a [server API](https://www.superlogical.com/rex/docs/automate/server-api.md) that documents itself: sessions, windows, blocks, floating layers, splits, labels, events. The CLI and Lua are generated from it, and Rex ships a skill so agents like Claude Code and Codex can open tabs, split panes and read a terminal's screen. **Axel builds on it:** Axel is just a program in a Rex block. The launcher is two floating panes it opens over your window; a thread is the conversation streaming in one pane with the composer split in below. No custom window toolkit, no Electron: the terminal is the UI. ## Back to the terminal With that foundation, the good ideas don't need an app anymore: | Idea | Where it came from | In Axel, on Rex | |---|---|---| | **Threads** | The Codex app, T3 Code | Durable, signed threads; each session lives in a Rex block. See [Threads](https://axel.md/docs/threads). | | **Named agents** | Buzz, skills.sh | Agents with keys, their own skills, permissions and budgets. See [Agents and identity](https://axel.md/docs/agents). | | **Agents elsewhere** | Remote agent apps | Rex hosts on your tailnet. See [Remote hosts](https://axel.md/docs/remote-hosts). | | **Knowing who needs you** | Per-app status lights | `OSC 7501`, shown by Rex everywhere. | | **Reading a long conversation** | Each app's own scrolling view | Plain output in a Rex pane, native scrollback. | You keep your terminal, your shell, your keys, and the agents' native CLIs. Axel adds the layer around them. # Threads > The unit of work. An intent, and everything done in its name. A **thread** is what you asked for ("add retries to the webhook sender") and the history of everything done about it. It is the one thing in Axel that lasts: agents' processes end, panes close, machines sleep, and the thread is still there to read, resume or hand to someone else. ## Why threads The Codex app and T3 Code made the thread the centre of working with agents, and they were right. A chat tab or a terminal process is the wrong unit: it dies with its window, it holds one agent, and it forgets. A thread is the right one: - **Parallel without losing track.** Five threads run at once; each keeps its own conversation, diff and state, and the dashboard shows which one needs you. - **Durable.** Close the pane, reboot, come back next week: the thread is still there, and a new session resumes the agent's conversation. - **Shared.** Several agents can work on one thread: one builds, another reviews, and all of it is one history. - **Isolated when you want.** One git worktree per thread keeps parallel agents on the same repository out of each other's way. Axel adds one thing: a thread is a **signed event log**, so it can live on several machines and merge, which is what lets it run on a remote host while your laptop sleeps. ## What a thread holds | | | |---|---| | **Intent** | The first prompt. It's also the thread's title. | | **Projects** | 0 or more directories, usually git repositories. None makes a *scratch* thread in `~/.axel/scratch/`. | | **Workspace** | Per project: work *in place*, or in a new *git worktree* on its own branch. | | **Sessions** | Every agent instance that worked on it: which agent, where, with which harness, and the harness's own conversation id. | | **Items** | The conversation: your messages, the agents' replies, tool calls, questions, permission requests. | | **Usage** | Input, output and cache tokens, and the estimated cost, per session. | | **Checkpoints** | Per turn in a git workspace: the tree before and after it, as hidden git refs, with the file list on the turn. | Several agents can work on the same thread at once, and one agent can come back to it many times. Each time is a new **session**: `axel thread resume` starts one that continues the last harness conversation, so the agent remembers where it was. ## Life cycle ```text open ──settle──▶ settled ──reopen──▶ open │ │ └──archive──▶ archived ◀──┘ delete: hidden everywhere ``` - **Open**: listed first in the recent threads and on the dashboard. - **Settled** (`axel thread done`): finished, but still listed under the open threads, dimmed with a ✓. Its agents keep running if they were. - **Archived** (`axel thread archive`): its sessions stop and it is hidden. `axel thread reopen` brings it back. - **Deleted** (`axel thread delete`): its sessions stop and it is hidden everywhere, including `axel thread ls --all`. Its files and worktrees are left alone. Live state (working, blocked, idle) is not stored on the thread: it comes from its sessions. ## Every change is a signed event Under the hood a thread is a log of events, each signed by whoever made it: you, or one of your agents. Two copies of a thread merge by taking the union of their events, which is what lets a remote machine work on a thread while your laptop is closed and catch up later. Because the log only grows, deleting a thread writes a *tombstone* event rather than erasing the history. ## Views - **The thread view**: the conversation with tool calls folded, and a composer. Inside Rex it's two panes: the conversation streaming as plain terminal output (native scrollback) above, the composer below. Opened from the launcher, they take the place of the shell you typed `axel` in, so nothing else in the window moves; closing the composer (Esc, or the pane's ×) brings that shell back, scrollback and all. Each agent's session log stays out of sight; **^L** in the composer shows the log of the agent you're talking to, and hides it again. Rex's Activity (⌘.) still lists every agent on the thread, with its state. The window is named after the thread, and it works both ways: rename the window in Rex and the thread takes the new name. - **What a turn changed**: under each turn that touched files, a change line, `↗ 3 files +42 −7`, or `2 files (+1 not this agent)` when a command or another agent also changed files during the turn. Click it to open the diff pane: the file list, the diff side by side or in one column, notes you can send back as a review, and undo. See [Getting the most out of Axel](https://axel.md/docs/tips#review-by-turn) and the [keys](https://axel.md/docs/keys#diff-pane). - **Thread controls** (**Ctrl+D**): the thread's sessions with what each spent, its context fill and the last hour, and the things you do to a thread: reset it to a fresh context with a recap, move its agent to a host, settle, archive, stop, rename. See the [keys](https://axel.md/docs/keys#thread-controls). - **Attachments**: the 📎 chips under a message are links; a click shows the file in Finder. - **Tokens**: a pane beside the composer shows what each agent on the thread spends, as it spends it. See [Tokens and cost](https://axel.md/docs/usage). - **Tool calls**: each `↗ 5 tool calls` line is a link. Click it (⌘-click if Rex asks) to open every call in it in a pane down the right of the window: who ran it and when, how long each call took, commands with what they're for, edits as diffs, files read and searches, and their output. Scroll it as usual; Esc closes it. The first click asks whether Rex may open links with Axel's link handler. - **Questions**: when an agent asks you to choose (Claude's multiple-choice questions), the question floats in the middle of the window. Pick with ↑↓ and Enter, or type its number. Questions allowing multiple selections show checkboxes: **Space** or **1–9** toggles, **Enter** confirms all checked options, and Decline clears the selection; Esc leaves it for the composer. Questions always wait for you, even in autopilot. - **The dashboard**: every open thread and agent with live state, tokens and a sparkline. It adapts to its size, from a small corner HUD to a full grid. - **`axel thread show `**: projects, participants, sessions and recent messages, as text. # Agents and identity > Named agents with their own Ed25519 keys, profiles and inboxes. An **agent** is a name you can call (`@terra`), a key that signs everything it does, and a profile that says how to run it. Agents are reusable: the same terra works on many threads, over months. ## Why named agents Buzz gave agents names and keys; skills.sh turned skills into a one-line install. Together they point at a better way to work than one assistant that knows everything: - **Specialists.** `terra` builds, with the handful of skills your stack needs. `opus` reviews, with a review skill and a different model. You address each by name. - **Real code review.** The best review comes from someone who didn't write the code. When terra is done it asks opus, on the same thread; opus's findings arrive as terra's next prompt, and you see the whole exchange. A different model catches different mistakes. - **No skill bloat.** Installing every skill into one agent costs you on every session: each skill's description sits in its context, and the more there are, the more often the wrong one triggers. A named agent loads only its own. - **Accountability.** Everything an agent does is signed with its key, and it has its own permissions, reach and daily budget. ## Create one ```bash axel agent new terra codex --skills rust,axum axel agent new opus claude/opus --skills review,security axel agent ls axel agent show terra # profile, policy and the owner attestation ``` Creating an agent: 1. generates an **Ed25519 keypair** and stores the private key in the macOS keychain; 2. signs an **attestation** with your owner key: "this key is my agent terra"; 3. records the profile. The second word is what it runs: a harness and, after a `/`, its model. `claude` uses Claude Code's default model, `claude/opus` picks Opus, `codex/gpt-5.5` a Codex model. Leave it out and the agent runs Claude Code. The harnesses: `claude`, `codex`, `opencode`, `goose`, `cursor`, `pi`, `omp`, `devin`, `grok`, `kimi`, `amp`, `hermes` and `openclaw` (see [Installation](https://axel.md/docs/installation#harnesses)), or any other command. A custom command speaking ACP runs as a managed session too. | Profile | | |---|---| | `HARNESS[/MODEL]` | What it runs; `claude` by default. `--harness` and `--model` say the same as flags. | | `--skills` | Skills to install for it, comma-separated, or `*` for all of them. | | `--prompt` | A standing prompt added to every session. | | `--effort` | How hard its model thinks: `low`, `medium`, `high`, `xhigh` or `max`. See [Reasoning effort](#reasoning-effort). | | `--color` | How it shows up in the dashboard and in `@mentions`. | | `--runtime-mode` | How much it may do alone; see [Permissions and budgets](https://axel.md/docs/policies). | | `--host` | Where it runs unless told otherwise; see [Remote hosts](https://axel.md/docs/remote-hosts). | Change any of it later with `axel agent edit terra …`: `axel agent edit terra goose` moves terra to Goose, `axel agent edit opus --model fable` changes only the model, `axel agent edit terra --name sol` renames it (its key, policy and history stay; sessions already running keep the old name until they restart), `--effort high` sets how hard it thinks (`--effort default` goes back to the harness's own), and `--skills`, `--prompt` and `--color` replace those. `axel agent archive terra` retires an agent and keeps its key and history. ### Custom ACP harnesses Pass the entire ACP command as the harness and set the model separately: ```bash axel agent new maki --harness 'maki acp' axel agent new maki-fast --harness 'maki acp' --model 'opencode-go/deepseek-v4.1-flash' ``` Wrappers work too: `--harness 'fnox exec -- maki acp'`. Axel splits quoted command arguments and starts the command directly, without a shell. The executable must be installed and authenticated on the machine where the agent runs. Axel selects models through ACP `configOptions` when the harness advertises a model selector, including selectors grouped by provider. Older adapters keep using `session/set_model`. Standard ACP usage updates populate the context gauge and cumulative USD cost; the context gauge is not counted as billable tokens. Prompts sent during a turn queue until it finishes. **Ctrl+S** cancels the current turn and sends your new prompt. Harnesses can also opt into live steering with `agentCapabilities._meta.axel.steer: true` and the `_axel/steer` extension described in the [design document](https://github.com/lgalabru/axel/blob/main/docs/DESIGN.md#managed-runtime-acp-and-the-thread-view). This is capability-based and works for custom harnesses as well as the built-ins. ## Reasoning effort ```bash axel agent new opus claude/opus --effort xhigh axel agent edit terra --effort high axel agent edit terra --effort default # back to the harness's own axel agent show terra # "effort high", when one is set ``` The levels are `low`, `medium`, `high`, `xhigh` and `max`; anything else is refused when you type it. An agent without one launches exactly as before: Axel sends no flag and no option, and the harness uses its default. With one, every new session and every `axel thread resume` starts at that level: | Runtime | How the effort is applied | | --- | --- | | Managed Claude | Claude Code starts with `--effort LEVEL` | | Managed Codex | `model_reasoning_effort` in the thread's config overrides, as `-c model_reasoning_effort=LEVEL` would; Codex stops at `xhigh` | | Other managed harnesses (OpenCode, Goose, Grok, custom ACP commands…) | The effort option the harness advertises in its ACP `configOptions` (category `thought_level`, or one named for effort, reasoning or thinking), set with `session/set_config_option` when it offers that level | | Claude pane | `--effort LEVEL` | | Codex pane | `-c model_reasoning_effort=LEVEL` (not `max`) | | Pi pane | `--thinking LEVEL` | | Grok pane | `--reasoning-effort LEVEL` (not `max`) | | Other panes | No flag to pass | When a runtime cannot apply the level (a pane with no flag, Codex and `max`, a managed harness that offers no effort option or not that level, or one that refuses the change) Axel says so: at launch, on the thread for managed sessions, and in `axel agent show` for what it can tell in advance. The session still starts. A pane, or managed Claude or Codex on Axel's built-in adapter, is sent nothing and runs at the harness's default. Any other managed harness keeps the level it already has, which need not be its default; the warning names that level when the harness reports it. The effort is part of the agent's profile, kept on its record beside the model; the agent's key and attestation don't change, and a rename keeps it. `axel agent ls` lists it next to the model. A [remote host](https://axel.md/docs/remote-hosts) gets it with each job, so changing or clearing it locally applies to the next session started there too. ## Why keys Everything an agent does on a thread (a reply, a tool call, a message to another agent) is an event signed with its key. That makes three things possible: - **Attribution you can check.** A thread shows who did what, and a copy of it on another machine can verify that it was really terra. - **Safe delegation.** On a remote machine, terra's key never leaves home: the machine gets a short-lived grant to sign for it on one thread. See [Remote hosts](https://axel.md/docs/remote-hosts#keys-never-leave-home). - **Multiplayer threads.** Threads merge across machines and people by their signed events. ## Inside a session Axel tells the agent who it is through its environment: | Variable | | |---|---| | `AXEL_AGENT_NAME` | Its name. | | `AXEL_AGENT` | Its public key. | | `AXEL_THREAD` | The thread it works on. | | `AXEL_SESSION` | This session. | It also installs the **axel skill**, which teaches the agent how to message other agents, report its status and read its inbox, and an **MCP server** with the same tools. See [The agent's toolkit](https://axel.md/docs/agent-toolkit). ## Inbox Every identity, you included, has an inbox: messages that mention it, permission requests, questions, and status from its sessions. `axel inbox` prints yours; `axel inbox --agent terra` prints terra's. When anything needs you, `axel` opens on the inbox instead of the launcher. # Agents working together > Messages, summons and replies between agents on a thread. An agent can ask another agent for help on the same thread: a review, a second opinion, a piece of the work. You decide who may reach whom, and you see every message. ## Sending From an agent, with the `send` tool of its `axel` MCP server, or the CLI: ```bash axel send "@opus can you review src/auth.rs for the token refresh bug? Reply to terra when done." ``` You can send the same way, from a terminal or by mentioning `@opus` in the composer. Each recipient gets the message in front of it, **on this thread**: | Recipient | What happens | Outcome | |---|---|---| | Already working on the thread | It becomes its next prompt. Mid-turn, yours goes into the turn (the agent reads it at its next step); another agent's waits for the turn to end, so the answer goes back to it. | `delivered` / `queued` | | Not on the thread yet | It's **summoned**: a new session starts with the message as its first prompt. | `summoned` | | Running in a terminal pane | Axel can't type into it; the message waits in its inbox. | `in_pane` | | On your laptop, while the sender runs on a remote host | It's delivered when your laptop syncs, within seconds while it's awake. | `awaiting_sync` | The receiving agent reads: ```text Message from terra, another Axel agent on this thread: can you review src/auth.rs for the token refresh bug? … ``` ## Replies When terra's message starts opus's turn, opus just answers. When that turn ends, its last message goes back to terra by itself, as terra's next prompt, and you see it on the thread as it happens. Terra is told you've already seen it, so it carries on with its task instead of repeating it to you. An answer that comes back is never answered in turn, so two agents can't keep a conversation going on their own, and it never summons anyone. Agents are also told to: - ask **you**, not another agent, for anything only you know; - make each message self-contained, since the recipient can't see their conversation; - end their turn after sending a request, instead of polling; - say results rather than narrate what they're about to do; - only send when they have something the other needs, never "got it" or "thanks": every message costs the recipient a turn. ## Notes that need no reply Not everything needs an answer. An agent sends news as a **note** with `send` and `fyi: true`, or `axel send --fyi`: ```bash axel send --fyi "@opus FYI: the QEDIT build passes now" ``` A note shows on the thread, but it doesn't start the recipient's turn: the recipient reads it at the start of its next one. It never summons an agent that isn't on the thread, so it can't wake anyone up. ## What each agent knows Agents can't see each other's turns; only you see the whole thread. So when you turn to an agent (`@opus what do you think?`), its prompt starts with what it missed since its last turn: the other agents' replies (the newest in full), your messages to them, notes left for it, and who else is working on the thread and on what. Your message comes last. The thread still shows it as you typed it, `@opus` included. Without an `@name`, a message goes to the agent that replied last. The composer's footer shows where it will go before you press Enter: `→ opus`, or `→ +vega` when vega would be summoned onto the thread. Messages an agent already got as a prompt or a note are marked `handled` in its inbox, so it treats them as history rather than requests to act on again. ## Who may reach whom Agents start with **no reach**. You grant it per agent: ```bash axel agent edit terra --allow opus,vega # terra may message and summon opus and vega axel agent edit terra --reach anyone # …or any agent axel agent edit terra --disallow vega ``` When an agent tries to message one it may not reach, Axel asks you then and there, in the middle of the window: **Allow this message**, **Always allow** (the same as `axel agent edit terra --allow opus`), or **Don't allow**. The agent never decides this itself: only your answer grants reach. An agent that may reach you may always be answered: if terra may ask opus, opus may reply to terra, but only while terra is on the thread. Replying never starts a session. Axel also refuses: - **loops**: summoning an agent already in the summon chain; - **deep chains**: beyond each agent's `--max-depth` (3 by default); - **runaway conversations**: too many agent messages on a thread since you last wrote; - **overspending**: an agent past its `--daily-usd` budget. Every refusal names the command that would allow it, and agents are told to pass it on to you rather than look for another way in. # Permissions and budgets > How much an agent may do alone, what it may never do, and what it may spend. Axel is built so you don't babysit agents. Each agent has a **runtime mode** for routine permissions, a **guard** for the things that are never routine, and a **budget**. ## Runtime modes ```bash axel agent edit terra --runtime-mode edits ``` | Mode | | |---|---| | `autopilot` (default) | Never asks. Claude Code runs with bypass permissions, Codex with `--full-auto`. | | `edits` | File edits are accepted; anything else asks you. | | `supervised` | Asks before every action. | | `plan` | Read-only: it may look and propose, not change. | When an agent asks, the request appears inline in the thread view and in your inbox, with the file, diff or command. Answer from either place. ## The guard Whatever the mode, Axel's guard hook refuses **irreversible shell commands** (the kind you can't take back, like wiping a directory or force-pushing over someone's branch) and tells the agent why. Autopilot means "don't ask about the routine", not "anything goes". ## Budgets ```bash axel agent edit terra --daily-usd 20 # or `unlimited`, the default ``` Axel counts every session's input, output and cache tokens and estimates their cost. An agent past its daily budget can't be summoned again until the next day, and the refusal says how to raise it. The tokens pane and the dashboard show tokens and cost per thread and per agent, with a chart of the last hour, and how much of your plan's limits is used. See [Tokens and cost](https://axel.md/docs/usage). ## Reach Which agents an agent may message and summon is a policy too. See [Agents working together](https://axel.md/docs/messaging#who-may-reach-whom). ## Where these apply Policies are enforced by Axel on your machine, and travel with every job sent to a [remote host](https://axel.md/docs/remote-hosts), so terra has the same permissions and budget on the Mac mini as on your laptop. # Tokens and cost > What each agent spends, as it spends it, and how much of your plan is left. Axel counts every session's tokens and estimates what they cost, per agent and per thread, over the last hour, the last day and all time. It also keeps an eye on your plan's limits, so you know before an agent stalls. ## The tokens pane ```bash axel usage # a pane in the top-right corner of the Rex window; again to hide it ``` Every thread opens with the same pane beside its composer, so it's there while you work. It shows as much as its size allows: ```text Axel ~$68.67 24h 24h ~$ 24h ctx last hour opus 79M ~$57.86 62% ⣀⣀⣀⣠⣿⣄⣀⣀⣀⣸ fable 22M ~$10.81 23% ⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀ all 101M ~$68.67 claude 5h ▰▰▰▰▱ 84% ↻2h wk ▱▱▱▱▱ 9% ↻5d ``` | Column | | |---|---| | **24h**, **~$ 24h** | Tokens and estimated cost over the last 24 hours. Wider panes add all time. | | **ctx** | How full the agent's context window is right now, for a session that reports it. | | **last hour** | A chart of the last 60 minutes, two bars per cell, every agent on the same scale. A quiet minute is a dot on the floor. | | **all** | Everyone together, when there's more than one agent. | | **plan limits** | Each harness's windows: Claude's five hours and week, Codex's windows or its monthly credit. The bar, the share used and when it resets (`↻2h`). A window at 100% keeps its reset time however narrow the pane, since that's when your agents start again. | A tall pane adds the threads that spent in the last 24 hours. A sliver of a pane is one line: the last hour's tokens and the 24-hour estimated cost. The dashboard shows the same numbers per thread and per agent, with the sparkline. ## As it spends Managed sessions report tokens while a turn runs, at most every 15 seconds, so a turn that works for an hour moves the chart as it goes rather than landing as one bar at the end. The turn's total still counts once. Pane sessions are read from the harness's own transcript at each hook. ## Where the numbers come from - **Local sessions**: a background worker reconciles the harness logs every 30 seconds. Claude messages count once by message and request ID, including cache duration. Codex request ledger entries count once by response ID. Their cumulative notification mirrors are ignored, including after compaction. Older Codex logs use cumulative differences. Calls use their original timestamps, so a resumed conversation's past spend stays in the past. - **Other sessions**: when native logs are unavailable, Axel uses the reported usage. A missing or unreadable log keeps its last good reconciliation. - **Plan limits**: reported by the harnesses themselves as they run, and kept locally. A window that started over shows as `new` until the next report. `~$` means an API-price estimate, not a charge against your subscription. Model-specific rates include supported long-context tiers and one-hour cache writes. The pane covers **Axel sessions over rolling 24 hours**. CodexBar can include conversations outside Axel and its daily total uses a calendar day, so the scopes can differ. Run `axel usage --refresh` to reconcile immediately and print per-agent estimates. Reconciliation is local and leaves signed reports intact. Dashboard, agent, thread and budget reads use the same reconciled totals. Cost is an estimate from a per-model price table. Every usage report is kept, with no retention, so any window is a sum; the dashboard's sparkline samples are kept for a day. ## Budgets `axel agent edit terra --daily-usd 20` caps what an agent may spend in a day. An agent past its budget can't be summoned until the next day, and the refusal says how to raise it. See [Permissions and budgets](https://axel.md/docs/policies). # The AXEL.md file > One file at the root of a repo, for every harness: the project's context and the skills its agents use. `AXEL.md` sits at the root of a project. Its body is the project's context, the instructions any agent should read before working on the repo. Its frontmatter lists where the project's skills come from. Commit it, and everyone who clones the repo gets the same context and the same skills, whatever harness they run. ```markdown --- skills: - ./skills # a directory in the repo - https://skills.sh/mattpocock/skills/grill-me # one skill, as listed on skills.sh - vercel-labs/skills/find-skills # the same kind of link, short - github:acme/agent-skills@v2 # every skill in a repo, at a tag --- # How to work on this repo - `docs/DESIGN.md` is the source of truth. - Run `cargo test --offline` before saying you're done. ``` ## The context At launch, Axel links `AXEL.md` as the harness's own context file: `CLAUDE.md` for Claude Code, `AGENTS.md` for Codex and OpenCode. The link is relative (`CLAUDE.md -> AXEL.md`), so you can commit it and it still works in a clone. If the project already has its own `CLAUDE.md` or `AGENTS.md`, Axel leaves that file alone. It appends `AXEL.md` to the agent's system prompt instead, so the agent reads both. ## Skills Each entry under `skills:` is one source: | Written as | Means | |---|---| | `./skills`, `~/skills`, `/abs/path` | A directory of skills: `.md` or `/SKILL.md`. | | `https://skills.sh/owner/repo/skill` | One skill from the GitHub repo behind that skills.sh page. | | `owner/repo/skill` | The same, short. It's read as a path instead when that path exists. | | `github:owner/repo[/skill][@ref]` | A whole repo's skills, or one, at a branch, tag or commit. | | `https://github.com/owner/repo[/tree/ref]` | A whole repo's skills, at an optional ref. | Which skills an agent gets is up to the agent: `axel agent new terra --skills grill-me,rust`. When two sources define the same name, directories on disk win over remote skills, so copying a skill into `./skills` overrides it. The first source listed wins otherwise. ### Your own skills Skills that are yours rather than the project's, such as how you like commits written, go in `~/.config/axel/skills`, one `.md` or `/SKILL.md` each. Every project sees them, after its own, and an agent with `--skills '*'` gets them all. They're linked into each project where its harness looks (`.claude/skills`, `.codex/skills`), and each link is listed in the repo's `.git/info/exclude`, so it never shows in `git status` or gets committed. ### Pinned, never silently updated A remote skill is instructions an agent follows with your permissions, so Axel treats an upstream change to it like a code change. The first launch that uses a remote source fetches it and pins the exact commit in `AXEL.lock`, next to `AXEL.md`: ```yaml # Remote skills pinned by axel, one commit per source. Commit this file. skills: mattpocock/skills/grill-me: 4ae2317ddb22b046e26455e4f9c9b3aaaf62212d ``` After that, every launch uses that commit, on every machine that has the lock. Commit `AXEL.lock` with `AXEL.md`. Fetched skills are cached under `~/.axel/skills/cache` by commit, so launches work offline once a skill has been fetched. To move the pins: ```bash axel skills update # fetch, show each diff, ask before moving each pin axel skills update grill-me # just one source axel skills update --yes # apply without asking ``` `axel skills ls` lists every skill available in the project and where each comes from. A source that can't be fetched, or a skill name the repo doesn't have, is reported and skipped. The launch goes on without it. ## Agents aren't declared here Agents are keyed identities in your own store: [Agents and identity](https://axel.md/docs/agents). A repo can't ship them, and doesn't name them. A legacy `agents:` block in `AXEL.md` is ignored. # Remote hosts > Run agents on another machine, close the laptop, find the work when you're back. A **host** is another machine that runs agents for you: a Mac mini at home, a build box, a cloud VM. Ask terra to do something on the mini, close your laptop, take the subway. The work keeps going, and syncs back when you reconnect. ## Add a host Any machine you can reach over SSH works. [Tailscale](https://tailscale.com) makes that easy from anywhere. ```bash axel host add mini # `mini` is an SSH host alias axel host ls ``` This copies Axel over, installs what's missing (Node, Claude Code, the ACP adapter) and records the machine with its host key. Log in to Claude Code once on the host, from a pane of its own Rex, because the keychain isn't reachable over SSH: ```bash rex -S mini run -- claude # then /login ``` For a host that should survive reboots and power cuts unattended, have it log in automatically, keep the Rex server running at login, and disable key expiry for it in your Tailscale admin console. ## Ask an agent to run there ```text › profile the import job and make it faster @terra@mini ``` Or make it terra's default, so a plain `@terra` runs it there: ```bash axel agent edit terra --host mini # `--host local` brings it home ``` `@terra@local` runs it on your laptop for one thread. From the command line: `axel thread new … --host mini`, `axel thread spawn … --host mini`. ## What happens 1. **The thread** is shared with the host. 2. **The code** goes as a snapshot of your working tree (tracked and untracked files, not ignored ones), pushed over SSH into a repository on the host. Your index and branches aren't touched. 3. **The agent** starts in a worktree on its own branch, in a managed session on the host's Rex, on autopilot: nobody is there to answer prompts, and the guard hook still runs. Its [permissions and budget](https://axel.md/docs/policies) and the agents it may reach go with it. Rex on the host notifies you when a turn ends or something needs you. 4. **Your laptop follows along** while the host has live sessions: the thread view streams as if the agent ran locally. It backs off while the laptop sleeps and catches up after. Prompts, steering, approvals and messages you send to that session are relayed to the host. When you're back, its branch (and any uncommitted work) is fetched home. Agents on the host can [message agents on your laptop](https://axel.md/docs/messaging): those messages are delivered when your laptop syncs, under the sender's permissions. ## Keys never leave home terra's private key stays in your laptop's keychain. For each job, the host makes a fresh **job key**, and terra signs a **delegation** to it: "this key may sign as me, on this thread only, for the next 7 days". Every copy of the thread verifies that delegation before it trusts anything the host signed. A delegation can't create threads, can't touch other threads, and expires on its own. `axel host rm mini` stops new jobs. ## Moving a running session ```bash axel session move --to mini # and later: --to local ``` The session stops, and its code (uncommitted changes too) and its Claude Code conversation move with it. A new session on the same thread picks up the conversation where it stopped. Coming home, the work lands in a worktree on the agent's branch, with the host's uncommitted changes still uncommitted. Claude Code sessions only, for now. ## Not yet - Moving a session straight from one host to another: bring it home first. - Moving Codex sessions. - Agents on two different hosts messaging each other directly: it works, through your laptop's sync. # Getting the most out of Axel > Habits that make agents, threads and hosts pay off. Axel works out of the box, but a few habits make it much better. ## Give agents outcomes, and a reviewer A thread's intent is its title and its first prompt. State the outcome and who should check it: "add retries to the webhook sender, then ask @opus for a review". Let autopilot run; answer questions when Rex's tab says an agent is blocked. Agents work best when they aren't narrating steps to you. ## A small team on different models One builder with the few skills your stack needs, one reviewer on another model with a review skill. A different model catches different mistakes, and each agent loads only its own skills, so no session pays for skills it doesn't use. ```bash axel agent new terra codex --skills rust,axum axel agent new opus claude/opus --skills review,security axel agent edit terra --allow opus ``` ## Review by turn Under each turn that changed files, the thread view shows a change line: `↗ 3 files +42 −7`. Click it to open the diff pane. There, **↑↓** picks a file, **j/k** moves through the diff, **v** marks lines, **c** writes a note under them, and **Enter** sends your notes to the agent as one review with the exact lines attached. Wide panes show the old and new text side by side; **s** switches between that and the single column. **u** undoes the turn in the working tree, keeping later work unless it overlaps (**R** restores the turn's files instead). **[** and **]** step between turns. From a shell: ```bash axel thread diff [--turn N] [--stat] axel thread undo --turn N [--restore] ``` Checkpoints are hidden git refs, never on your branches and never pushed. `axel gc` prunes old ones, and runs by itself when you archive a thread. ## Long jobs on a host A Mac mini on your tailnet with Rex running at login is the place for the three-hour refactor. `@terra@mini …` sends it there; the branch comes home when you reconnect, and you review the turns when you're back. See [Remote hosts](https://axel.md/docs/remote-hosts). ## One worktree per parallel thread Press **Tab** in the launcher and pick a new worktree when two threads touch the same repository. Agents stay out of each other's way, and each thread has its own branch to review and merge. ## Keep AXEL.md honest The body is what you'd tell a new colleague before they touch the repo. The frontmatter lists the skills the project needs. Commit both with `AXEL.lock`, so every machine and every harness reads the same context. See [The AXEL.md file](https://axel.md/docs/axel-md). ## Steer without stopping Mid-turn, **Enter** drops your message into the agent's turn; it reads it at its next step and carries on. **Option+↑** edits that message until it's read. **Ctrl+S** is for when the agent must stop now. ## Watch what it costs `axel usage` shows tokens and estimated cost per agent over the last hour, day and all time, and how much of your Claude and Codex plan limits is used. Look before changing models or budgets. `axel agent edit terra --daily-usd 20` caps an agent. ## Let scripts report Anything running in a thread can say where it is, and it shows on the dashboard and on Rex's tab: ```bash axel status working "migrating the auth tests" axel status blocked --kind question "which DB should staging use?" axel status done "PR ready: auth refresh fix" ``` ## When something is off `axel doctor` first: Rex, the keychain, the database, the harnesses. Then `axel log -f` for a managed session's raw frames. Processes started before an update keep the old binary until they're restarted. # Command line > Every axel command. `axel --help` has the flags. `axel` with no arguments opens the launcher (inside Rex, as floating panes; elsewhere, inline). Run it again to close it. The first time, with no agent yet, it runs `axel setup` first. Everything else is a subcommand. Commands answer to the names you'd reach for: the plurals (`axel threads`, `sessions`, `agents`, `hosts`, `logs`), `list` for `ls`, `info` for `show`, `create` for `new` (and `add` for agents, `start` for threads), `rm` for `thread delete`, `settle` for `thread done`, and `msg` for `send`. ## Updates `axel update` runs `curl -fsSL https://axel.md/install | sh`, with installer output shown directly. The composer suggests it when a background check finds a release more than ten patches ahead, or at least one minor or major version ahead. ## Agents | | | |---|---| | `axel agent new NAME [HARNESS[/MODEL]] [--skills a,b\|*] [--effort LEVEL] [--color C] [--runtime-mode M] [--host H]` | Create an agent: key, attestation, profile. `terra codex`, `opus claude/opus`, `gus goose`. | | `axel agent edit NAME [HARNESS[/MODEL]] [--model M] [--name NEW] [--skills a,b\|*] [--effort LEVEL\|default] [--prompt P] [--color C] [--allow A] [--disallow A] [--reach nobody\|anyone] [--daily-usd N\|unlimited] [--max-depth N] [--runtime-mode M] [--host H\|local]` | Change anything about it: harness, model, name, skills, reasoning effort, prompt, colour, permissions, budget, mode or default host. A rename keeps its key and history; running sessions keep the old name until they restart. `--effort` takes `low`, `medium`, `high`, `xhigh` or `max`; `default` goes back to the harness's own. | | `axel agent ls` · `show NAME` · `archive NAME` | List, inspect, retire. `ls` and `show` include the effort when one is set, and `show` warns where the harness cannot take it. | ## Skills | | | |---|---| | `axel skills ls` | Every skill this project can use, and where each comes from. | | `axel skills update [SOURCE] [--yes]` | Fetch remote skills, show what changed, move their pins in `AXEL.lock`. | See [The AXEL.md file](https://axel.md/docs/axel-md). ## Threads | | | |---|---| | `axel thread new "intent" --agent NAME [--project DIR]… [--scratch] [--worktree [BRANCH]] [--host H] [--no-launch]` | A thread and its first session. | | `axel thread spawn THREAD --agent NAME [--host H]` | Another agent on the same thread. | | `axel thread resume THREAD [--agent NAME]` | A new session continuing the last harness conversation. | | `axel thread attach THREAD --project DIR` | Attach another project. | | `axel thread open THREAD` | The thread view, in this terminal. | | `axel thread split THREAD` | A Rex window: the conversation above, the composer below. | | `axel thread ls [--all]` · `show THREAD` | List, inspect. | | `axel thread manage THREAD` | The thread controls: its sessions and spend, and reset, move, settle, archive, stop, rename. **Ctrl+D** in the composer opens the same. | | `axel thread diff THREAD [--session S] [--turn N] [--stat]` | What a turn changed: the file list, then the patch. Without `--turn`, the latest turn that changed a file. `--pane` is the floating pane a change line opens. | | `axel thread undo THREAD [--session S] [--turn N] [--restore] [-y]` | Take a turn's edits back out of the working tree, keeping later work unless it overlaps; `--restore` rewrites the turn's files to how they were before it. A snapshot is kept first; the agent is told. | | `axel thread stop THREAD` | End every live session on it. | | `axel thread done` · `reopen` · `archive` · `delete THREAD` | Settle, reopen, archive, delete. | Thread and session ids accept any unique prefix. ## Sessions | | | |---|---| | `axel session ls [--all]` | Sessions, with their state and where they run. | | `axel session stop SESSION` | End one session and close its pane. | | `axel session move SESSION --to HOST\|local` | Move a running Claude Code session to a host, or home. | | `axel log SESSION [-f]` | The raw frames of a managed session. | ## Messages and status | | | |---|---| | `axel send "@opus …"` | A signed message to every `@name` in the text, as you, or as `$AXEL_AGENT` from inside a session. | | `axel inbox [--agent NAME]` | Your inbox, or an agent's. | | `axel status working\|blocked\|done\|idle\|error\|clear "msg" [--kind permission\|question\|auth]` | Report a status for `$AXEL_THREAD`. | ## Hosts | | | |---|---| | `axel host add TARGET` | Install Axel on a machine reachable over SSH and register it. | | `axel host ls` · `rm LABEL` | List, forget. | | `axel sync [HOST] [--follow]` | Exchange threads, conversations and job branches with hosts. Runs by itself while hosts work for you. | ## Plumbing | | | |---|---| | `axel ui [--screen launch\|threads\|dashboard\|inbox]` | What the floating panes run. | | `axel mcp` | The MCP server, on stdio. | | `axel hook claude\|codex` | The hook sink; installed for you at launch. | | `axel setup` | Check this machine and create an agent, interactively. Runs by itself the first time. | | `axel usage` | The tokens pane in the top-right corner of the Rex window: what each agent spent (last hour, 24 hours, all time), its context fill, and how much of your plan limits is used. Run it again to hide it. See [Tokens and cost](https://axel.md/docs/usage). | | `axel gc` | Prune old turn checkpoints: archived threads after a week; on live threads, after a month, all but each session's latest 20 turns. Runs by itself after `axel thread archive`. | | `axel doctor` | Check Rex, the keychain and the database. | # Keyboard > Keys in the launcher, the recent threads and the thread view. ## Launcher | Key | | |---|---| | **Enter** | Launch with the defaults shown at the right: the last agent used (or the one an `@name` names), in place, here. | | `@name` | Pick the agent. Its name takes the agent's colour as you type. | | **Tab** | The full form: projects, agent, workspace. The pane grows to fit. | | **↓** | Move to the recent threads. | | **Esc** | Close Axel. | | Drop files | Attach them to the first prompt. **Backspace** on an empty prompt removes the last one. | ## Recent threads | Key | | |---|---| | Type | Filter by title, project or agent. | | **↑ ↓** | Move. **↑** on the first row goes back to the prompt. | | **Enter** | Open the thread where you typed `axel`. | | **Ctrl+S** | Settle the thread, or reopen a settled one. | | **Ctrl+X** | Archive it: stop its sessions and hide it. | | **Ctrl+D**, twice | Delete it. | | **Esc** | Clear the filter, then close. | ## Thread view Inside Rex, a thread has two panes: the message pane scrolls and selects text natively, and the composer below edits your message. The message pane has no keyboard cursor. Use the terminal's scrollback controls to read older messages and Cmd-click a tool-call link to open its details. | Key | | |---|---| | **Enter** | Send. Agents advertising live steering read it at their next step; other ACP harnesses queue it until the current turn finishes. | | **Shift+Enter** | A new line (Option+Enter works too). | | **Ctrl+S** | Interrupt the agent and send this instead. | | **Option+↑** | With an empty composer: edit your latest message the agent hasn't read yet. **Enter** saves it, **Esc** leaves it as it was. | | **↑ ↓** | Move between the wrapped lines of your message, including recalled prompts. Past the first or last screen row, browse prompt history. While a question is open: choose an answer. | | **Ctrl+L** | Show the session log of the agent you're talking to, or hide it again. | | **Ctrl+T** | Open a floating terminal in the thread’s project directory or worktree. | | **Ctrl+D** | The thread controls: its sessions and spend, and reset, move, settle, archive, stop, rename. | | **1–9** | Answer a single-choice question, or toggle a checkbox on a multi-select question. | | **Space** | Toggle the highlighted checkbox on a multi-select question. **Enter** confirms the complete selection. | | **Tab** | Move between the composer, attachments and queued messages, skipping empty lists. With no attachments or queue, focus stays in the composer. On a queued message, **Enter** sends it now, **e** edits it and **x** removes it. | | **Space** | Type a space in your message. Open tool-call details with Cmd-click in the message pane. | | Terminal scrollback | Scroll the message pane using your terminal's mouse wheel, trackpad or scrollback keys. | | `@name` | Message or summon another agent on this thread. | | Click `↗ 5 tool calls` | Open the run of calls in a pane. | | Click `↗ 3 files +42 −7` | Open the turn's diff pane. | | Click a 📎 chip | Show the attached file in Finder. | ### Editing your message | Key | | |---|---| | **Option+← →** (or **Ctrl+← →**) | Move by word. | | **Cmd+← →**, **Home / End**, **Ctrl+A / E** | Start or end of the line. | | **Cmd+↑ ↓** | Start or end of the message. | | **Option+Backspace**, **Ctrl+W** | Delete the word before the cursor. | | **Option+Delete**, **Option+D** | Delete the word after it. | | **Cmd+Backspace**, **Ctrl+U** | Delete to the start of the line. | | **Ctrl+K** | Delete to the end of the line. | | **Ctrl+Y** | Put back what you last deleted by word or line. | | **Cmd+Z**, **Ctrl+Z** | Undo, a word at a time. **Shift+Cmd+Z** redoes. | Pasted text keeps its line breaks. ### Inline view outside Rex In the single-pane thread view, **Tab** also visits the timeline. There, **↑ ↓** moves its cursor, **Space** expands or folds tool calls, and **PgUp / PgDn** scrolls the conversation. These timeline keys apply to the inline view, not Rex's read-only message pane. ## Thread controls Opened with **Ctrl+D** from the composer, or `axel thread manage `. On top, the thread's sessions: agent, harness and model, state, turns, tool calls, tokens, cost, context fill and how long each ran, then the thread's totals and the last hour. Below, what you can do to it. | Key | | |---|---| | **↑ ↓**, **Enter** | Choose. Each row has a key too: **r** reset, **m** move, **s** settle, **o** reopen, **a** archive, **t** agents, **x** stop all, **n** rename, **h** hard reset. | | **Reset** | End the thread's sessions, start the agent again with a fresh context and a recap of the thread (the intent, the last turns in a few lines each, the files they changed), and relaunch the thread's own panes. Everything comes back on the installed binary. For when a long thread has grown slow, or after an update. | | **Move** | Run the agent on one of your hosts. A live Claude Code session travels with its conversation; anything else starts there with the recap. | | **Agents** | Choose an agent, then **p** Pause, **r** Resume, **x** Kill, or **d** Remove from thread. Available actions follow its state. | | **Pause** / **Resume** | Freeze the agent and its running tools, then continue them in place. | | **Kill** | End that agent's live sessions on this thread. | | **Remove from thread** | Stop that agent and remove it from the thread roster. Its history and global configuration are kept. An explicit `@name` can bring it back. | | **Stop all** | Stop every live session on this thread. | | **Settle** / **Reopen**, **Archive** | As in the launcher. | | **Rename** | Edit the title in place; the window follows. | | **Hard reset** (in red, last) | End every session and relaunch the panes, starting nobody and carrying nothing over: the next message on the thread starts a brand-new conversation. | | **y / n** | Confirm or back out. **Esc** closes. | After updating Axel, `axel thread refresh ` reloads the thread views while its agents keep running. ## Diff pane Opened from a turn's change line, or with `axel thread diff --pane`. The reader uses normal terminal scrollback, like the message view. Scroll, select text, and search with Rex's usual controls. | Key | | |---|---| | **r** | Enter line review to mark source lines and write comments. | | **s** | Switch between split and unified layouts. | | **[ ]** | Read the previous or next turn. | | **Enter** | Send saved review notes to the agent. | | **u**, then **y** | Undo the turn. Available between turns. | | **R** | Restore after an undo that encountered overlapping work. | | **q**, **Esc** | Close the diff pane. | In line review: | Key | | |---|---| | **↑ ↓**, click a file | Jump to a file in the continuous review. The agent's own files come first, the rest under *also changed*. Wide panes show directory groups beside the code. | | **j / k** | Move through the diff, by line, or by row when side by side. **PgUp / PgDn** page; **g / G** jump to the ends. | | **s** | Switch between side by side (old left, new right) and one column. The code area needs 110 columns for automatic side by side; the sidebar's width is excluded. | | **← →**, **Home** | Pan long code lines horizontally; Home returns to the start. | | **n / p** | Next or previous hunk. | | Mouse wheel | Scroll through all changed files. The header follows the file being read. Click a code line to select it. | | **Tab** | Choose the old or new comment side in side-by-side view. | | **v** | Start or clear a mark; move with **j** to extend it. | | **c** | Write a note under the marked lines (or the cursor line). **Enter** saves it, **Esc** drops it. | | **d** | Remove the note under the cursor. | | **Enter** | Send every note to the agent as one review, each with its path, line range and the marked lines. | | **u**, then **y** | Undo the turn in the working tree, keeping later work unless it overlaps. Not offered while the agent is mid-turn. | | **R** | After an undo that hit overlapping work: restore the turn's files to how they were before it. | | **[ ]** | The previous or next turn of the same agent. | | **q**, **Esc** | Return to native scrolling. Notes you haven't sent are kept. | Syntax colors come from the turn's saved source snapshots. The gutters identify added and removed lines; stronger highlights mark the words that changed. Notes wrap beside the code they refer to, and keep their source line numbers while you scroll, pan or switch layouts. ## Dashboard | Key | | |---|---| | **n** | New thread. | | **Enter** | Open the selected thread. | | **o** | Focus the agent's own pane. | | **s** | Spawn another agent onto the selected thread. | | **Tab** | Next widget: threads, agents, tokens, inbox. | | **i** | Inbox. | | **q** | Quit. | # The agent's toolkit > What Axel gives every agent session, the axel skill and MCP tools. Every session Axel starts knows who it is and how to work with others, whatever its harness. ## The axel skill Installed into each session's skills directory. It teaches the agent: - who it is, from `AXEL_AGENT_NAME`, `AXEL_AGENT`, `AXEL_THREAD` and `AXEL_SESSION`; - how to message, summon and answer other agents, and what each outcome means; - how to behave on a remote host, where nobody can answer prompts; - what each refusal means and what to tell you. ## MCP tools Each session gets an MCP server named `axel`. Agents prefer it to the CLI: structured arguments, no shell quoting, no permission prompt. | Tool | CLI equivalent | |---|---| | `send` `{to: ["opus"], text}` | `axel send "@opus …"` | | `set_status` `{state, message, kind}` | `axel status STATE "MSG" --kind KIND` | | `read_inbox` `{limit}` | `axel inbox --agent "$AXEL_AGENT_NAME"` | | `list_agents`, `get_agent` | `axel agent ls`, `axel agent show NAME` | Agents can't change policies or create agents: `axel agent edit`, `axel agent new` and `create_agent` refuse them. You can run the same server for any MCP client with `axel mcp`. ## Status Managed sessions report working and idle by themselves. For the rest, agents (or your own scripts) report one line you see on the dashboard: ```bash axel status working "migrating the auth tests" axel status blocked --kind question "which DB should staging use?" axel status done "PR ready: auth refresh fix" ``` Status from every harness flows the same way, through Claude Code hooks, Codex notify, ACP, or `axel status`, and is mirrored to Rex, so Rex's tab indicators agree with Axel.