a-agent
a is a fast, single-process terminal coding agent written in Rust.
Its core stays intentionally small:
- three tools:
read,apply_patch, andbash - no repository indexing, daemon, PTY wrapper, LSP, or background watcher
- progressive loading for file targets and Skills
- an append-only colored transcript with a Rustyline prompt
- resumable, branchable SQLite conversations
- Anthropic Messages, OpenAI Responses, and OpenAI-compatible Chat Completions
Build
Rust 1.95 or newer is required.
# Or install the current checkout:
The installed binary is named a.
Configure
On the first agent run, a creates ~/.config/a/config.toml from
config.example.toml and prints its path. The default
Responses settings are active. Configuration uses named provider and model
profiles; the legacy singular [provider] table is not supported.
One provider can serve multiple independently configured models:
= "codex"
[]
= "responses"
= "https://api.openai.com/v1"
= "OPENAI_API_KEY"
[]
= "openai"
= "gpt-5.6"
= "medium"
= ["low", "medium", "high", "xhigh", "max"]
= 1050000
[]
= "openai"
= "gpt-5.6"
= "low"
= ["none", "low", "medium"]
An API key can also be stored directly. A non-empty api_key takes precedence
over api_key_env:
[]
= "sk-..."
This is convenient but stores the secret as plaintext. Keep the file private and out of version control; environment variables remain the safer default.
Anthropic Messages:
[]
= "anthropic"
= "https://api.anthropic.com"
= "ANTHROPIC_API_KEY"
[]
= "anthropic"
= "your-claude-model"
= "high"
= ["low", "medium", "high", "max"]
Anthropic's Rust SDK appends /v1; configure an origin rather than a /v1
endpoint. OpenAI protocol base URLs should normally include /v1.
OpenAI-compatible Chat Completions:
[]
= "chatcompletion"
= "https://gateway.example/v1"
= "GATEWAY_API_KEY"
[]
= "acme"
[]
= "priority"
[]
= "gateway"
= "provider-model-id"
= "medium"
= ["low", "medium", "high"]
Provider profiles own endpoints and authentication. Model profiles own the
model ID, effort choices, context window, token limit, and optional
header/request overrides.
When set, context_window must be greater than the model's effective
max_tokens value.
No provider discovery or capability probe is performed. Only the selected
provider is initialized.
Project-local .a/config.toml values override the global config.
Use
|
-1 exits after one complete logical user turn, including all model/tool
cycles. Target files are sent as paths; their contents are read only if the
model calls read. Piped stdin is bounded and keeps the tail, which is useful
for compiler and test logs.
Interactive a defaults to multi-turn mode. Tab switches the right prompt
between multi · tab and once · tab; once mode exits after the current
response. Input history is stored in SQLite and shared across interactive
a-agent sessions. Fish keeps its own existing history behavior.
Interactive commands:
/model [profile]
/effort [level]
/thinking
/status
/clear
/compact
/resume [session-id]
/help
Without an argument, /model and /effort open an arrow-key selector. Typing
/ opens a live-filtered command palette below the input. Use Up/Down to
select a command, then Tab to complete it or Enter to run it immediately.
Each row shows the command's parameters and purpose. /thinking toggles
reasoning visibility, like Ctrl+O, and
reports the new state. Model profile and effort changes are persisted with the
session and restored by resume. /resume opens a current-directory session
selector when no ID is given; entries are labeled with their first user prompt.
Resuming a session prints a divider and replays its active history before new
input. Sessions from another cwd are rejected. In Fish, selecting a session
also rebinds that Fish process so later Ctrl+G turns continue the selected
conversation.
/compact immediately summarizes the active branch; automatic compaction uses
the same path.
/status reports the active model and effort plus context usage. It
distinguishes the latest provider-reported token anchor from locally estimated
trailing messages, and shows the context window and automatic-compaction
threshold when configured.
When a model profile sets context_window, automatic compaction triggers near
context_window - max_tokens. Context usage is anchored to the latest valid
token count returned by the provider. OpenAI cached input is normalized into
separate cache-read/cache-write fields; total_tokens is preferred when the
provider returns it. Only messages added after the usage anchor use a small
characters-per-token estimate. Compaction does not add a token-count API
request to each turn, and compaction summary requests do not expose tools.
Context
Active AGENTS.md files are loaded along the current/target path ancestry,
from broad scope to specific scope. The optional global file is:
~/.config/a/AGENTS.md
Skills are discovered only in direct child directories:
~/.config/a/skills/<name>/SKILL.md
<project>/.a/skills/<name>/SKILL.md
Only Skill name, description, and path are loaded during startup. The model
must use read to load a relevant Skill body.
Sessions And Rewind
Sessions are stored in $XDG_STATE_HOME/a/sessions.db, or
~/.local/state/a/sessions.db when XDG_STATE_HOME is unset. SQLite uses WAL,
normal synchronous mode, foreign keys, and semantic write boundaries.
An interrupted turn records an internal notice so a later resume does not
silently continue the cancelled task.
In interactive mode, press Esc to select a previous user checkpoint. A
second Esc triggers it immediately instead of waiting for the terminal's
500 ms escape-sequence timeout. Rewind moves the session HEAD; it does not
delete the old branch. The picker uses Up/Down, Enter, and Esc, and
includes persisted user checkpoints from before compaction.
Default controls:
Esc/Esc Esc: rewind pickerCtrl+O: toggle reasoning visibilityEscorCtrl+Cduring a turn: cancel the active turnCtrl+Cat the prompt: exitUp/Down: input or picker history
The reasoning key is configurable with ui.reasoning_toggle = "ctrl-r".
User, assistant, reasoning, running tools, successful tools, and errors use
distinct semantic colors. Every line is written once to normal terminal
scrollback: there is no viewport, content redraw, history overwrite, or
alternate screen.
Tool calls use domain-specific, bounded output: Bash shows $ commands and a
live output tail, read shows the path/range and a numbered preview, and
apply_patch shows A/M/D file operations plus diff statistics. Unknown tools
fall back to labeled input/output blocks. Configure display limits with
ui.tool_input_max_bytes, ui.tool_output_max_bytes, and
ui.tool_output_max_lines.
apply_patch updates existing files in place so permissions, ownership, hard
links, ACLs, and extended attributes remain attached to the same inode. New
files use the process's normal umask.
The transient parallel-tool panel keeps the latest
ui.tool_live_output_lines lines per running tool.
A transient spinner remains below the currently streamed reasoning or assistant
line throughout model generation. Completed lines are appended to scrollback
immediately; only the unfinished line is redrawn. The spinner disappears when
generation completes and never enters scrollback.
Fish
Install Fish hooks and the AI-mode binding:
Restart Fish, or source ~/.config/fish/conf.d/a.fish. Ctrl+G opens the
dedicated a> input prompt. It deliberately does not enable Fish --shell
mode, so shell syntax highlighting and autosuggestions do not apply. The right
prompt shows once · tab by default; press Tab to switch to multi · tab.
Once mode returns to Fish after one response. Multi mode keeps showing a>
after each response until it is switched back to once or cancelled. The mode
choice is retained for the lifetime of that Fish process, including across
Ctrl+G and Ctrl+C exits from AI input.
Press Ctrl+G again to restore the current text to the normal Fish editor on
the same line. Press Ctrl+C to cancel the AI input line and open a fresh Fish
prompt.
Each Fish process has an isolated conversation for each cwd. Opening another
Fish process in the same directory starts a separate conversation. Use
a --resume explicitly to resume the latest conversation for a cwd regardless
of which Fish process created it.
The Fish hooks record command, cwd, exit status, pipe status, start time, and duration. They never capture stdout or stderr. The Rust runtime injects recent command records from that Fish process and cwd into the request's system context.
Security
read, apply_patch, and bash can access paths outside the cwd and run with
the current user's permissions; none is sandboxed. API keys are read from the
selected provider profile or its configured environment variable and are never
persisted in SQLite.
Validate
Set A_DEBUG_TIMING=1 to print startup phase timings before the first model
request.
Resume startup can be benchmarked against a local mock provider. The final argument is the number of turns preloaded into the baseline session: