Skip to main content
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.
This binary boots straight into the flagship, and it does not install, uninstall, search, or vote on agents — that stays the Python CLI’s job (gaia hub install email --trust for the email agent). An earlier version of the TUI opened on an agent browser that did all of that, with the flagship listed as “Coming Soon.” That screen, and the list / install / uninstall / hub subcommands that drove it, are gone for good.What did come back, scoped down: type /agents in chat to list every agent already installed on this machine and switch to one, without quitting the TUI. See /agents below.

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.
Uninstalling leaves ~/.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:
There are two receipts because the tools and the licence ship as separate components — forget both. 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:
This builds 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:
On a terminal shorter than 32 rows or narrower than about 44 columns, the mascot is dropped and the frame is just the wordmark and tagline on one line.

2. The readiness gate

For the flagship, three things are checked, in order, each depending on the one before it: is gaia-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.
Move with ↑/↓ (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.
When the AMD gateway can’t be reached (no AMD network or VPN), its option is greyed out and says “No network available”. Connect, then press r.
Press 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:
An embedding model that will not load does not stop the launch — 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:
This row has no 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:
Anything you type meanwhile waits and is sent the moment GAIA is ready. 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:
The 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, or always allowed '<scope>'.
  • The agent’s narration (“Let me check the tests first”) is folded away. Ctrl+O shows 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. Press Enter 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:
Keep typing to narrow the list (/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.
A few stay refused with no prompt: a PowerShell -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:
Two things that line is careful about, because a cost readout that gets them wrong looks like a measurement and nobody re-checks it:
  • 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 time is 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.
While a metered model is running — a cloud provider you are billed by, or Claude — the running spend also rides the status bar, so it is in front of you when you decide whether to ask the expensive follow-up. A local model costs nothing to run again and a gateway your organisation already pays for is not your bill, so neither shows the line.

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:
Dollars per million tokens; your file wins over the built-in rates, and the readout says which of the two it quoted. Keys match exactly first and then by longest prefix, so one entry can cover a whole family. Omitting 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:
The first line is a risk badge — 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, but gaia-tui can also drive email by id — it keeps its own five-row readiness gate:
Installing or removing it is the Python CLI’s job:

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 MB user.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