Anatomy

Five regions, top to bottom. Only two are always on screen — the header and the input bar. The rest appear when they have something to say.

The full Axon TUI screen: the header at the top, the empty conversation area, the input bar, and the working directory and token count on the bottom row

The identity block. Who you are talking to, what is powering it, and where this conversation is recorded.

The TUI header showing the braille logo, agent name @axon/zeno, session id, account email, module and tool counts, and the model
LineWhat it tells you
Agent nameThe focused instance — the thing your next message reaches
Session idThis conversation's record. Press it to open the .jsonl
AccountThe signed-in profile
LoadedModules and tools the agent actually registered, and boot time
ModelThe engine the focused agent declares — what * changes

The tool count is the live manifest, not what the config asked for. If something you wrote is missing here, it did not register and the agent cannot call it.

Conversation

The message stream for the focused instance: what you sent, what the agent said, every tool call it made, and any errors along the way. One instance is one continuous stream — there are no branches to track.

The conversation area showing a user message and the agent's reply beneath it, with the token count updated in the bar below

Tool calls render inline as they run. Nothing is hidden behind a toggle you have to know about — the point of the interface is that you can see what the agent did.

Status row

Appears only while something is happening. It carries the spinner and a label for the current activity — booting, working, rebooting, shutting down — and the update notice when a newer Axon is available.

When nothing is in flight the row is empty, so the interface is quiet by default. It is Axon's row, not yours — the rows you compose are status lines, further down.

Input bar

Where you type, and the most information-dense part of the screen. The symbol on the left is the active mode.

The input bar in history mode: an up-arrow symbol on the left, the recalled message 'nice' in the box, the history list above it, and the working directory on the row beneath

The row beneath the box normally shows your working directory — but it is shared, and several things borrow it:

What showsWhen
The pathDefault
A noticetui.info / warn / error, tinted, for a few hundred ms
An escape hintA palette is open and Escape will back out
The exit ladderctrl+c was pressed and outranks everything else
The row beneath the input bar showing a tinted 'tui.warn' notice in place of the working directory

One line, one thing at a time, and the terminal's own hints always win. A notice fired during the exit window waits rather than displacing it.

Palette

Opens over the input bar when you press a mode key. Type to filter, arrows to move, Enter to confirm, Escape to cancel.

TUI command palette open above the input bar, showing a breadcrumb, filtered rows with descriptions, and the cursor on a row

Every palette is the same widget — the built-in ones and any you register have identical row shapes, filtering and navigation. That is deliberate: a palette you write is as good as :, and gets better when : does.

The mode keys

You are always in a mode. The default is normal: type a message, press Enter, it goes to the focused agent. Press a mode key on an empty input to switch; press it again, or Escape, to come back.

You never have to remember them. ? opens the same list, in the terminal, with the symbol beside what it does:

The help palette listing the mode keys with descriptions: colon for command, slash for instance, asterisk for model, caret for session and tilde for agent
KeyModeWhat it opens
:commandThe : command tree
~agentStart an agent
/instanceSwitch to a running conversation
^sessionReopen a past conversation
*modelSet the focused agent's model
%moduleThe agent's modules, and the registry
>promptInsert a prompt into your message
"themeSwitch colour theme, with live preview
#voiceVoice input
?helpKeyboard reference
↑historyPrevious messages (on an empty input)

Two of these also work mid-sentence, because they have a coherent answer for what happens to text already in the box: # appends its transcript, and @ splices a file path over its own trigger. The rest stay literal characters once you have started typing.

A few keys are the terminal's and cannot be rebound: ctrl+c, ctrl+d, Escape, Enter, Tab, the arrows, and backspace.

Agents, instances, sessions

Three of those keys look similar and are not. They address three different nouns, separated by tense:

KeyNounTenseWhat it is
~agenttimelessThe project — config, tools, prompts
/instancepresentA live process you can talk to
^sessionpastA recorded conversation on disk

One agent can have many instances running at once. One instance writes one session.

~ always spawns. Every agent in your profile, with a count beside any that are already running. Selecting one starts a new instance and focuses it — it never navigates you back to something already going.

The agent palette listing @axon/zeno marked '1 running', with @cody/barry.mk3, @cody/dave, @axon/fragcheck and others beneath

/ is how you go back. Live conversations only, in spawn order — a list you navigate must not reorder under the cursor. Each row carries its state and instance id, so two instances of the same agent are still tellable apart.

The instance palette showing two instances of @axon/zeno, one 'active' and one 'exited just now', each with its instance id

^ reopens the past. The focused agent's sessions, newest last, with age and token count. If a session is still live it focuses it; otherwise it boots an instance over the log. Sessions can be renamed, and a fork shows as a branch off the one it came from.

The session palette listing sessions by age and token count, including a renamed session 'mysessionname', a running session, and a forked session shown as a branch beneath its parent

The rule that makes all of this safe to explore: nothing reachable from a palette destroys a conversation. :agent close is the only verb that ends one. Without that, every key needs its own memorised answer to "does this replace what I'm on?"

The command tree

Space descends into a group and the breadcrumb tracks where you are. Rows that have a faster keystroke say so:

The command palette descended into the agent group, breadcrumb reading 'agent › spawn ›', listing spawn, switch, close, reboot and clear with descriptions
GroupCommands
:agentspawn switch close reboot clear model
:sessionpick fork rename open
:moduleinstall update uninstall
:extinstall update uninstall
:linestoggle on off
:providercodex connect|disconnect · openrouter connect|disconnect
:openlog flame engine
top level:init :reload :update :docs :logout :exit

:open needs an attached editor — it opens this session's event log, its trace as a flame graph, or its engine calls as a buffer. See Fleet.

Enter runs what you typed, never what happens to be highlighted. Command mode's query is a path, not a filter, so a partial like : up refuses rather than firing update.

Some rows are a descent rather than an action. Selecting a group rewrites the query instead of running something, and the breadcrumb shows how deep you are. A working row replaces the list while an async action runs, and the list returns when it settles.

Status lines

Configurable rows of your own, between the cwd row and the voice row — and one above the conversation if you want it.

A powerline status line beneath the input bar, carrying the agent name and git branch on the left and the account on the right

You choose what each one shows, in what order, and how it is drawn. Place a second above the conversation and the screen is bracketed by them:

The same terminal with matching powerline status lines both above the conversation and below the input bar
lines.create("me:status", {
    left: ["axon:agent/name", "axon:agent/model"],
    right: ["axon:git/branch", "axon:clock"],
})

lines.set(["me:status"])

Nothing appears until you ask for it: a fresh terminal has none, and the lines Axon ships are registered rather than placed. :lines toggle flips them without touching your config.

The two rows Axon owns stay Axon's. The cwd/token row and the voice row are what must always be readable, and a config that could push them off screen would be one that hides the thing you need in order to fix it.

See lines and components.

Where to go next

Lines — the status bar you compose.

Models — what * opens, and how to find a model in it.

Profile Structure — where your config lives, and what each file is for.