Source Code:
src/gaia/cli.pyPlatform Support
Windows 11
Full GUI and CLI support
Linux
Full GUI and CLI support via source installation (Ubuntu/Debian)
Quick Start
- Windows
- Linux
- Follow the Quickstart to install GAIA
- Open PowerShell and run
gaiato launch the Agent UI, orgaia --clifor terminal chat
Top-Level Flags
Runninggaia with no subcommand launches the Agent UI by default:
Examples:
gaia chat --ui continues to work as an alias. The Agent UI does not gate on your processor model — the Settings panel reports your processor, memory and model status for information only.Agent step limit
Agents stop after a maximum number of reasoning/tool steps. The flagship GAIA agent (gaia chat, the Agent UI, the TUI) defaults to 150, enough for long desktop tasks such as reading a folder of datasheets and writing a costed BOM. Other agents default to 50.
When 20, 10 and 5 steps remain, the agent is told so and asked to produce what the request asked for from what it already has, marking anything it couldn’t verify, rather than keep researching. An agent that runs out of steps before finishing still answers: it gets one more model call in which it can’t use tools, and reports what it found, what it couldn’t finish and why, and what you can do next. That summary is kept even when a requested file was never written; the missing file is listed after it. If that last call fails, you get the step-limit notice with the agent’s latest write-up and a line saying why the summary couldn’t be written. Set GAIA_AGENT_BUDGET_NOTICES=0 to turn the step-budget notices off.
The same closing call runs when an agent is stopped for repeating one tool call with identical arguments (max_consecutive_repeats, default 4): the model gets one correction first, and if it asks for the same call again the turn ends — a run that finished its work and then kept re-checking it reports what it did instead of a “can’t confirm” notice. Repeats that failed or were refused get the same closing call, told what failed, and the failure is reported after the answer, so research done before the loop is kept. The same applies to one tool that keeps failing with different arguments, and to an agent that, having answered, starts work the request never asked for: the off-request call is not run, and a second one ends the turn with an answer to what you asked.
- Per-invocation: pass
--max-steps <n>togaia chat(e.g.gaia chat --max-steps 80). - Fleet-wide: set the
GAIA_AGENT_MAX_STEPSenvironment variable to change the default for every agent at once, without per-command flags.
GAIA_AGENT_MAX_STEPS value (non-integer or ≤ 0) fails fast with an actionable error rather than silently capping agents.
Per-tool execution timeout
Each tool call is bounded so a hung tool (e.g. a stuck connector or network request) surfaces an actionable error instead of leaving the agent — and the UI — stuck indefinitely. The default is 180 seconds per tool. Time a tool spends waiting for you to answer a file-access prompt doesn’t count toward it, and neither does time the PC spends in S3 sleep or hibernation. Modern Standby counts as running time.- Fleet-wide: set
GAIA_AGENT_TOOL_TIMEOUT(seconds) to change the default for every tool at once.
@tool(timeout=...) — for example image generation, which may need to download a model on first use. A tool that takes its own timeout argument, like run_python and execute_python_file, is never abandoned before the time that call asked for plus 30 seconds. For relayed agent queries, the same variable also extends the SSE idle-read budget in the daemon relay, API host, and thin client. That transport budget remains at least 300 seconds and adds a 60-second grace period above a larger configured tool timeout so the sidecar can return its own timeout error. An invalid GAIA_AGENT_TOOL_TIMEOUT value (non-numeric or ≤ 0) fails fast with an actionable error rather than silently removing the guard.
Confirming dangerous tools
Shell commands, file writes, and an agent’s own destructive tools (email send / forward / permanent delete, calendar RSVP) prompt before they run:[a]lways for <scope> and names it — a
command family such as pytest or git commit, one file, or one skill — and
a stops asking about that scope until the command exits. It is never offered
for a delete or for a command line GAIA cannot read.
When GAIA is not attached to a terminal — output piped or redirected, a CI job, a
host process — there is nobody to ask, so gated tools are denied with an
actionable error rather than run silently. For an unattended run you trust, set
GAIA_AUTO_APPROVE_TOOLS=1 in the launching environment:
.env file cannot set this variable; it must come from the real process
environment, so a project directory can never switch off your prompts.
Narrowing file access
The flagship agent can read anything under your home folder by default. To confine one run to particular folders — an evaluation run that must not read the graders’ answer keys, or a session you want kept to one project — setGAIA_ALLOWED_PATHS to absolute paths separated by ; on Windows and :
elsewhere:
- It only narrows. The agent’s scope becomes the overlap of its normal scope
and this list. An entry wider than the normal scope (
C:\,/) narrows nothing, and one outside it (another drive) is ignored with a warning — neither grants anything. If no entry overlaps, the agent can reach no files at all except its scratch folder. Out-of-scope paths are refused without an approval prompt, and full access does not lift that. - Every file tool honours it: reading, writing, listing,
tree, name and content searches (including the Documents/Downloads sweep and deep search), indexing a document, code search and its index, the project map, saving downloads, capturing a skill from a local folder, and the path checks on shell commands. The agent’s own scratch folder stays writable. - It does not sandbox code. A
run_pythonscript or a shell command the agent runs can open any file your OS account can read. This setting confines GAIA’s tools, not arbitrary code — for real isolation, run the agent as a separate OS user, in a container, or in a VM, and keep answer keys where that account cannot read them. - It is read when the agent starts.
gaia chatreads it directly, andgaia-tuipasses it to the agent it launches. A Hub-installed flagship runs under the GAIA background service, so the variable must be set whengaia daemon startruns; restart the daemon to change it. The Agent UI server reads it when it starts.
~/x included) or a folder that
does not exist stops the agent at startup with an error naming the bad entry;
GAIA never falls back to your home folder. Unset the variable to get the default
scope back.
Initialization
Init Command
New users start here! The
gaia init command is the easiest way to get GAIA running.
Available Profiles:
The
--profile flag accepts one of the following values (see
src/gaia/cli.py for the
canonical choices list):
A bare
gaia init runs the gaia profile: Lemonade, the chat model, the RAG/memory
embedder, and the flagship GAIA agent itself, installed from GAIA’s download server if it is missing. It does
not install the terminal UI (gaia-tui) — get that with npx @amd-gaia/gaia, which
fetches and verifies both binaries with no Python required.If the download server cannot be reached, gaia init still finishes the other steps, then
reports the setup incomplete and exits 1, naming the URL and the error. Fix the
network or proxy, then run gaia init again. gaia init does not upgrade an agent that
is already installed.Before it downloads anything,
gaia init adds up what the models still need and checks
it against the free space in Lemonade’s model store. When they don’t all fit, it stops
before the first download with Not enough disk space, how much the models need, how much
is free, and where, and exits 1. Each model fitting on its own is not enough. What an
interrupted download already left there counts as downloaded, so a retry asks only for
the rest. When GAIA can’t read that store (a remote server), a shortfall is a warning and
the download goes ahead.Progress events
With--progress-json, each event is one stdout line holding a JSON object with an
event key. The lines between them are the usual human output; skip any line that is
not such an object, and any event you don’t know.
gaia init picks the profile on the agent axis only. NPU users must still ask for the
device axis explicitly with gaia init --profile npu, which swaps the GGUF models for
their FLM equivalents — the default never switches your backend for you. It installs
the same flagship agent as a bare gaia init, and fails the same way
when the download server can’t be reached.Only the
gaia and npu profiles install an agent. The other model profiles set up
models only; when no agent is installed yet, they say so and name the fix,
gaia init.The
talk agent relies on the chat profile — there is no dedicated talk
profile. The default gaia profile is a superset, so a bare gaia init covers it.For the
gaia, chat, rag and all profiles the chat model follows the
hardware. Where Lemonade reports a GPU with enough memory for it — about 27 GB for
models, its 23.3 GB of weights and vision projector plus the context cache at its
smallest, 64K window, so a 64 GB+ Strix Halo or a 32 GB GPU, but not a 24 GB card or a
CPU-only PC — gaia init also sets up Qwen3.6-35B-A3B-GGUF (a 23 GB Lemonade
built-in MoE, run with thinking on, needs Lemonade v11.7.0 or newer) as the chat model,
prints why, and records it as default_model. It must also fit the memory free when
setup runs, so a PC busy with other apps keeps Gemma and says why: close them and
re-run gaia init. If setup’s verify step fails, no default model is recorded. It loads with the largest window the
memory holds, up to 262,144 tokens: 256K on a Strix Halo, about 88K on a 32 GB GPU
(see Context length follows memory). Gemma is
still downloaded, since vision and document-image extraction load it by name. Every
smaller PC gets Gemma alone. A default_model you set yourself always wins and is
downloaded instead of Gemma; questions about images then download Gemma (~6 GB) the
first time you ask one, and gaia init says so. --check asks for the same models
gaia init would download.user.Qwen3.8-Flash-Next-GGUF (an 82 GB download, multimodal, thinking on) is
available on a 128 GB Strix Halo and never auto-selected. It needs ~90 GB for models
and Lemonade v2026.39.1 or newer (its llama.cpp cannot load the model otherwise;
upgrade with gaia init --force-reinstall). Choose it with
gaia config set default_model user.Qwen3.8-Flash-Next-GGUF, or pick it in the
terminal UI’s model picker; Lemonade downloads it on first use. gaia init refuses it
on a PC that cannot hold it and names the memory it needs. To measure both on your
own PC, speed, tool calling and (with --tasks core) agent quality, run
python util/compare_local_models.py from a GAIA checkout.gpt-oss 20B (
user.ggml-gpt-oss-20b-MXFP4-GGUF, a 12 GB download, ~15 GB for models)
and gpt-oss 120B (gpt-oss-120b-mxfp-GGUF, 63 GB, ~70 GB for models, a 128 GB Strix
Halo) are supported and never auto-selected. Choose one with
gaia config set default_model <id>; see
gpt-oss 20B and 120B.gaia llm quick queries use default_model when set, else Gemma-4-E4B-it-GGUF.~/.gaia/lemonade, on a
port only GAIA uses, behind a generated API key. It needs no admin rights and
never touches a Lemonade app you installed yourself.
- GAIA's own server (default)
- Another Lemonade Server
- Starts Lemonade Server — downloads GAIA’s copy on first run (checksum-verified), then starts it. Re-running replaces an older copy or one that stopped answering.
- Downloads Models — pulls the models for the selected profile (the NPU profile also installs the FLM backend)
- Verifies Setup — tests each model with inference to detect corrupted downloads
Install Command
Install individual GAIA components.
Examples:
If a different version of Lemonade is already installed, you’ll be prompted to uninstall first.
Uninstall Command
Tiered cleanup of GAIA components. By default, the OS-native uninstall (Add or Remove Programs, drag to Trash,apt remove) only removes the app — user data in ~/.gaia/ is preserved. This command lets you escalate cleanup as far as you want.
Examples:
--purge keeps ~/.gaia itself and what is not GAIA’s to delete: your connector setup
(mcp_servers.json, connectors/, and the MCP server secrets that file names), your own
skills in ~/.gaia/skills, and any file another tool put there. The plan and the end of the
run list each kept entry. The desktop app’s ~/.local/bin/gaia shim (or $XDG_BIN_HOME/gaia)
is removed only when it is the app’s exact wrapper around this GAIA home’s venv; any other
gaia there is left alone and named.--purge also undoes what the one-line installer set up. It stops a running GAIA daemon
before deleting its state, removes gaia-tui and gaia-agent from ~/.gaia/bin, and
removes the installer’s PATH entries: the # Added by GAIA installer block in
~/.zshrc, ~/.bashrc, ~/.bash_profile or ~/.profile, or the ~\.gaia\venv\Scripts
and ~\.gaia\bin entries on the Windows user PATH. The rest of each file and every
other PATH entry are left exactly as they were. If you edited the installer’s export PATH
line by hand, it is kept and the command tells you to remove it yourself. A GAIA_HOME
other than ~/.gaia leaves these PATH edits alone, because they still point at ~/.gaia.
Open a new terminal afterwards so it stops using the old PATH.GAIA_HOME moves the directory this command deletes into, and the resolved path is printed above the plan and in the --purge confirmation prompt. It must name a directory GAIA owns, and both --venv and --purge check this before deleting anything:- If it resolves to your home directory, a directory containing it, or a drive root,
gaia uninstallrefuses and exits64rather than deleting$GAIA_HOME/documents— which on Windows and macOS is your realDocumentsfolder. - An existing
$GAIA_HOMEmust also be named.gaiaor hold something GAIA created (config.json,chat/,lemonade/,memory.db, …). A barevenv/does not count, so neither tier will eat the virtualenv of a project directory thatGAIA_HOMEhappens to point at. A$GAIA_HOMEthat does not exist yet is a no-op, not an error.
Kill Command
Stop running GAIA services.
Examples:
--daemons stops only orphaned daemons: ones whose home folder or instance.json is gone, so no GAIA command can reach them (test runs used to leave these behind). The daemon of your own home is listed but never stopped; use gaia daemon stop for that. Daemons of other homes, such as a GAIA_HOME you set elsewhere, are listed and left running. Exits 1 if an orphaned daemon would not stop.On Windows,
--lemonade also kills orphaned llama-server.exe and lemonade-tray.exe processes.--port only targets a socket that is listening on exactly that port — clients connected to it, and servers on a port that merely shares a prefix, are left alone. Before killing, it checks the owning process: GAIA’s servers run under a Python or Node interpreter, so a native service (a database, svchost, nginx) on a mistyped port gets a refusal message instead of a kill -9. Port-listing and forceful termination commands time out after five seconds and report inspection failures. If only some listeners are terminated, the command reports the killed, refused, and failed processes and exits 1. An empty port exits 0 because the requested stopped state already holds. --lemonade propagates failures from its port-based stop path. Both stop paths for the API server — gaia api stop and python -m gaia.api.app stop — use the same targeting.Agent Command
Author, version, validate, and share GAIA agents.Developer workflow: init, version, test
Scaffold a new agent package, bump its version, and run the quality gates that publishing requires. The scaffold mirrors the canonical hub package layout (hub/agents/email/python/). init and version are hidden from gaia agent -h but still work.
init scaffolds a package directory named after <name>:
- Python:
gaia-agent.yaml,pyproject.toml(with thegaia.agententry point), agaia_agent_<id>/package (__init__.py+agent.pyskeleton),tests/test_agent.py, andREADME.md. - C++:
gaia-agent.yaml,CMakeLists.txt,src/agent.cpp,tests/, andREADME.md.
Use
--layout hub when authoring a package for this repo’s hub/agents/ tree, which nests the implementation under a language directory (hub/agents/<id>/python/). Standalone packages outside the repo want the default flat layout.
version bumps the SemVer in gaia-agent.yaml and keeps pyproject.toml / __init__.py in sync.
test runs quality gates in two modes:
The publish workflow requires
--lint to pass; --live is recommended but not enforced.
Examples:
Lifecycle: configure, health, status
Manage an installed agent: set per-agent configuration, verify it loads, and inspect its state. Configuration is persisted under ~/.gaia/agents/<id>/config.json and survives restarts.
configure writes per-agent settings (e.g. a preferred model). --set values are JSON-decoded when possible (--set temperature=0.2 stores a number, --set verbose=true a boolean), otherwise kept as strings. Settings merge into the existing config by default; pass --replace to overwrite it wholesale, or --show to print the current config without changing it.
health verifies that an installed agent actually loads — its registration resolves and its entry point imports. It reports one of healthy, degraded (loads but something optional is off, e.g. a corrupt config), error (a required piece fails to load), or not_installed.
status aggregates installed version, health, config summary, and source for one agent — or every discovered agent when <id> is omitted.
Exit codes: with an explicit <id>, both commands exit 1 when that agent’s health is error or not_installed, 0 otherwise — so scripts can gate on a single agent without parsing table output. The all-agents form (gaia agent status with no <id>) always exits 0; an absent agent shows up as a row, not a failure of the listing itself.
--json emits machine-readable output instead of the table/text form, with log lines routed to stderr so stdout stays pure JSON for | jq. health --json prints one object (HealthStatus.to_dict()); status --json prints one object for a single <id>, or a JSON list of objects for the all-agents form.
Examples:
Distribution: pack, publish, login
gaia agent pack, gaia agent publish and gaia agent login are maintainer release commands. They are hidden from gaia -h and not documented here.
Installing a published agent
The two publish targets back two install paths, and both register the agent the same way — via thegaia.agent entry point, so the registry discovers it
automatically:
From PyPI (pip)
PyPI publishing for
gaia-agent-* wheels is currently paused (tracked by
#2240), so the command above doesn’t
resolve yet. Until publishing lands, install an agent straight from this repo:From source (works today)
~/.gaia/agents/<id>/ (backed by gaia.hub.installer). Install headlessly with:
gaia agent list shows what is available to install so you know which id to pass.
An installed agent shows the version on disk with an [installed] marker, plus the
catalog’s latest version when the two differ. This is the supported way to provision a sidecar
agent on a machine with no UI.
gaia agent install installs in-process. gaia hub install
performs the same install through the daemon, which additionally stops that
agent’s running sidecar first and keeps it stopped for the whole download —
the install directory is the sidecar’s own binary cache. Reach for gaia hub
when the daemon supervises the agent, and gaia agent when it does not (or
when the daemon extras are not installed). Both enforce the same --trust gate
and the same SHA-256 verification.gaia daemon start-agent <id> is an optional pre-flight to launch and
health-check it early.
Sharing: export, import
Export every custom agent installed under ~/.gaia/agents/ into a single .zip bundle, and import a bundle produced on another machine.
Import options:
Examples:
Importing a bundle runs third-party Python code on your machine.
gaia agent import shows the agent IDs in the bundle and requires explicit y/yes confirmation (or --yes) before proceeding.Core Commands
LLM Direct Query
The fastest way to interact with AI models - no server management required.
Examples:
Chat Command
Talk to the flagship GAIA agent (the same agent the TUI and Agent UI run): start an interactive conversation, or send a single message and exit.- No message: Starts interactive chat session
- Message provided: Sends single message and exits
gaia chat -q "…" > answer.txt captures
just the answer. INFO diagnostics are written only to the log file
(~/.gaia/gaia.log, or the path in GAIA_AGENT_LOG); --debug also shows them
on stderr.
Options:
Exit codes:
--query exits 0 when the agent answered, 1 when the query or the agent failed, and 130 when interrupted with Ctrl+C — so gaia chat --query "..." && next-step only runs next-step on success.
Examples:
Prompt Command
Send a single prompt to a GAIA agent.
With
--stats, the command exits 1 if the stats cannot be fetched after the answer has printed.
Examples:
Specialized Agents
Talk Command
Voice Interaction
Speech-to-speech conversation with optional document Q&A
Speech recognition (Whisper) and voice output (Kokoro) run in the same Lemonade Server as the chat model, at
--base-url; the first run downloads both models through it. The microphone is muted while GAIA speaks. Say “stop” or press Ctrl+C to end the session; gaia talk exits non-zero if the voice loop, the microphone or Lemonade’s transcription fails.
Examples:
Telegram Command
Telegram Adapter
Bridge a Telegram bot to GAIA so you can chat with your agents from Telegram.
→ Telegram Adapter Guide
Slack Command
Slack
Drive the flagship GAIA agent from a Slack direct message, over Socket Mode.
→ Slack Guide
Email Command
Email triage
The standalone email triage agent for Gmail or Outlook, with all body inference running locally on Lemonade. Needs the Google or Microsoft connector. The flagship agent reads mail too, through its own tools.
gaia email autonomy takes status, trust, set-level, pause, resume, kill and run.
→ Email Guide
API Server
API Server
OpenAI-compatible REST API for VSCode and IDE integrations
Quick Start
- Start GAIA API server — it brings up Lemonade through the daemon, at the context size your device profile pins:
- Test the server:
Commands
- Start
- Status
- Stop
--host- Server host (default: localhost)--port- Server port (default: 8080)--debug- Enable debug logging--show-prompts- Log the prompts sent to the LLM for every request (useful for debugging)--streaming- Stream tokens to clients via SSE (OpenAI-style)--step-through- Pause between agent steps for manual inspection (development aid)
GAIA_API_KEY is set, since the agent loop would otherwise be open to the
network (Authentication):MCP Client
MCP Client
Connect GAIA agents to external MCP servers
~/.gaia/mcp_servers.json by default ($GAIA_HOME/mcp_servers.json when GAIA_HOME is set), or to a custom config file using --config.
Commands
Managing MCP servers (add / remove)
gaia mcp add and gaia mcp remove were removed in #977 — MCP servers are now
configured through the connectors framework. Run gaia connectors --help for the
current commands. gaia mcp list (below) still lists configured servers.gaia mcp list
List all configured MCP servers.
--config PATH- Custom config file path (default:~/.gaia/mcp_servers.json)
gaia mcp tools
List tools available from a configured MCP server.
<server-name>- Name of the server to query
--config PATH- Custom config file path (default:~/.gaia/mcp_servers.json)
gaia mcp test-client
Test connection to a configured MCP server.
<server-name>- Name of the server to test
--config PATH- Custom config file path (default:~/.gaia/mcp_servers.json)
MCP Bridge
MCP Bridge
Expose GAIA agents as MCP servers
Quick Start
Install MCP support:Commands
gaia mcp start options
Browser origins
A web page can reachhttp://localhost:8765 from the user’s own browser, so
the bridge refuses any request whose Origin is not loopback (localhost,
127.0.0.1, [::1]) with 403, and never answers
Access-Control-Allow-Origin: *. Clients that send no Origin — curl, MCP
clients, n8n — are unaffected. To allow a browser app on another origin, list
it in GAIA_MCP_ALLOWED_ORIGINS (comma-separated).
Concurrent requests and limits
Each request runs on its own thread, so/health and /status answer while a
/llm or /chat call waits on a busy model. Calls to the same tool take turns:
/chat shares one conversation. A queued caller waits for the call ahead of it,
which can run 15 minutes or more, so give clients such as n8n a generous HTTP
timeout. A client that stops sending its headers or body
for 30 s gets 408. A request body over 1 MiB gets 413; raise the limit with
GAIA_MCP_MAX_BODY_BYTES (bytes). A request with any Transfer-Encoding
(chunked or other) gets 411; send a plain Content-Length body instead.
Authentication
The bridge is unauthenticated by default. Anything that can reach the port can enumerate and invoke its tools, which is why--host defaults to
localhost. Pass --auth-token before exposing it anywhere else:
--auth-token <token>: on Linux and macOS
command-line arguments are visible to any local user via ps.
Clients then send the token on every call:
GET /health stays public so container and orchestrator liveness probes keep
working; it reports only liveness plus agent/tool counts. Every other
endpoint — /status, /tools, /chat, /llm, and the
JSON-RPC endpoint — requires the token. gaia mcp status, gaia mcp test, and
gaia mcp agent accept --auth-token (also defaulting to
$GAIA_MCP_AUTH_TOKEN) so they can reach a protected bridge.
gaia mcp test options
gaia mcp agent
request and, optionally, a --domain (e.g. atlassian,
gaia, all) and free-form --context string to steer the orchestrator.
gaia mcp serve options
Wraps the Agent UI backend’s REST API as MCP tools, so an MCP client (Claude
Code, for example) can chat through the same backend that powers the browser
UI — conversations and tool activity show up there in real time. The Agent UI
backend (gaia chat --ui) must already be running.
Over HTTP, any request carrying a browser
Origin header is refused with 403,
so a web page can’t drive the server. A non-loopback --host is refused unless
--allow-remote is given with a token, sent by clients as
Authorization: Bearer <token>. See
Agent UI MCP Server for
the tools that run a turn unattended.
gaia mcp tui options
Wraps the TUI control API as MCP tools, so an assistant can
navigate and type in the TUI session you are watching. The TUI must already be
running with gaia tui --control; the server finds it through
~/.gaia/tui/control.json rather than a fixed port.
→ Full TUI Control MCP Guide
→ Full MCP Integration Guide
Connectors
Connectors
OAuth providers, MCP-server connectors, and per-agent scope grants
Examples:
--device flag on connect uses the RFC 8628 device-code flow instead of
the browser redirect — required for Microsoft zero-setup sign-in (no Azure app
registration or loopback redirect URI). Which authority a Microsoft connector
signs in against is fixed by the connector itself (microsoft → consumers,
microsoft_work → organizations) — to restrict microsoft_work to one
Entra tenant, set its optional Directory (tenant) ID setup field instead of an
environment variable; see the Microsoft connector guide.
→ Connectors Guide · → Connectors SDK
AMD LLM Gateway
Runs GAIA agents on gateway-hosted models — larger on-prem models and frontier models — alongside local inference. Requires Lemonade Server 11.8.0+. You enter your token once. Lemonade holds it in memory and forgets it on restart, so GAIA keeps a copy in your OS credential store (DPAPI, Keychain, SecretService) and replays it — encrypted at rest, never in a GAIA file.
Gateway models are namespaced
amd.<model> and work anywhere a local model
does. LEMONADE_AMD_API_KEY in Lemonade’s environment still takes
precedence over a stored token; if both are set, Lemonade says so rather than
silently choosing.
When a gateway model answers HTTP 404, GAIA records it. status and models then
mark it unavailable, and chat, llm, and prompt warn when it is your saved
default. GAIA never switches models for you; pick another with gaia gateway use <id>.
→ LLM Gateway Guide
Configuration
GAIA keeps a small persistent config at~/.gaia/config.json (override the
location with the GAIA_CONFIG_DIR / GAIA_CONFIG_FILE environment variables).
Use it to set a default model once instead of passing --model on every
command.
Full access
By default the agent asks before it runs a shell command or writes a file. Full access stops the asking: every gated tool runs without a prompt, and the shell guardrails come off — output redirection works, and the read-only command list is replaced by a developer set (python, pytest, node, npm,
make, go, cargo, gh, git, …) that can run arbitrary code. git is
unrestricted, including push and history rewrites. It is the only mode in which
commands GAIA otherwise refuses outright (a credential print such as
gh auth token, an encoded PowerShell command) can run.
Full access is one of three permission modes. Shift+Tab in the TUI cycles
them, and the status bar shows the one that is on:
Ways to turn full access on — each is deliberate:
Turn it on every time you launch
gaia-tui with:
Full access needs an agent the TUI launches itself. A Hub-installed flagship runs
through the GAIA background service, which doesn’t support it yet:
--full-access
is refused there, and a saved full_access leaves prompts on with a note in the
chat saying so.
This is the only thing that turns full access on without someone asking for it
on that launch, so it is read only from your own ~/.gaia/config.json — a
project-local .env or a checked-in config file can never switch off your
confirmation prompts.
Default model precedence
Forgaia chat, gaia llm, and gaia prompt, the model is resolved highest-wins:
- An explicit
--model <id>flag default_modelfrom~/.gaia/config.json- The command’s built-in default (
DEFAULT_MODEL_NAME)
default_model, then the built-in floor. So
gaia config set default_model <id> also changes what a brand-new “New
Chat” lands on, not just the CLI.
So gaia config set default_model <id> lets you skip --model entirely, while
--model still overrides it for a single run. For gaia chat, passing an
explicit --device selects a device-specific model and takes precedence over
the config default.
A missing config file is fine — GAIA falls back to built-in defaults. A
corrupt config file (invalid JSON) fails loudly with the file path and how
to recover, rather than silently reverting to defaults.
Using a custom config file
Point GAIA at a config file anywhere on disk — handy for per-project configs or keeping work and personal defaults separate. Two equivalent ways:--config wins over GAIA_CONFIG_FILE, which wins over the
default ~/.gaia/config.json.
Model Management
Download Command
Download all models required for GAIA agents with streaming progress.
Without
--host or --port, gaia download uses the same Lemonade Server as the
rest of GAIA: LEMONADE_BASE_URL if set, otherwise GAIA’s own Lemonade on whatever
port it started on (gaia lemonade embedded status shows it).
--host on its own targets Lemonade’s standard port (13305) on that host.
Available Agents:
chat, talk, rag, vlm, minimal, mcp
Examples:
List all models:
Pulling a single model
gaia download takes no model name; it fetches every model an agent needs. To
pull one model, use the client that ships with your Lemonade install — on a
current Lemonade that is lemonade pull MODEL_NAME. When a GAIA command finds a
model missing, its error names the exact command for your machine, so you never
have to guess which client you have.
Embedded Lemonade
GAIA can run its own private Lemonade Server instead of the machine-wide install. Nothing else on the machine can reach it: it binds a port of its own and requires an API key GAIA generates, so two apps never fight over one server. This is the self-contained path — GAIA downloads the server itself, no installer and no admin rights.gaia init installs and starts it; a Lemonade you installed
yourself is left alone unless you choose to use it (see
Use a Lemonade you already run).
start writes them to a file you source rather than printing the key,
so the secret never lands in terminal scrollback, shell history or a CI log:
LEMONADE_BASE_URL and LEMONADE_API_KEY, is owner-readable only,
and is deleted on stop — credentials naming a dead port are worse than none,
since whatever grabs that port next would inherit the trust. On Windows it is
env.ps1, loaded with . $HOME\.gaia\lemonade\env.ps1.
GAIA agents find the embedded instance on their own through its state file. The
env.sh / env.ps1 file is for other tools.Use a Lemonade you already run
Point GAIA at a Lemonade Server you run yourself instead of its own. GAIA then installs and starts no Lemonade at all; if yours is down, the error says so and how to start it. GAIA never changes that server’s setup: no cloud providers or keys, no backends, no saved load options, and no unloading or deleting your models. The install guide covers what GAIA does on your server.gaia config set lemonade_mode gaia is refused, with nothing
changed, until GAIA’s own server is installed; gaia init --gaia-lemonade installs
it and switches.
LEMONADE_BASE_URL wins over the saved setting.
Embedded commands
start options:
install options:
Inference backends
The downloaded server is small (~5 MB) and ships no inference backend — those are fetched separately, and only the ones your hardware needs:
GAIA’s default models (
Gemma-4-E4B-it-GGUF, embeddinggemma-300m) run on the
llamacpp backends, so CPU + Vulkan is enough for the common case:
Where it stores things
Everything lives under~/.gaia/lemonade (or $GAIA_HOME/lemonade):
Downloaded models are not duplicated: the embedded server reads the same
Hugging Face cache as every other Lemonade install, so models you already have
are picked up immediately.
cache/ is deliberately shared across versions. Backends run from 141 MB to
4.3 GB, so a Lemonade version bump re-downloads the 5 MB server, not the backends.
gaia uninstall --purge and gaia lemonade embedded uninstall remove this
directory, including those downloaded backends.gaia daemon stop, and stops it after the idle timeout like any
other — see GAIA’s Lemonade Server.
After a Lemonade version bump, stop the old instance before starting the new one —
start refuses rather than silently leaving the previous version serving:
Evaluation Commands
Evaluation Framework
Systematic testing, benchmarking, and model comparison
- Agent eval benchmark (scenario-based, end-to-end)
- Auto-fixing failures with Claude Code
- Report generation
- Performance-log visualization
Visualize llama.cpp performance logs:
git grep, scale, robustness; no LLM):
Benchmark memory over months of chats (changing facts, forgets, lessons, planted content):
→ Full Evaluation Guide
Agent Eval
Agent Eval Benchmark
Scenario-based end-to-end testing of the GAIA Agent UI
Examples:
The eval agent requires Claude Code CLI (
claude command), an Anthropic API key, and the Agent UI backend running. See the Agent Eval Guide for full setup instructions.Code Benchmark
Each task ships a project and a test suite; the agent is asked to change it and the suite decides pass/fail — no LLM judge. A TUI must already be running with a control port, since this drives that session so the run is visible.Retrieval Benchmark
Scores RAG retrieval (recall@k, MRR) separately from answer accuracy, on real documents with labelled evidence, and measures indexing and query cost as the corpus grows. See Retrieval Benchmark.Flagship Agent Tasks
Run an agent on real coding, data and Q&A tasks and score what the finished project does. CI gates on passes, tested changes, quality, honesty, tokens, steps and runtime, against main’s committed results.
SWE-bench Verified. The
swebench suite builds its tasks from real upstream issues, and grading runs the official harness in Docker. run grades as it goes; pass --no-evaluate to capture the predictions now and grade them later on a machine that has Docker:
→ How tasks are scored and gated · → Comparing harnesses and models
Email Throughput Benchmark
Measure end-to-end email-triage throughput (tokens/sec), time-to-first-token, and pipeline latency for an on-device model. Direct-drives the email agent over the committed synthetic corpus and harvests metrics from the agent’s per-step stats. The committed bar is ≥10 tok/s (snappy-UX stretch ~30 tok/s); the benchmark is non-gating — a miss is reported, not failed.Runs from a GAIA repo checkout (it drives the synthetic corpus in
tests/fixtures/email/) and needs Lemonade serving the target model. Run at most one gaia eval process at a time against a single Lemonade server.Performance Visualization
Plot llama.cpp server performance metrics from one or more log files. Plots are saved as images; pass--show to also display them interactively.
Examples:
Memory
Agent Memory Guide
Persistent second brain — remembers facts, preferences, and workflows across sessions
Commands
- status
- bootstrap
Show aggregate memory statistics.Output includes:
- Knowledge entries by category (fact, preference, error, skill) and context
- Search-vector coverage, and how many entries are Without vector (saved while the embedding model was unavailable, so only keyword recall finds them) with how to re-embed them
- Conversation count and session history
- Tool call success rates and error counts
- Upcoming and overdue time-sensitive items
- Database size
Skills
Agent Skills Spec
Portable
SKILL.md capabilities — instructions, optional typed tools, and resources an agent loads only when relevantSKILL.md; GAIA implements the Agent Skills open standard, so a Claude Code skill loads unchanged.
Subcommands
- list
- info
- deltas
- create
- import
- export
- audit
- migrate
- search
- install
- lock
- promote
- publish
- keygen / trust
4. One under the read-only claude-import roots belongs to another tool, so it is listed as a warning (import_errors in --json) and does not change the exit code.Security tiers at install
Three tiers set the install-time permission ceiling. A skill’s front matter states the tier it wants; its signature decides the tier it gets.
The effective tier is
min(claimed, attested), so no unsigned skill installs as
verified — the claim is collapsed rather than trusted. Imported and captured
skills (gaia skill import, capture_skill) always land experimental. The ceiling
is checked again whenever a skill loads or is promoted, against the tier it landed
at, so editing SKILL.md afterwards cannot raise its tier or its grants.
skill-lock.json
Hub installs are tracked in ~/.gaia/skills/skill-lock.json. Discovery answers
what is on disk; the lock answers what was requested, what resolved, what
the artifact and the installed files hashed to, who signed it, and which
tier it was installed at after the ceiling was applied:
gaia skill install writes source: "hub" entries, and gaia skill import
writes source: "imported" ones held at experimental. A skill from create
has no provenance to record; gaia skill lock --relock may record it as
source: "local", which claims exactly the origin it has. Relock never raises
the tier of a hub, imported, or captured entry.
content_digest covers the installed directory (after the tier re-stamp), not
the downloaded archive. That is what makes post-install tampering detectable:
gaia skill lock compares against it, and a community / verified skill whose
files no longer match refuses to load — those bytes are not the ones the
signature covered, so the tier badge no longer means anything. An experimental
or locally-authored skill warns and keeps working; nothing attested it, and
editing a skill you wrote is the normal workflow.
skill-lock.json has no integrity protection of its own — anyone who can write
to it can rewrite a digest. It defends against tampering with the skill
directory (a swapped bundle, an edited manifest, a downgraded version), which
until now was entirely silent.0 success · 2 missing/unknown subcommand · 3 skill not found · 4 invalid skill (bad manifest, name collision without --force, or a GAIA discovery root containing a malformed skill — a malformed claude-import skill is only a warning).
Loading a skill into an agent
Skills are never globally active — an agent loads one explicitly, and its tools register under a<skill-name>/<tool> namespace:
gaia-agent.yaml and write no Python at all:
Agent subclass resolves this block at construction, so a custom agent
under ~/.gaia/agents/<id>/ consumes an installed hub skill by dropping a
gaia-agent.yaml beside its agent.py — no code change, no registration call.
Resolution mirrors agent dependencies:: highest installed version satisfying the
range, tool providers ordered before their consumers, and fail-loud on a conflict
or a dependency cycle. A missing required: true skill raises with the
gaia skill install command that fixes it; a missing optional one is logged and
skipped. Set AUTOLOAD_DECLARED_SKILLS = False on the class to opt out and call
load_declared_skills() yourself.
Schedule
Run a prompt on a recurring cron schedule and route its output to a sink. Schedules are stored in~/.gaia/schedules.toml (hand-editable). The daemon action runs a long-lived scheduler that fires each enabled schedule when due.
The running daemon reloads schedules every second, so adding, pausing, resuming, removing, or editing a schedule does not require a restart. Pausing or removing a schedule prevents future runs; it does not interrupt a run already in progress.
A run that comes due while the daemon is running but the machine is asleep or busy still fires once the daemon catches up, as long as that is within an hour of the due time; several missed runs collapse into one. A run more than an hour late, or one that comes due while the same schedule’s previous run is still going, is skipped and logged at WARNING with the schedule name. A run that came due while the daemon itself was not running is not replayed on restart.
Runs that never happened are not silent: the ones a sleep skipped or collapsed, and the ones due while the daemon was not running, are counted on the schedule. gaia schedule show prints the total, missed: 3 runs in all while the PC was off or asleep, or the schedule daemon wasn't running (latest due …), and gaia schedule list adds missed=3. Runs due while a schedule was paused are not counted. The total is kept until the schedule is removed; past 100,000 in one stretch it reads “at least”, and the latest due time is still exact. Times are shown in local time.
Only one gaia schedule daemon can run per schedule store. A second one exits immediately with an error instead of firing every schedule twice. The daemon holds ~/.gaia/schedules.lock while it runs; the OS releases it when the process exits, even after a crash. On Windows that error names no pid — Windows refuses another process’s read of the locked byte, so the holder is unknowable.
Subcommands
add Options
Examples:
Sinks
A sink decides where each scheduled run’s output goes. Set it with--sink on add (default stdout). add rejects a sink that could never deliver (an unknown name, telegram without --to, bare file without a path, or notification on Windows) and stores nothing. The Telegram bot token is only checked when a run delivers, because the daemon reads it from its own environment.
Telegram example:
--skill is not yet implemented — gaia schedule add --skill is rejected with an error at add time. The skills runtime has shipped (#888), but the scheduler is not wired to it yet. Use --prompt for now.Utility Commands
Stats Command
View performance statistics from the most recent model run.0 and says so when no run has recorded stats yet. If the stats cannot be fetched — for example, the LLM server is unreachable — it prints the cause to stderr and exits 1.
Test Commands
Run various tests for development and troubleshooting.- TTS Tests
- ASR Tests
Test Types:Test streaming:Generate audio file:
tts-preprocessing- Test TTS text preprocessingtts-streaming- Test TTS streaming playbacktts-audio-file- Test TTS audio file generation
--test-text- Text to use for TTS tests--output-audio-file- Output file path (default: output.wav)
YouTube Utilities
Download transcripts from YouTube videos.--download-transcript- YouTube URL to download transcript from--output-path- Output file path (defaults to transcript_.txt)
Daemon Command
Manage the headless custody daemon — the always-on, single-instance background process that supervises agent sidecars (spawn, health, tree-kill; email is the first) and that later Agent UI v2 phases (/host/v1/* custody, the
model-slot broker, the scheduler clock) mount into. The Agent UI backend is a
daemon client: it asks the daemon to ensure a sidecar and talks to the
sidecar directly, so closing the UI leaves the sidecar running — stopping
is a daemon command.
The daemon also serves a streaming data plane: ANY /v1/<agent>/* (e.g.
POST /v1/email/query) is reverse-proxied to that agent’s running sidecar,
SSE relayed unbuffered, with cancel propagated on client disconnect and a
synthetic terminal error event if the sidecar crashes mid-stream. Clients
authenticate every route — control plane and data plane alike — with the
daemon client token from ~/.gaia/host/instance.json; the per-sidecar bearer
is injected by the daemon and never leaves it for relayed traffic.
Requires the daemon extras (fastapi/uvicorn/psutil) — install with
pip install "amd-gaia[api]" (or [ui], which adds the Agent UI’s RAG stack on
top). The one-line installer already does this. Running it on a base install
fails loudly with that instruction.
GAIA’s Lemonade Server
The daemon owns GAIA’s own Lemonade Server (the onegaia init installs). It
starts it when it comes up, and again whenever a GAIA app or command needs it,
so it is back after a reboot without running gaia init. It also frees the
server’s memory when GAIA is not in use:
- Closing the last GAIA app unloads every model. The Agent UI (desktop app
or
npx @amd-gaia/agent-ui) andgaia-tuiregister with the daemon while they run. When the last one exits, and nogaiacommand or sidecar agent is still using the server, the daemon unloads all of its models. The server stays up, so the next launch only reloads the model. An app that is killed rather than closed is noticed within about five seconds. - Every GAIA process holds a lease while it uses the server. Each client
of the server registers on its own: apps,
gaiacommands, sidecar agents, and a process under anotherGAIA_HOMEwhoseLEMONADE_BASE_URLnames this server (it registers with this daemon too). A lease is renewed every 30 seconds and dropped when its process exits or stops renewing for two minutes. - No lease and no request for 15 minutes stops the server. The daemon also
reads the server’s own activity, so a request from a process it does not
know about restarts the clock, and nothing is stopped or unloaded while a
request is in flight. Fifteen minutes balances freeing GPU memory for other
apps against the 20 to 60 seconds a cold model load costs. Change it with
gaia config set lemonade_idle_timeout_minutes <minutes>, or turn it off with0. - A stopped server comes back on the next request. A GAIA process that finds the server gone mid-request has the daemon start it again and sends the request once more, so the turn still answers. A stream already under way is not replayed.
- A server that is briefly not answering is waited for. A request, a
/modelswitch, or a CLI command such asgaia llmthat finds GAIA’s server unreachable shows “Reconnecting to the model server…” and waits up to 60 seconds from finding it gone while the daemon brings it back, then carries on. A new agent session waits the same way while it starts, but only logs the message. If the server is not back by then, the request fails with an error that says so and points atgaia daemon status. A Lemonade you run yourself, or oneLEMONADE_BASE_URLnames, is never waited on. - Closing a TUI session never stops the server other sessions use. On Windows the daemon and GAIA’s server leave the session’s process group when its agent starts them, so they keep running for every other session.
gaia daemon stopstops the server, whoever started it, including the one first-time setup starts. If the daemon is not running, it still stops GAIA’s server.- A server a crashed daemon left behind is taken over by the next daemon while it still answers, and stopped and replaced when it does not.
lemond binary under ~/.gaia/lemonade/dist/, on the recorded port, with the
recorded API key. A process that reused the recorded pid, or a Lemonade you
run yourself, is never killed.
If GAIA’s server crashes, or is killed without its child processes, its
model servers (llama-server and the like) can keep running and holding
their memory. GAIA stops them the next time it starts its server, or when it
finds the server gone. It stops a process only when it runs from
~/.gaia/lemonade/cache/bin and the process that started it has exited. A
tool from that folder that you run yourself, such as llama-bench, is left
alone while the shell that started it is open.
The daemon never installs Lemonade, never restarts a server that is slow to
answer while its owner is running (it may be loading a model), and never
replaces one running a different version. Those need gaia init. With
LEMONADE_BASE_URL set, or lemonade_mode set to external, it leaves
Lemonade alone entirely: no unload, no idle stop, no gaia daemon stop.
Switching to your own server stops GAIA’s; switching back starts it again.
Model-slot serialization
Lemonade is single-tenant per model slot: a second process loading a different model evicts the first. The daemon therefore runs a model-slot broker that hands out one lease at a time, so model loads queue instead of racing. When a daemon is running,gaia commands and the Agent UI backend attach to it
automatically and take a lease around each model load and request. Interactive
chat turns take priority over background work (memory extraction, embedder
warm-ups, autonomous briefs).
A request that has to wait is queued, not failed:
- It waits for as long as the request ahead of it holds the slot. The holder renews its lease every 15 seconds. One that stops renewing for a minute (it exited) is dropped and the queue moves on. One that keeps renewing past the time its own request is allowed (its request timeout, the two-minute retry window, and 15 minutes for a model load) is wedged, and loses the slot too.
- Background work (memory extraction, document indexing) that has waited ten minutes goes ahead of newer chat turns, so it is never starved.
- While an Agent UI turn waits, it shows
Waiting for the model — <who> is using itwith its place in line and seconds waited, updated every two seconds, and the wait never counts toward the turn’s idle stop. Agaiacommand prints⏳once. The gaia agent’s/querystream, which the terminal UI reads, carries the same wait as amodel_queuestatus (seedocs/spec/agent-ui-query-sse-contract.md§4.4). - Pressing Stop in the Agent UI, cancelling a
/queryrun, pressing Ctrl+C, or closing the app takes the request out of the queue, so the slot never goes to a caller that has left. Indexing a turn started keeps going after the turn ends. - To cap the wait, set
GAIA_MODEL_LEASE_WAIT_Sto a number of seconds. Past it, the request fails with where it stood in line and who held the model. - If the daemon stops sending queue updates for 30 seconds, the request fails and names the daemon as the cause.
gaia daemon status. A daemon left running at an incompatible version is
reported as a warning and loads proceed unbrokered; gaia daemon restart
restores serialization.
A daemon that is running but slow to answer is not killed for it. GAIA
gives it 10 more seconds, then reports it busy: commands fail with an error
naming its pid, and gaia daemon status shows running, but not answering.
Its status check waits on nothing else, so a daemon that has not answered it
for two minutes, across probes no more than a minute apart, is hung: the next gaia daemon start (or any command that
starts the daemon) replaces it, and gaia daemon restart does so at once. A
daemon whose port refuses connections, answers as something else, or whose pid
now belongs to another program is replaced right away. An exiting app does not
wait on a busy daemon.
A daemon also shuts down on its own, logging why, within a few seconds of its
home folder or
instance.json being deleted, since no GAIA command can reach it
after that. A daemon for any home other than ~/.gaia (a scratch GAIA_HOME,
say) also shuts down after 120 minutes with no client connected, no sidecar busy
and no scheduled job pending, and the next GAIA command starts a fresh one. Set
GAIA_DAEMON_IDLE_EXIT_MINUTES to change that limit, or 0 to keep it running.
The daemon for ~/.gaia never idles out. gaia kill --daemons finds and stops
any that are still left.
Daemon HTTP surface (the daemon serves no OpenAPI schema, so this is the
contract; every route needs Authorization: Bearer <token> from
~/.gaia/host/instance.json):
Hub Command
gaia hub is hidden from gaia -h but still works. Use it for scripted installs of
extra agents such as email from GAIA’s download server (https://hub.amd-gaia.ai).
The flagship GAIA agent comes from gaia init, not from here.
~/.gaia/agents/<id>/. Every artifact is checked against its
SHA-256 before it is written; a mismatch fails the install and leaves nothing behind.
Install and uninstall stop a running sidecar first, and two installs of the same agent
never race (the second gets a clean “already in progress” error). Requires the daemon
extras (pip install "amd-gaia[api]").
A Python agent’s install waits up to 5 minutes when another install holds uv’s
package cache (GAIA sets UV_LOCK_TIMEOUT for uv, keeping a shorter value of your
own). While it waits, the install status reads “waiting for another install to
finish”; if the cache is still taken, it stops with an error saying so. An install
that does no work (no CPU or disk activity) for 900 seconds is stopped as stuck
(GAIA_HUB_PIP_TIMEOUT changes that window), and one still running after 2 hours is
stopped however busy it looks (GAIA_HUB_PIP_MAX_SECONDS changes that ceiling).
Either way, everything the install started is stopped and the install is rolled back.
Any agent outside the verified security tier runs third-party code on your machine,
so the daemon refuses it with HTTP 403 until you pass --trust. The error shows
the agent’s publisher and security tier and names the --trust re-run.
gaia agent install <id> does the same install in-process, without the daemon.
Prefer gaia hub when the daemon supervises the agent (today: email).Terminal UI (gaia tui)
gaia tui is the Go/Bubble Tea terminal client: it boots straight into the
flagship gaia agent’s chat, behind a readiness gate. Building from source the
binary is tui/bin/gaia-tui (cd tui && make build).
The binary accepts a leading
tui word and drops it, so gaia tui status
and gaia status are the same command. Running the source build directly,
both ./tui/bin/gaia-tui tui status and ./tui/bin/gaia-tui status work.
Options accepted by every
gaia tui command:
There is no
list, install, uninstall, or hub subcommand — the TUI does
not install agents. Installing the email sidecar is the Python CLI’s job
(gaia hub install email --trust, see Hub Command).
run --query is a real one-shot
--query does not open the alt screen. The answer goes to stdout, progress to
stderr, and the exit code is 0 on a terminal answer, 1 on an error, and 3
when a confirmation gate held back a destructive action — so gaia tui run email --query "…" > answer.txt captures exactly the answer:
--timeout 90s / --timeout 2h to change it — so an agent that accepts the query and then stops answering is
reported with what to read next instead of hanging a CI job until the job’s own
timeout kills it. There is no “wait forever”: --timeout 0 is refused. Interactive
gaia tui run <id> is unaffected — a person can read what arrives and press
ctrl+c.
Readiness gate keys
In chat,
/provider opens the same provider panel with masked key entry and a
searchable model list. See AI providers for credentials,
the recommended Fireworks models, and gateway settings.
Waiting on a consequential readiness problem
Most readiness rows that cannot be verified are named on screen and the launch continues — the sidecar itself does not treat them as fatal (an unadvertised Lemonade version, for instance). A handful are consequential enough to hold instead: right now, a model loaded into a smaller context window than this machine’s profile expects, since a document-sized request against it comes backcontext_length_exceeded rather than an answer. When
that happens the screen waits for enter instead of proceeding on its own,
and the notice lists every such row at once if more than one applies.
Theme (light vs dark terminals)
The TUI asks the terminal for its background colour on startup and picks a light or dark palette to match, so text stays readable either way. Over SSH, inside tmux, or in a CI log where the terminal never answers that query, force a mode instead of guessing:GAIA_TUI_THEME also accepts auto (the default) to re-enable
detection.TUI Control API
The terminal UI (gaia tui, the Go/Bubble Tea binary) can expose a loopback
HTTP API that drives the session you are looking at — not a headless copy.
An assistant navigates, types, and drives the readiness gate while the frames
render in your terminal in real time. It is how the TUI gets tested without a
human at the keyboard.
Off by default. Bound to 127.0.0.1 only, and every request needs a bearer
token.
These are persistent flags on the TUI binary’s root command, so they apply to
the bare launch,
run, and chat alike. Building from source, that binary is
tui/bin/gaia-tui (cd tui && make build).
On start the TUI writes
~/.gaia/tui/control.json (mode 0600) holding the
pid, port, and token, and removes it on exit. Clients find the TUI by reading
that file — the token is never printed to the terminal. A client must verify
both that the recorded pid is alive and that /control/v1/status answers
with a matching pid before trusting the port: after a crash the file can point
at a port some unrelated process now owns.
Endpoints (all under /control/v1, all requiring Authorization: Bearer <token>):
Errors come back as
{"error": {"code", "message", "hint"}}; a /wait timeout is
HTTP 408 and carries the screen it saw.
Two response details matter when driving this:
settledon/keys,/text, and/resize. The call returns only once every injected key has been consumed and redrawn, so reading/screenstraight after is race-free.settled: falsemeans the model was still busy — the input is queued, so re-read rather than assume it was ignored. It does not promise the consequences are done: pressingenterto launch an agent is consumed immediately, while the view switch it kicks off lands later. Use/waitfor anything asynchronous.- HTTP 503
not_runningwhen the TUI’s event loop is not consuming input — it is still starting, or the user has quit. Bubble Tea silently drops messages in that window, so the API refuses instead of reporting a success for keys that went nowhere. Reads (/status,/screen,/frames) keep working.
esc is not universally “go back”: on the readiness gate it quits (there is no
screen behind it), in an idle chat it clears the composer, and mid-turn it cancels
the turn. A driver should read view and act on that rather than assume what esc
does.
Most callers should not speak this API directly — the
TUI MCP server wraps it as MCP tools.
TUI Event Trace
--trace writes down what the agent actually did, so a wrong answer can be
diagnosed from a file instead of from a screenshot. Every event the TUI receives
is appended to a JSONL file — one JSON object per line, in arrival order, with
tool calls carrying their arguments and tool results carrying their
payloads.
trace → …). An unwritable path is a startup
error, not a warning: a trace that is silently not being written looks exactly
like an agent that did nothing.
The path must be attached —
--trace=run.jsonl, not --trace run.jsonl.
A spaced value is read as a command name (the flag is legal with no value, so
it never consumes the next argument); the TUI says so and names the working
form.unparsed (the raw text) instead of event, or
unparsed_b64 when the bytes are not valid UTF-8, since encoding those as a
JSON string would replace each bad byte with U+FFFD and lose what went wrong.
A reader must check all three keys. Events are flushed one at a time, so a run
that crashes mid-turn still leaves everything it received.
--trace and --dev are independent: --dev chooses what is rendered on
screen, --trace chooses what is written to disk. Use both together to watch a
run and keep it.
This records the agent’s externally visible behaviour — tool calls, arguments,
results, errors, and timings. It does not capture prompt size or token
accounting, which exist only in the agent’s own per-turn recorder
(
GAIA_TURN_LOG).~/.gaia/traces is never pruned otherwise — delete old runs yourself, or
remove them all with gaia uninstall --purge.
Cache Command
Inspect or clear GAIA’s on-disk caches (document-Q7 metadata, chat history, context7 library docs, etc.). Caches live under~/.gaia/cache/ (Windows:
%LOCALAPPDATA%/gaia/cache/).
Flags for
clear:
Examples:
Knowledge Command
Web research via Tavily, with SQLite result caching, a per-session credit budget, and an automatic keyless DuckDuckGo fallback when themcp-tavily
connector isn’t configured. See the Tavily connector.
Options:
Examples:
search automatically degrades to DuckDuckGo when the mcp-tavily connector isn’t
configured; extract requires Tavily and raises an actionable error otherwise. Configure
the connector with gaia connectors configure mcp-tavily --set TAVILY_API_KEY=tvly-....
Kill Command
Terminate processes running on specific ports.
Examples:
- Find the process ID (PID) bound to the specified port
- Forcefully terminate that process
- Report killed, refused, and failed listeners; exit 1 on any refusal or failure. An empty port is a successful no-op (exit 0). Listing and forceful termination commands each have a five-second timeout.
Diagnostics Command
Bundle system info and logs into a tarball for bug reports.
Examples:
- System info snapshot: OS version (
uname -aand distro on Linux,sw_verson macOS,veron Windows), relevant env vars with secrets redacted, the pid and port of the GAIA daemon, GAIA’s Lemonade and the Agent UI backend with what listens on them, and all TCP listeners (ss -tlnpon Linux,lsof -iTCP -sTCP:LISTENon macOS,netstat -anoon Windows) ~/.gaia/electron-install-state.json(no chat content)- Log files, omitted with
--no-logs:~/.gaia/gaia.log, the Electron logs (electron-install.log,electron-main.log,electron-updater.log),~/.gaia/logs/*.log, the daemon log (~/.gaia/host/daemon.log), GAIA’s Lemonade log (~/.gaia/lemonade/lemond.log) and agent sidecar logs (~/.gaia/agents/*/logs/*.log), each with its rotated copies (gaia.log.1, …). A log over 50 MB is bundled as its last 50 MB, named<file>.tail.
lemonade/state.json, host/instance.json) are never bundled.
Global Options
Most commands support these options. They come from a shared parent parser, so despite the name they are not accepted bygaia agent, gaia cache,
gaia config, gaia connectors, gaia daemon, gaia diagnostics, gaia engineering,
gaia gateway, gaia hub, gaia init, gaia knowledge, gaia lemonade, gaia memory or
gaia skill — passing one there fails with unrecognized arguments.
On commands with a nested subcommand, put these before the subcommand —
gaia eval --no-lemonade-check agent, not gaia eval agent --no-lemonade-check —
because the nested parsers don’t inherit the shared parent. gaia mcp start is
the one exception: it declares them itself, so there they must come after
(gaia mcp start --no-lemonade-check).Troubleshooting
Connection Errors
Connection Errors
Connection errors mean the model server isn’t up. The daemon owns it, so
check there first, then start it:If it still won’t come up,
gaia daemon logs --lines 100 has the reason —
most often that Lemonade isn’t installed, which gaia init fixes.Model Issues
Model Issues
Check available system memory (16GB+ recommended)Verify model compatibility:Pre-download models:Install additional models: See Features Guide
Audio Issues
Audio Issues
List available devices:Verify microphone permissions in Windows settingsTry different audio device indices if default doesn’t work
Performance
Performance
For optimal NPU performance:
- Disable discrete GPUs in Device Manager
- Ensure NPU drivers are up to date
- Monitor system resources during execution
See Also
Voice Interaction
Speech-to-speech conversation
API Server
OpenAI-compatible REST API
MCP Integration
Model Context Protocol
Evaluation Framework
Testing and benchmarking
Agent Memory
Persistent memory across sessions
Agent Skills
Portable SKILL.md capabilities
Developer engineering
gaia engineering --developer-mode manages explicit Claude Code/Codex handoffs —
snapshot-only sharing of GAIA context, gated behind --developer-mode and a fresh
consent prompt on every share. Normal mode exposes none of this. See the
developer engineering guide for the full workflow.
Subcommands
gaia mcp engineering --developer-mode --backend <claude|codex> starts its local
stdio bridge with the pairing credential supplied through its generated MCP configuration.
Normal mode cannot start this bridge. gaia-tui --developer-mode enables the
flagship skill and sharing tools; --dev remains diagnostic output only.