@amd-gaia/gaia 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,244 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@amd-gaia/gaia` are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this package adheres
5
+ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [0.1.1] — unreleased
8
+
9
+ First working release. `npx @amd-gaia/gaia` is now the single command that gets a
10
+ user running GAIA: it fetches and verifies everything GAIA needs and drops them
11
+ into the terminal UI. Before this there was no packaged path at all — the flagship
12
+ agent had to be run from a repo checkout with a Python environment, and reaching
13
+ the terminal UI meant building it from source.
14
+
15
+ ### Fixed
16
+
17
+ - Windows npm launchers now find the Python daemon CLI even when npm passes the
18
+ package script as argv[1], preserving unrelated tools in shared PATH directories.
19
+
20
+ ### Added
21
+
22
+ - **Image generation, reachable out of the box.** "Draw me a red bicycle" now
23
+ generates a PNG with local Stable Diffusion and reports the path; previously
24
+ the tools existed behind a flag nothing turned on, so the agent just said it
25
+ couldn't. Adds `generate_image`, `list_sd_models`, and `get_generation_history`
26
+ (70 tools → 73) plus an `image_gen` bundle so per-turn selection can find them.
27
+ Generating swaps the resident model, so the next reply waits for the chat model
28
+ to reload. The `image-gen` starter skill covers prompt expansion and iterating
29
+ on the previous image.
30
+ - TUI provider setup for Local, Fireworks AI, and AMD LLM Gateway, with masked
31
+ runtime API keys, discovered models, and remote-inference status.
32
+
33
+ - **A project map at task start.** In a code repository the agent now opens
34
+ every task knowing the directory shape, the likely entry points, which
35
+ commands are installed, and the three platform differences that change
36
+ command syntax — instead of discovering each one through a failed tool call.
37
+ Capped at 600 prompt tokens. If the repository has no code index the map
38
+ starts one in the background; `GAIA_PROJECT_MAP_AUTO_INDEX=0` turns that off,
39
+ and `GAIA_PROJECT_ROOT` picks the project when the working directory is not
40
+ it. See SKILL §11.
41
+ - **`503` from `/query` at session capacity.** When every retained session
42
+ slot is busy and none is idle enough to evict, starting a new session
43
+ returns `503` with the reason in `detail` — retryable, distinct from a
44
+ bug-shaped `500`. See SPEC §5.2.
45
+ - **Three further client-visible refusals from `/query`.** Reusing a `run_id`
46
+ that is still in flight gets `409` — it used to replace the live run, leaving
47
+ it with no way to be cancelled. Supplying a `model` that differs from the one
48
+ the `session_id` was built with gets `409` rather than silently answering on
49
+ the old model. A request with an absent or empty `Host` header gets `400`
50
+ rather than being served, closing a DNS-rebinding check that failed open.
51
+ See SPEC §5 and §5.2.
52
+ - **Per-turn skill-body selection.** A loaded skill stays loaded, but its body
53
+ only renders in the prompt on turns whose query matches its description; the
54
+ rest collapse to a one-line menu the model re-activates with `load_skill`.
55
+ `GAIA_DYNAMIC_SKILLS=0` turns the selection off, `GAIA_DYNAMIC_SKILLS_TAU`
56
+ overrides the match threshold, and an embedder outage disables it for the
57
+ session (every body renders — capability is never lost to a failed match).
58
+ - **Per-turn tool selection, now on by default for the flagship `full`
59
+ profile.** The model is sent at most 26 of its 71 tools on any one call — a
60
+ fixed core plus whichever cohesion bundles the query matched — instead of the
61
+ whole registry every time. No capability is lost: `load_tools` is an escape
62
+ hatch the model calls mid-turn to pull in a bundle the selector missed.
63
+ `GAIA_DYNAMIC_TOOLS=0` turns the selection off, `GAIA_DYNAMIC_TOOLS_MAX`
64
+ moves the cap and `GAIA_DYNAMIC_TOOLS_TAU` the match threshold.
65
+ - **One bundled skill ships enabled: `gaia-voice`.** It is a manifest `skills:`
66
+ entry, so it is always on and rendered in full on every LLM call — 676 tokens
67
+ of every prompt, and it declares no tools. It is the agent's honesty floor
68
+ (don't claim work you didn't do, don't present empty output as a result,
69
+ don't substitute a near-miss and report success), which is why it is not in an
70
+ opt-in bundle the way a task skill is. No *skill set* ships enabled: the
71
+ manifest's `skill_sets:` / `default_skill_set:` blocks stay commented out until
72
+ an eval measures what loading several bodies costs. See SKILL.md §10.
73
+ - **A materially smaller fixed prompt on every call.** That always-on
74
+ `gaia-voice` guidance was rewritten from 2,129 tokens to 676 with all of its
75
+ behavioural rules intact. It had been a rationale document — every rule
76
+ followed by the incident that motivated it — and the model needs the rule,
77
+ not the incident report.
78
+ - **`gaia run` (the default command)** — resolves the host platform, fetches and
79
+ SHA-256 verifies both binaries, then launches the terminal UI and propagates its
80
+ exit code. Arguments after a bare `--` are forwarded to the TUI verbatim.
81
+ - **Dual-binary delivery.** The package installs two published artifacts: the
82
+ frozen agent sidecar (`gaia-agent`), published by this package's own release,
83
+ and the terminal UI (`gaia-tui`), which is the published **`terminal-hub`**
84
+ component. The TUI is consumed, not rebuilt — it is byte-for-byte the binary a
85
+ full GAIA install runs as `gaia tui`, so an npm user and a core user cannot end
86
+ up on terminal UIs that behave differently. A second build under this package's
87
+ own lane would have been the same bytes at a different version under a third
88
+ naming convention, and the two would have drifted.
89
+ - **`binaries.lock.json` `schemaVersion` 3.0** — a component-keyed checksum
90
+ manifest where **each component carries its own `componentVersion`, `baseUrl`
91
+ and `platforms`**. Component-first rather than the email agent's flat `binaries`
92
+ map because the two differ in every dimension: hub lane, version, and platform
93
+ coverage (terminal-hub covers arm64 Linux and arm64 Windows; the PyInstaller
94
+ sidecar does not). A single shared base URL cannot address two lanes, so a
95
+ `1.x`- or `2.x`-shaped lock is rejected at load with an error naming the schema.
96
+ - **Terminal-hub artifact naming is handled in data.** That lane names its Windows
97
+ builds `gaia-win-x64.exe` / `gaia-win-arm64.exe`, while platform keys come from
98
+ `process.platform` and say `win32`. The lock keeps the `win32-*` key and carries
99
+ the hub's spelling in `filename`, so nothing branches on platform to construct a
100
+ URL. The mapping is asserted on both sides (`TUI_ARTIFACT_NAMES` in
101
+ `src/platform.ts` and in the lock generator) because a wrong name there is not a
102
+ build failure anywhere — it is a 404 on a user's first run.
103
+ - **Mandatory SHA-256 verification.** Every download is hashed and compared
104
+ against the lock before it is written. A mismatch deletes the download and
105
+ raises `IntegrityError` naming expected vs actual. A placeholder hash blocks the
106
+ fetch before any network call. There is no flag that relaxes either.
107
+ - **`gaia fetch`** — download and verify without launching; prints JSON. Supports
108
+ `--component` and `--platform` for cross-platform staging in CI.
109
+ - **`gaia serve`** — run the agent sidecar alone on `127.0.0.1:8141` for
110
+ integrators who want the REST surface without a daemon or a UI. Health-polls
111
+ `GET /health`, checks the contract version, and tree-kills on exit. Port `4001`
112
+ is refused.
113
+ - **`gaia version`** — prints, per component, its version, the URL it is fetched
114
+ from, and its platform matrix.
115
+ - **Programmatic exports** — `fetchAll`, `startSidecar`, `shutdown`, `runTui`, the
116
+ platform helpers, and the typed error classes, for embedding GAIA in another
117
+ app.
118
+ - **The `.installed` record is written after a verified sidecar install.**
119
+ Staging the binary was only half an install: the daemon and the terminal UI
120
+ both key "this agent is installed" on `~/.gaia/agents/gaia/.installed`, and
121
+ without it the UI ran the REST sidecar as its own stdio child and the chat
122
+ filled with uvicorn's startup log. It is written on a cache hit as well as a
123
+ fresh download, so an install left by an earlier version repairs itself, and
124
+ only for this host's own platform — a `--platform` fetch stages a binary for a
125
+ different machine and records nothing. See SPEC §4.1.
126
+ - **`--allow-insecure-base-url`** — opt-in for a non-`https` `--base-url`, for a
127
+ trusted local mirror.
128
+
129
+ ### Changed
130
+
131
+ - **A `LEMONADE_BASE_URL` that already carries a path is now used exactly as
132
+ written.** Previously any URL not ending in `/api/v1` had that suffix appended,
133
+ so a reverse proxy configured as `https://proxy.example/lemonade` was silently
134
+ rewritten to `https://proxy.example/lemonade/api/v1`. It now resolves to
135
+ `https://proxy.example/lemonade` unchanged, and only a bare origin with no path
136
+ at all gains `/api/v1`. If a proxied install starts returning `404` after
137
+ upgrading, append the API path to the variable yourself.
138
+
139
+ ### Fixed
140
+
141
+ - **A second `gaia serve` no longer reports success against a server it does not
142
+ own.** With the port already taken, the incumbent answered `/health` while our
143
+ own sidecar was still unpacking, so the start "succeeded", printed a ready URL
144
+ for someone else's server, and the child then died of `EADDRINUSE`. The port is
145
+ now checked before anything is spawned, and a taken one fails naming the port
146
+ and how to find the process holding it.
147
+ - **Importing the package no longer changes a host app's error handling.** The
148
+ crash and signal handlers reaped every sidecar *before* checking whether the
149
+ host had its own handler, so an exception the host handled killed the sidecar
150
+ and the host's next request got an unexplained `ECONNREFUSED`.
151
+ - **`gaia run` no longer breaks the terminal UI's `PATH`.** Hiding our own `gaia`
152
+ shim removed the whole bin directory, which on a Homebrew or pipx layout also
153
+ took `python3`, `lemonade-server`, and the real `gaia` with it — so the UI
154
+ reported a missing CLI that we had hidden. A shared directory now moves to the
155
+ end of `PATH` instead of being dropped.
156
+ - **Flags a command does not read are refused, not ignored.** `run --port 9000`
157
+ parsed fine and came up on the default port; likewise `serve --component` and
158
+ `serve --cache-dir`.
159
+ - **A failed install says what to do.** A download that could not be moved into
160
+ place — usually a running sidecar holding the file on Windows — printed a raw
161
+ stack trace.
162
+ - **`taskkill` failures name their reason.** Its exit code and stderr were
163
+ discarded, so "Access is denied" surfaced ten seconds later as a generic
164
+ timeout.
165
+ - **A sidecar that survives shutdown is still reaped at exit.** `shutdown`
166
+ de-registered it before killing it, so one that survived both kill windows
167
+ became a permanent orphan holding the port.
168
+ - **`serve` removes its signal handlers once it stops**, so Ctrl+C keeps working
169
+ afterwards, and a repeat Ctrl+C during a slow teardown now says what it is
170
+ waiting for instead of looking frozen.
171
+ - **A non-JSON reply from a sidecar probe raises a typed error** rather than a
172
+ bare `SyntaxError` — the case where a proxy answers `200` with an HTML page.
173
+ - **`--port` no longer accepts what `Number()` would coerce**, so `--port 0x2710`
174
+ is rejected instead of quietly binding 10000.
175
+
176
+ ### Security
177
+
178
+ - **A desktop notification can no longer run code.** On Windows, `notify_desktop`
179
+ rendered its message box by pasting the title and body into a PowerShell command
180
+ string, so a `'` in either — text the model picks, and prompt-injected content
181
+ can steer it — closed the string literal and the remainder ran as PowerShell.
182
+ The command is now a fixed script that reads both values from the child's
183
+ environment, and the tool now needs your approval before it runs, like the
184
+ other tools that spawn a process (SKILL.md §8).
185
+ - **`resolveSidecarPath` / `resolveTuiPath` verify the binary before returning a
186
+ path that gets spawned.** Both fed `spawn()` from a predictable cache path with
187
+ no integrity check, so anything able to write `~/.gaia/agents/gaia/` got code
188
+ run — despite the package documenting the SHA verify as its security boundary.
189
+ They now re-hash against `binaries.lock.json`; pass `{ verify: false }` for a
190
+ binary you built yourself. Note this makes them proportional to the binary's
191
+ size — resolve once at startup, not per request.
192
+ - **`--base-url` requires `https`** unless `--allow-insecure-base-url` is passed.
193
+ The pinned SHA already made a plaintext mirror non-exploitable, but tampering
194
+ surfaced as a confusing `IntegrityError` instead of the transport failure it is.
195
+ - **A ~200MB artifact is never held in memory whole.** Downloads stream to disk,
196
+ and the cache-hit check that re-hashes an already-installed binary — which runs
197
+ on every `gaia run` — reads it in bounded chunks. Both hashes are computed
198
+ incrementally, and a download is still verified *before* the file is moved into
199
+ place.
200
+
201
+ ### Fixed
202
+
203
+ - **Esc stops a running turn in the terminal UI without killing the agent.**
204
+ The TUI used to kill the agent process, and on the released one-file binary
205
+ that killed only the launcher: the cancelled tool call ran to completion and
206
+ the surviving process consumed the next message. The first Esc now sends the
207
+ agent a `cancel` control message, so the turn ends and the session keeps its
208
+ loaded skills, "always" grants, history and bypass mode. A second Esc stops
209
+ the whole process tree.
210
+ - **A restart after a hard stop no longer turns bypass permissions back on.**
211
+ The replacement agent is launched in the session's current permission mode
212
+ instead of from the original flags, and the TUI says what the restart lost.
213
+
214
+ ### Notes
215
+
216
+ - The sidecar is installed into `~/.gaia/agents/gaia/`, the GAIA daemon's own
217
+ cache directory. The daemon spawns and supervises the sidecar; putting an
218
+ already-verified binary where it looks turns its fetch into a cache hit instead
219
+ of a second large download. `run` therefore does not spawn a sidecar itself —
220
+ the terminal UI reaches agents through the daemon relay and never holds a
221
+ sidecar token, so a second process would only contend for the port. `serve` is
222
+ the direct path for callers who do want to own it.
223
+ - The TUI is installed as `gaia-tui`, never as `gaia`, so it cannot shadow the
224
+ `gaia` bin shim npm places on `PATH` — the terminal-hub artifact itself is named
225
+ `gaia-<platform>`, which is why the lock separates `filename` from `executable`.
226
+ - Because the TUI comes from the `terminal-hub` lane, this package cannot be
227
+ released until that component is published at the version the lock pins. The
228
+ release fails loudly naming the required version; it never falls back to
229
+ building its own TUI. Each terminal-hub artifact is additionally cross-checked
230
+ against the hub's own server-side SHA-256 before its hash enters the lock.
231
+ - Requires Node.js 18+ (built-in `fetch`), a running Lemonade Server for
232
+ inference, and the `gaia` Python CLI 0.23.1+ on `PATH` for the daemon the TUI
233
+ starts. 0.23.1 is the first core whose daemon knows how to supervise this
234
+ agent; on 0.23.0 the UI starts with nothing behind it.
235
+ - The sidecar has no arm64 Linux or arm64 Windows build. On those platforms the
236
+ run stops with an error naming the platform and the supported set rather than
237
+ launching a UI with no agent behind it.
238
+ - `gaia_agent` enforces a per-session caller-auth bearer on every `/v1/gaia/*`
239
+ request, plus a loopback `Host` allowlist and non-loopback `Origin` rejection.
240
+ This package mints no token, so a sidecar it spawns comes up in dev mode (token
241
+ check skipped, loudly warned, Host/Origin still enforced) — pass your own
242
+ through `spawnSidecar`'s `env` to turn it on. See SPEC §5.4.
243
+ - Tracks sidecar contract `apiVersion` **2.12**; a differing major raises
244
+ `VersionMismatchError`.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (C) 2024-2025 ADVANCED MICRO DEVICES
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,8 +1,227 @@
1
- # @amd-gaia/gaia — placeholder
1
+ # @amd-gaia/gaia
2
2
 
