gaia-tui is GAIA’s terminal-native front door. It opens directly on the flagship
gaia agent — conversation, documents, data, web research, memory, skills — behind a
readiness gate that runs on every launch and checks the few things that would
otherwise make the agent fail. Where it can fix a problem itself, one key does it.
Where it can’t, it says so and gives you the exact command.
Download the installer for your platform from amd-gaia.ai,
run it, then open a new terminal:
The Terminal UI and the Agent UI are two front ends over the same
agents. Use the terminal when you live in one or are on a headless box; use the Agent
UI when you want rendered cards and a browser. Both take a dropped file or a pasted
screenshot.
gaia-tui is the Go terminal binary — never gaia, which is the Python CLI’s
name and has entirely different subcommands. It accepts a leading tui word and
drops it, so gaia-tui and gaia-tui tui open the same session. See the
CLI reference for its non-interactive
subcommands.Installing
Every release publishes a native installer per platform at amd-gaia.ai (the page picks your platform). Each puts two binaries on disk and on your PATH —gaia-tui (this app) and gaia-agent (the flagship agent
it runs) — so there is nothing to unzip and nothing to chmod.
On Windows this is the one GAIA installer: on Choose Components, tick
Terminal — and the desktop app too, if you want both. Install GAIA
covers the choice and silent installs (
/S /COMPONENTS=tui).
The Windows setup is per-user: it needs no administrator rights and shows no UAC
prompt. It also bundles Lemonade Server, so the install itself needs no network
(Lemonade downloads its own runtime the first time you run a model). Start Menu
and desktop shortcuts are created; open a new terminal afterwards, because an
already-open one keeps the PATH it started with. Quit GAIA before upgrading —
Windows cannot replace a running program, and the setup will tell you so rather
than install over it half-way.
The Windows setup also gives GAIA its own look in Windows Terminal. It adds a
GAIA profile (IBM Plex Mono, roomy spacing, a dark GAIA colour scheme) and installs
IBM Plex Mono for your account only. When Windows Terminal is installed, the shortcuts
open that profile. Without it, they run gaia-tui in the default console, and the
install log says so. Specifically, the setup writes:
Your Windows Terminal
settings.json and default profile are never changed. To
restyle the profile, use Windows Terminal’s settings. A reinstall rewrites the fragment
but keeps your overrides, because those live in settings.json. If IBM Plex Mono was
already installed, the setup leaves your copy alone. Uninstalling removes the
fragment and only the font files the setup itself added. If Windows Terminal has a
font open during uninstall, that face stays installed and the uninstall log says so.
To remove it, close Windows Terminal, then go to Settings → Personalization → Fonts.
There is no installer for Windows on Arm or Linux on Arm. The flagship agent
publishes no build for either, so an installer there would set up the terminal app
with no agent behind it. The raw
gaia-tui binary is still published for all six targets
if you want to run it against an agent you build yourself.~/.gaia — your chats, documents and memory — in place unless
you say otherwise. On Windows, the terminal is its own GAIA Terminal UI entry
in Installed apps, separate from the desktop app’s, and its uninstaller offers to delete it; on Linux,
apt remove and rpm -e keep it. Lemonade Server is never removed with GAIA,
because other things may be using it — see gaia uninstall --purge-lemonade.
A macOS .pkg ships no uninstaller — that is the platform convention, not an
omission — so remove the files and then forget the receipt:
pkgutil --forget drops only the installation receipt
and deletes nothing, which is why the rm comes first. ~/.gaia is untouched either way.
macOS packages are unsigned unless the release was built with Apple credentials
configured. Unsigned, Gatekeeper warns that the package comes from an
unidentified developer. Right-click → Open no longer bypasses that as of macOS 15:
dismiss the warning, then go to System Settings → Privacy & Security and click
Open Anyway next to the blocked package.
Building from source
Contributors who want the binary from a checkout, rather than the installer:gaia-tui only. gaia-agent still has to come from an installer or a
hub download — the readiness gate below says so on the first screen if it is
missing.
The boot sequence
Every launch —gaia-tui with no arguments, or gaia-tui run email — goes
through the same screens: a splash, a readiness gate, then chat. The flagship
agent adds a short “Getting GAIA ready” stage before chat opens — see
Getting ready.
1. Splash
The first frame is GAIA’s mascot over the wordmark and tagline, while the readiness gate spins up behind it — the launch never opens on a blank terminal:2. The readiness gate
For the flagship, three things are checked, in order, each depending on the one before it: isgaia-agent on this machine, is the local model server (Lemonade)
reachable, and do the models load. The gate stops at the first failure — a
missing model server makes “do the models load” meaningless.
An all-green machine lands in chat without a keypress, naming the chat model on
its way out. Because the last check loads the models, that takes a few seconds
when they are already in memory and longer right after a reboot — time the first
message would otherwise have spent.
First run
On a new machine nothing is broken yet — Lemonade and the models just are not there. The gate shows that as numbered steps, not failures, and the first step is a question: where should chat run? It comes before any download, because the answer decides what gets downloaded.↑/↓ (or press 1–3) and press Enter. When Lemonade is already
installed, the Local option names the model setup would download and whether it
fits this PC’s memory, by the same rule the provider panel uses. esc goes back
to the list of steps, where the question is step 1 and Enter reopens it. If you
chose a model on an earlier launch, or started with --model or
--use-claude, the question is skipped.
Every choice still installs Lemonade next: it runs local models, and for a cloud
provider it routes the requests and computes the embeddings that document
search and memory use.
- Local — step 2 installs Lemonade, step 3 downloads the models.
- Fireworks AI or AMD LLM Gateway — step 2 installs Lemonade. Step 3 opens that provider’s key form; paste the key, pick a model, and setup downloads only the embedding model. No local chat model is downloaded.
Enter and the step runs right there. The row it is working on shows it,
and the line underneath says what is happening in words — never a log line.
The Lemonade step installs Lemonade and stops, downloading nothing — and so does
every retry of it, and the key on a Lemonade row that is installed but not
running. p still opens the full provider panel at any point, to pick a
specific model rather than the default. Press Enter again to start the last
step:
esc cancels it. If setup stops, the screen says why and d shows its full
output; gaia init does the same work from a terminal.
If this PC already runs a Lemonade Server (v10.9.0 or newer) on its default
port, the Lemonade row offers it instead of step 1: press f to use it, or g
to install GAIA’s own (saved once GAIA’s server is installed and running). Using yours keeps one server and one copy of each model
on the PC. A server that needs an API key shows the gaia lemonade connect
command that saves the key. The choice is remembered. GAIA never changes your
server’s setup: it doesn’t register cloud providers or hand it keys, and the
/provider panel uses a provider only if your server already has it. Setup
downloads only the models your server lacks. To switch
back, run gaia config set lemonade_mode gaia (it’s refused until GAIA’s own
server is installed; gaia init --gaia-lemonade does both). See
Use a Lemonade you already run.
When setup finishes, the gate checks the models by loading them once — the
chat model, and the embedding model that document search and memory use — and
only then says it is ready, naming the chat model and its size:
When something is actually broken
A real failure is marked[!] and says what to do. For example, a model that
downloaded but will not load:
Enter starts
GAIA without document search and memory. A chat model that will not load does.
If gaia-agent itself is missing, the gate stops on the first row and sends you
to the installer — there is no in-TUI download for the agent binary:
f: the TUI cannot install its own agent binary, so it names
the installer instead of offering a key that would not work.
A daemon-supervised sidecar agent goes through the same three screens, but its
gate has more rows: background service, sidecar, Lemonade, and model. The
flagship is one of these once gaia init has installed it.
If the background service does not list the agent at all, the sidecar row names
gaia daemon restart. The service reads its agent list only when it starts, so
one started by an older GAIA does not see an agent installed since — the remedy
also names the install command (gaia init for the flagship) in case it is missing.
When the background service or the agent is simply not running — the usual
state after a reboot — the gate starts it itself and shows starting… on that
row, so the launch needs no keypress. A start that fails keeps the row’s error
and remedy, and f tries again. The gate starts nothing on its own when the
service’s port answers as something else, or when LEMONADE_BASE_URL points at
another machine; those rows wait for f.
Markers
The marker and the words carry the state on their own, so the screen reads the same
on a monochrome terminal or piped to a file.
Keys
Enter is not offered while a row is failing outright. Press it anyway and the
screen names the blocker rather than starting a chat that cannot talk. It is
offered when a row is merely unverified ([?]) — nothing there says anything is
broken.
Getting ready
On a local model, the flagship’s first answer used to pay for starting the agent, loading the model and reading its ~10K-token instructions while you watched a spinner. That now happens before the chat opens, with each step named:Esc
shows the chat without stopping the warm-up. A remote model (Fireworks, the AMD
gateway, Claude) has nothing to load, so the stage ends as soon as the agent
has started. A launch with --query skips it, because the question pays for
the same work.
3. Chat
Once the gate clears, GAIA starts the agent and drops you into the conversation:agent <id> segment is always the stable id, lowercased — the same string
--agent <id> takes, so you can read it straight off the header and pass it back.
The version beside it is the one the running agent reports about itself, and the
welcome line adds the GAIA core it runs on. An agent too old to report a
version gets no number at all rather than one read from an install record, which
can name a different build than the one answering.
On a narrow terminal this segment is the first thing to give way, never the model
chip next to it.
The model chip names the chat model from the moment the chat opens, local
included: the one the startup check loaded, until the agent reports the model it
actually runs. The model you last picked is restored on the next launch; if it
can’t be, the chat says so in one line and opens the provider picker. See
Your model is remembered.
Once setup has installed the flagship as a hub package, the TUI reaches it through
the background service. /model and /provider work the same there: the switch
is checked against the models Lemonade serves, the header names the new model, and
your next message runs on it. It is remembered once that message completes; if the
agent refuses the model, the previous one comes back. Neither command is ever sent
to the agent as a question. An agent too old to switch models mid-chat says so and
names the update command.
Reading a turn
While the agent works, and afterwards, each thing it did is one short row, with the answer set apart below:- Paths are shown relative to the folder you started GAIA in, or under
~; a path that is still long keeps its end. - A failed step keeps its reason under it, remedy included — that row is where a failure lives, so a retried call is one red row, not a separate error.
- A confirmation asks once, in the prompt pinned above the composer. The step
it gated then records your answer in a word:
approved,denied, oralways allowed '<scope>'. - The agent’s narration (“Let me check the tests first”) is folded away.
Ctrl+Oshows it, along with each step’s full command and timing. A stage or a narration line the agent repeats word for word — a plan’s “Following the plan to …” headline before every step — is shown once, until it changes.
Saying something while the agent is still working
You can keep typing through an answer — the composer stays live while text streams and while tools run. PressEnter and the message goes to the turn
already running: the agent picks it up at its next step and answers it
alongside what it was doing, instead of you waiting out a five-minute task to
ask a one-line follow-up. Nothing is interrupted and no second turn starts.
The row under the composer says which of two things Enter will do, because
they are not the same:
Your message only enters the transcript once the agent actually received it. If
delivery fails you are told why, and the text goes back to the queue (or to the
composer, if the turn has already ended) rather than disappearing.
Mid-turn messages need agent contract 2.15 or newer. On an older one
Enter
queues as before, and the TUI says so with the command to update.
By default the mouse belongs to your terminal, so you drag to select text and
copy and paste with your terminal’s own keys (Ctrl+Shift+C / Ctrl+Shift+V,
Cmd+C / Cmd+V, or right-click). The wheel still scrolls the conversation:
GAIA turns on your terminal’s alternate scroll mode, which sends each wheel tick
as ↑ / ↓. Your terminal’s selection only covers what is on screen, though:
dragging past the top or bottom of the conversation doesn’t scroll it. To select
something longer, press Ctrl+T to hand the mouse to GAIA, or copy without the
mouse at all with Ctrl+Y, /copy or /copy all. The status bar shows the
Ctrl+T hint either way.
Commands the current agent can’t run drop out of
/help and the / palette on
their own — /model, /setup, and /provider are flagship-only, and /memory
needs a peer new enough to serve it (see the memory guide).
/agents is always available.
Selecting a different agent from /agents reconnects in place and re-runs the
readiness gate for it; the transcript stays on screen with a divider noting the
switch, but the new agent never sees the conversation above that line. Backing
out of the picker (Esc) returns to the chat you were already in — it does not
quit the TUI.
Typing / as the first character of an empty composer opens a palette listing every
command above with a one-line description, so there’s no need to already know them or
open /help first:
/mo above narrows to /model), ↑/↓ to move the
selection, Enter to run it, Esc to close the palette without touching the composer
or cancelling a running turn. A / typed mid-sentence is just a slash — the palette
only opens on an otherwise-empty line.
The mouse works the same list: hovering a row moves the selection there, and
clicking the row that is already selected runs it — the common case, since hovering
already selects before you click. Clicking outside the box closes the palette, same
as Esc. None of this needs a mouse: every path above is reachable from the keyboard
alone.
When an agent asks a follow-up question mid-turn — “Gmail or Outlook?”, say — its
options are the same: ↑/↓ (or Tab) to move between them, a number key to pick
one directly, Enter to answer, and the mouse works identically to the palette above.
Esc cancels the turn rather than the question, since abandoning it is the only way
out once it is up.
When the agent asks first
Before the agent runs a shell command or Python, or writes a file, it asks. The prompt shows the command once, labelled by what it does:
Paths are shown relative to the folder you started GAIA in, a leading
cd moves
to its own in … line, and a long command keeps its start and its end with the
middle marked as cut. The in … line also appears when an earlier cd left the
session in another folder. A WRITE or RUNS CODE command gets one plain line
saying what it can do.
A command GAIA doesn’t run unasked — python script.py, git commit, npm test
with no skill loaded for it — gets this prompt rather than an error. a covers
that one command family (git commit, python (any script)) for the session and
nothing wider. If you deny it, the agent is told not to get the same result
another way, and stops to explain.
A command GAIA’s own checks don’t cover — git push, git fetch, Python passed
with -c, a PowerShell command it can’t read, a line with $(…), a path outside
the project — is asked about too, with three differences. The prompt shows the
exact line the shell will run, unshortened, and the full folder it runs in. A
risk line says what it can do: “Sends your commits to the remote repository.”,
“Reads or changes files outside this project: …”, or “Can run any code with your
permissions — GAIA can’t inspect this command.” And only y and n are offered:
approving runs that exact line once, and the next one asks again.
-EncodedCommand or a line
with invisible or line-break characters (the prompt couldn’t show what runs), a
line whose quoting GAIA can’t split the way the shell would, a line its checks
don’t cover that also deletes or discards work (git push --force, git reset --hard, git clean, rm outside the project), and folders no approval can
open (credential folders, the system temp folder, a whole drive or your home
folder). The agent
says what it would have run, so you can run it yourself.
A prompt nobody answers expires after 10 minutes. The agent is told it timed
out, not that you refused, so it asks whether you still want it rather than
giving up on something you never saw.
Permission modes
Shift+Tab cycles the mode, and the status bar always shows which one is on:
Full access is never switched on by a stray keypress. The first time
Shift+Tab
reaches it in a session, GAIA explains what it does and stays in ask; type
/full-access confirm to turn it on. After that, or in a session launched with
--full-access or with full_access saved in your config, Shift+Tab switches
straight to it. Turning it off is never gated. While it is on, a banner says so
on every frame.
Commands GAIA’s checks don’t cover — printing a credential (gh auth token), a
git option that hides a script — ask once in ask and accept edits, showing
the exact line, and no a answer covers them. An encoded PowerShell command, or
one that deletes or discards work on such a line, stays refused. Only full
access lifts the shell guardrails; see Full access.
A session launched with --use-claude skips first-boot setup entirely and does not
start the local server — that flag exists to avoid the local backend, so running an
installer that launches it would defeat it, and would hold the first answer behind a
multi-minute install. The transcript says the server was not started and names what
still needs it: RAG, memory and the code index embed through Lemonade, which has no
Claude equivalent. Run gaia init --skip-chat-model, or /setup in
the composer, when you want those.
What a session costs
/cost answers “what has this conversation spent”, which is the question behind
deciding whether a task is worth running on a cloud model at all:
- Every number is measured, never estimated. They are summed from what the backend reported for each turn. A turn whose backend reported no token counts still counts as a turn, contributes nothing to the token totals, and the view says how many turns went unmeasured rather than quietly averaging over them.
active timeis the sum of the turns, not the clock. The minutes you spend reading an answer are not the agent working, so they are not in it.
Rates, and setting your own
Rates for the models GAIA ships are built in, and every dollar figure is printed with the date they were read, so a stale card is visible rather than silent. A model with no published rate shows tokens and no dollars — an absent figure sends you to look it up, where a guessed one quietly prices your month wrong. To override one — a negotiated price, a tier that isn’t listed, or a correction after a provider moves its prices — write~/.gaia/model-prices.json:
cached_per_mtok bills cached input
at the full input rate, and setting it to 0 means cached input is free — different
offers, so they are written differently. GAIA_MODEL_PRICES overrides the path.
If that file exists but can’t be parsed, /cost says so and names the problem rather
than reporting “no rate configured” — otherwise you would edit a file that is already
being ignored.
To run a turn somewhere other than this machine — Fireworks AI or your
organisation’s AMD LLM Gateway — choose it at the first-run question, press p
at the readiness gate, or type /provider. See AI providers.
When GAIA asks permission
Some tools do things that are hard to undo. Those stop and ask:READ, WRITE, RUNS CODE or
DESTRUCTIVE — and the question. Tools GAIA knows get a plain question (Run this command?, Write this file?, Install this skill?); any other tool reads
Allow <tool>?. A DESTRUCTIVE prompt adds a warning line under the call.
y runs it once, n or esc denies. Denying is a normal outcome, not an
error — the agent is told you said no, doesn’t try another way to do the same
thing, and carries on with whatever doesn’t need it. When nobody can answer — a
scheduled or background run, or a prompt that expires — the command doesn’t run.
A command GAIA’s own checks don’t cover offers no a: it shows the exact line
and a risk line, and runs once if you say yes (see
When the agent asks first).
The prompt names the tool and its arguments, because the argument is usually
the part that matters. An “always allow” answer, where offered, is scoped to
that specific call — approving gh issue list once does not hand over your
shell for the session.
--bypass-permissions runs every tool without asking, and the TUI shows a
persistent warning the whole time it is on. /bypass off turns it off
mid-session.
Running another agent
The flagship is the default, butgaia-tui can also drive email by id — it keeps
its own five-row readiness gate:
Colours (light vs dark terminals)
Colours adapt to your terminal automatically. Some terminals never answer that query (SSH, tmux, a CI log) — if the screen comes out hard to read, force a mode:Troubleshooting
“not downloaded yet” when a chat model already works. The Language model row covers the embedding model too, and the embedder is what usually blocks a machine that can already chat. The row says “Several GB” because that is the common case; if chat works, the missing piece is the ~300 MBuser.embeddinggemma-300m-GGUF. gaia init --check names the exact model id,
and f fetches just what is missing.
The gate says Lemonade is fine but chat fails. The gate checks that the
server answers; it does not load a model. Check the server’s own log —
~/.gaia/lemonade/lemond.log for the embedded instance.
A turn is taking minutes. On a local model most of that is prompt
processing rather than generation — the status line’s ttft is the honest
number. A cloud provider trades that for network latency and privacy.
It quit with no message. gaia-tui status shows the background service and
what is installed.
Is it running on Vulkan, ROCm or the CPU? gaia-tui status prints a
Model server line, and /provider shows the same under Local:
(default) means Lemonade picked the backend; unknown means this Lemonade
does not report it. To choose one, run gaia config set llamacpp_backend rocm
(or vulkan, cpu, auto), or use Settings → Advanced → Model server in the
Agent UI, which lists only the backends this PC can run. It applies the next
time the chat model loads.
Next steps
- CLI reference — the non-interactive
subcommands (
run,chat,status) and their exit codes. - Driving the TUI programmatically — the control API, for tests and assistants. Not needed for normal use.