3
- This `0.0.0` publish exists only to create the package so a **trusted publisher
4
- (OIDC)** can be configured on npmjs.com. npm cannot create a package from OIDC,
5
- so the first version has to be published with a token.
3
+ One command gets you a working GAIA:
6
4
 
7
- Nothing here is usable. The real CLI ships from `0.1.1` onward, published from
8
- `.github/workflows/release_agent_gaia.yml` with provenance.
5
+ ```bash
6
+ npx @amd-gaia/gaia
7
+ ```
8
+
9
+ That fetches the two binaries GAIA needs — the agent sidecar and the terminal UI —
10
+ verifies both against a checksum manifest that ships inside this package, and drops
11
+ you into the terminal UI. No Python to install, no repo to clone, no build step.
12
+ Local inference is the default. The TUI can explicitly select Fireworks AI or AMD
13
+ LLM Gateway through Lemonade; remote chat sends conversation history to that provider. The
14
+ terminal UI's `--use-claude` flag, which would send a conversation to the
15
+ Anthropic API, is refused for the agent this package installs — see
16
+ [`SPEC.md` §5.5](./SPEC.md#55-other-transports).
17
+
18
+ The terminal UI you get here is the published **`terminal-hub`** component — the
19
+ exact same binary a full GAIA install runs as `gaia tui`, not a separate build. So
20
+ however you arrive at the terminal UI, it behaves identically.
21
+
22
+ ## What it actually does
23
+
24
+ 1. **Resolves your platform** — `win32-x64`, `darwin-arm64`, `darwin-x64`,
25
+ `linux-x64` (plus `linux-arm64` / `win32-arm64` for the terminal UI).
26
+ 2. **Reads `binaries.lock.json`**, the checksum manifest published with this exact
27
+ package version. It records, per binary, which hub lane it comes from and what
28
+ it must hash to.
29
+ 3. **Downloads and SHA-256 verifies both binaries.** A hash that does not match is
30
+ a hard failure — the download is deleted and the run stops. There is no
31
+ "continue anyway" path and no unverified fallback.
32
+ 4. **Launches the terminal UI**, which brings up the GAIA daemon and the agent
33
+ sidecar and hands you the chat. Its exit code becomes ours.
34
+
35
+ ## Requirements
36
+
37
+ - **Node.js 18+** (for the built-in `fetch`).
38
+ - **[Lemonade Server](https://amd-gaia.ai/docs/reference/dev)** running locally —
39
+ it hosts the model the agent thinks with. GAIA tells you if it isn't up.
40
+ - The `gaia` Python CLI **0.23.1 or newer** on `PATH` for the daemon the terminal
41
+ UI starts. Earlier cores start a daemon that has no entry for this agent, so the
42
+ UI comes up with nothing behind it. Install it with
43
+ `curl -fsSL https://amd-gaia.ai/install.sh | sh` (Windows:
44
+ `irm https://amd-gaia.ai/install.ps1 | iex`).
45
+
46
+ ## Supported platforms
47
+
48
+ The terminal UI is Go and cross-compiles everywhere. The agent sidecar is a frozen
49
+ Python build, produced on the machine it targets, and **has no arm64 Linux or arm64
50
+ Windows build**. On those two platforms `npx @amd-gaia/gaia` stops with an error
51
+ naming your platform and the ones that do work — it will not start a UI with no
52
+ agent behind it.
53
+
54
+ | Platform key | Agent sidecar | Terminal UI |
55
+ | -------------- | :-----------: | :---------: |
56
+ | `win32-x64` | ✅ | ✅ |
57
+ | `darwin-arm64` | ✅ | ✅ |
58
+ | `darwin-x64` | ✅ | ✅ |
59
+ | `linux-x64` | ✅ | ✅ |
60
+ | `linux-arm64` | — | ✅ |
61
+ | `win32-arm64` | — | ✅ |
62
+
63
+ `npx @amd-gaia/gaia version` prints this matrix, plus the version and source URL of
64
+ each binary, for the release you have installed.
65
+
66
+ ## Commands
67
+
68
+ ```
69
+ gaia [run] [options] [-- <tui args>] Fetch + verify both binaries, then launch the TUI
70
+ gaia fetch [options] Download + verify only; print JSON and exit
71
+ gaia serve [options] Run the agent sidecar alone (REST API, no TUI)
72
+ gaia version Print the lock manifest and this host's platform
73
+ gaia help Show help
74
+ ```
75
+
76
+ Anything after a bare `--` goes to the terminal UI untouched:
77
+
78
+ ```bash
79
+ npx @amd-gaia/gaia -- --debug
80
+ ```
81
+
82
+ Common options:
83
+
84
+ | Flag | Meaning | Accepted by |
85
+ | --------------------- | ------------------------------------------------------------- | ----------- |
86
+ | `--base-url <url>` | Override the download base URL from `binaries.lock.json`. Must be `https:` | `run`, `fetch`, `serve` |
87
+ | `--allow-insecure-base-url` | Permit a non-`https` `--base-url` (a trusted local mirror) | `run`, `fetch`, `serve` |
88
+ | `--sidecar-dir <dir>` | Where to install the agent sidecar (default `~/.gaia/agents/gaia`) | `run`, `fetch`, `serve` |
89
+ | `--cache-dir <dir>` | Where to cache the terminal UI binary | `run`, `fetch` |
90
+ | `--force` | Re-download even when a verified binary is already cached | `run`, `fetch`, `serve` |
91
+ | `--platform <key>` | Fetch for another platform | `fetch` |
92
+ | `--component <name>` | Fetch only `sidecar` or `tui` | `fetch` |
93
+ | `--port <n>` | Sidecar bind port (default `8141`) | `serve` |
94
+
95
+ A flag a command does not read is **refused**, not ignored — `gaia run --port
96
+ 9000` exits 2 rather than silently coming up on the default port.
97
+
98
+ Set `DEBUG=gaia` for download, spawn, and sidecar output on stderr. Diagnostics
99
+ never touch stdout, which the terminal UI owns.
100
+
101
+ ## Where things land
102
+
103
+ | What | Path |
104
+ | --------------- | ---------------------------------------- |
105
+ | Agent sidecar | `~/.gaia/agents/gaia/gaia-agent[.exe]` |
106
+ | Install record | `~/.gaia/agents/gaia/.installed` |
107
+ | Terminal UI | `~/.gaia/npm-cache/gaia-<version>/gaia-tui[.exe]` |
108
+
109
+ The sidecar goes into the GAIA daemon's own cache directory on purpose: the daemon
110
+ is what spawns and supervises it, and it does its own SHA-256 check on the way. By
111
+ putting an already-verified binary there we save a second download rather than
112
+ racing one.
113
+
114
+ The `.installed` record next to it is what the daemon and the terminal UI read to
115
+ know the agent is installed — without it the UI would run the sidecar as its own
116
+ stdio child instead of letting the daemon supervise it. It is rewritten even when
117
+ the binary was already cached, so an install left by an earlier version repairs
118
+ itself the next time you run. A `--platform` fetch stages a binary for a
119
+ *different* machine, so it deliberately leaves no record.
120
+
121
+ The terminal UI is installed as `gaia-tui`, **never** as `gaia` — a file named
122
+ `gaia` in a cache directory would shadow the `gaia` shim npm puts on your `PATH`.
123
+
124
+ ## Ports
125
+
126
+ | Service | Port |
127
+ | ------------- | --------------------------------- |
128
+ | Agent sidecar | `8141` on `127.0.0.1` |
129
+ | GAIA daemon | assigned at start, recorded in `~/.gaia/host/instance.json` |
130
+
131
+ Port **4001 is reserved repo-wide** and is refused with an error if you pass it.
132
+ Both services bind loopback only — this agent speaks for your documents and memory
133
+ and has no business on a LAN interface.
134
+
135
+ ## Running the sidecar on its own
136
+
137
+ `gaia serve` skips the terminal UI and gives you the REST surface directly, for
138
+ integrating GAIA into your own app:
139
+
140
+ ```bash
141
+ npx @amd-gaia/gaia serve --port 8141
142
+ curl http://127.0.0.1:8141/health
143
+ ```
144
+
145
+ It waits for `GET /health`, checks the contract version, and tears the whole
146
+ process tree down on Ctrl+C. See [`SPEC.md`](./SPEC.md) for the endpoints.
147
+
148
+ The sidecar normally requires a per-session bearer token on `/v1/gaia/*`, but
149
+ neither `serve` nor `startSidecar` mints one, so both leave it in dev mode — the
150
+ token check off, `Host`/`Origin` still enforced. This agent has shell and file
151
+ tools, so before you expose it to anything, supply a token of your own: see
152
+ [`SPEC.md` §5.4](./SPEC.md#54-caller-authentication).
153
+
154
+ ## Programmatic use
155
+
156
+ ```ts
157
+ import { randomUUID } from "node:crypto";
158
+ import { fetchAll, startSidecar, shutdown } from "@amd-gaia/gaia";
159
+
160
+ const { sidecar } = await fetchAll(); // both binaries, SHA-256 verified
161
+ const proc = await startSidecar({ binaryPath: sidecar.binaryPath });
162
+
163
+ const sessionId = randomUUID(); // reuse across the whole conversation, see below
164
+
165
+ const res = await fetch(`${proc.baseUrl}/v1/gaia/query`, {
166
+ method: "POST",
167
+ headers: { "content-type": "application/json" },
168
+ body: JSON.stringify({
169
+ query: "summarize my notes",
170
+ run_id: randomUUID(),
171
+ session_id: sessionId,
172
+ context: [],
173
+ }),
174
+ });
175
+
176
+ await shutdown(proc);
177
+ ```
178
+
179
+ `/v1/gaia/query` streams Server-Sent Events terminated by exactly one `final` or
180
+ `error`. `fetchAll()` also returns the TUI's path if you would rather launch that.
181
+
182
+ **Reuse the same `session_id` for every turn in a conversation.** It is what
183
+ lets a document you had it index, or a skill you had it load, survive to the
184
+ next question — drop it (or mint a new one per call) and the agent still
185
+ answers, but it forgets everything from the previous turn. See
186
+ [`SPEC.md` §5.2](./SPEC.md#52-session_id-and-agent-retention) for the retry
187
+ and eviction behavior.
188
+
189
+ Every failure throws a typed error (`IntegrityError`, `PlatformError`,
190
+ `HealthTimeoutError`, `VersionMismatchError`, `BinaryNotFoundError`) with a message
191
+ that names what failed and what to do about it.
192
+
193
+ ## Where the binaries come from
194
+
195
+ The two binaries ship from two different places, and `binaries.lock.json` records a
196
+ version and a source URL for each:
197
+
198
+ | Binary | Published as | Built by |
199
+ | ------------- | ----------------------------------------- | -------------------------------- |
200
+ | Agent sidecar | the `gaia` agent, at this package's version | this package's release |
201
+ | Terminal UI | the `terminal-hub` component, at its own version | the core GAIA release |
202
+
203
+ The terminal UI is **consumed, not rebuilt**. It is byte-for-byte the `gaia tui`
204
+ binary a core install ships, so there is no second copy that could lag behind or
205
+ behave differently — which is the entire reason it is sourced this way.
206
+
207
+ ## Integrity
208
+
209
+ `binaries.lock.json` is the single source of truth for what gets downloaded and
210
+ what it must hash to. The release pipeline regenerates it from the artifacts
211
+ actually being served — the sidecars it just published, and the terminal-hub
212
+ artifacts it downloaded and cross-checked against the hub's own recorded hashes.
213
+
214
+ Between releases the lock carries `PENDING-replace-with-real-sha256` placeholders.
215
+ **A placeholder blocks the fetch outright** — before any network call — so an
216
+ unverifiable binary can never be downloaded, let alone executed. If you need to run
217
+ against a locally built binary, build it yourself and point the lifecycle helpers
218
+ at it directly; the fetcher will not be talked into it.
219
+
220
+ ## Links
221
+
222
+ - Guide: <https://amd-gaia.ai/docs/guides/gaia>
223
+ - Technical reference: [`SPEC.md`](./SPEC.md)
224
+ - Changes: [`CHANGELOG.md`](./CHANGELOG.md)
225
+ - Issues: <https://github.com/amd/gaia/issues>
226
+
227
+ MIT licensed. © 2024-2026 Advanced Micro Devices, Inc.