@amd-gaia/gaia 0.2.0 → 0.3.2

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 CHANGED
@@ -4,13 +4,933 @@ All notable changes to `@amd-gaia/gaia` are documented here. The format follows
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this package adheres
5
5
  to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
- ## [0.1.1] — unreleased
7
+ ## [Unreleased]
8
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.
9
+ ## [0.3.2]
10
+
11
+ Released with GAIA 0.25.2, and requires the `gaia`
12
+ Python CLI 0.25.2+ on `PATH`. Integrators: the sidecar contract is now
13
+ **2.24**; clients built for 2.18 keep working, and the new
14
+ `/query` fields are refused with `422` by older binaries, so probe
15
+ `/version` before sending them.
16
+
17
+ - **Memory downloads its embedding model when it is missing.** On the first
18
+ start that uses memory, the agent now fetches the required embedding model
19
+ from Lemonade instead of silently running without memory; the initial
20
+ download can be about 300 MB.
21
+ - **Unknown or misplaced switches are refused.** `gaia --forse` and
22
+ `gaia fetch --developer-mode` now exit 2 instead of silently starting the TUI;
23
+ pass terminal-UI arguments after a bare `--`.
24
+
25
+ - **The Agent UI's "Under the hood" figures cover GAIA chats.** It said every
26
+ answer was "not measured", because only the agent saw its own step timings.
27
+ `final` now carries `performance` with them: the turn's model and tool
28
+ seconds and each model call's token counts. Older binaries never send it.
29
+ - **`GET /v1/gaia/skills` says where each skill came from.** Each skill now
30
+ carries a `source` (`agent-bundled`, `user` or `claude-import`; `null` for
31
+ any other root), so the Agent UI can group the Skills list by origin. An
32
+ older agent omits it and the UI shows the list flat.
33
+ - **One very long turn no longer vanishes from the conversation.** A turn
34
+ bigger than the whole history budget, like a pasted log or a long document
35
+ read, was dropped from what the model saw next, answer included, so "now
36
+ shorten that" ran with no record of it. It is now kept: long tool results
37
+ become a short note naming the tool, and its longest messages are cut with
38
+ a note saying how much.
39
+ - **Internet off also stops the mailbox and Agent Hub tools.** With a chat's
40
+ Internet switched off, GAIA could still read Gmail or Outlook and search or
41
+ install skills from the Agent Hub, because those tools carry no URL for the
42
+ check to see. They are now refused with the same message as a web search.
43
+
44
+ ### For integrators: contract 2.24
45
+
46
+ - **Relative file paths use the chat workspace.** A new `working_directory` field
47
+ on `/query` tells the agent where bare file names resolve, separately from
48
+ `allowed_paths`. New and retained sessions use the same workspace for reads,
49
+ writes, edits and approval prompts. Send it only after `/version` reports
50
+ contract 2.24 or later.
51
+
52
+ ### For integrators: contract 2.23
53
+
54
+ - **`/query` takes `internet_off`** (contract **2.23**, #5883). The Agent UI
55
+ never told the agent when a chat's Internet switch was off, so the switch
56
+ stayed locked in every GAIA chat on a standard install. `true` refuses web
57
+ search, page fetches, the browser, connector, mailbox and Agent Hub tools and
58
+ commands that contact another host, as it does when the agent runs inside the Agent UI. `false`
59
+ allows them, and omitting it leaves the agent as it is. A retained session
60
+ keeps the last value. Older binaries `422` the field.
61
+ - **`POST /v1/gaia/sessions/{session_id}/internet`** (contract **2.23**)
62
+ reaches a turn already running. Without it, a user who turned the internet
63
+ off mid-turn watched the agent keep searching until the turn ended. Body
64
+ `{"internet_off": bool}`; the session's next tool call follows it. An
65
+ unknown session is a `404`, as for `/bypass`. Post it only once `/query`
66
+ has answered: until then the turn's own `internet_off` replaces it.
67
+
68
+ ### For integrators: contract 2.22
69
+
70
+ - **A client can show the model's reasoning.** Over `/query` the reasoning
71
+ only arrived folded into `status` lines, so the Agent UI showed none of it
72
+ for an installed GAIA. A request with `reasoning: true` now gets it as
73
+ `reasoning` events, `{ delta }`, kept apart from the answer. Without the
74
+ field nothing changes. Older binaries reject it with `422`.
75
+
76
+ ### For integrators: contract 2.21
77
+
78
+ - **`final` says how full the model's window is** (contract **2.21**,
79
+ #5738). The Agent UI's Context panel and the meter beside its message box
80
+ stayed empty for every GAIA chat, because only the agent can measure its
81
+ own prompt, tools and window. `final` now carries `context` with that
82
+ measurement for the next call, or `context_error` when measuring failed.
83
+ A stopped or failed turn carries neither. Older binaries never send it.
84
+ - **A relayed write prompt names where the file lands.** When the model asks to
85
+ write `shop2.txt`, `needs_confirmation` now carries the absolute path the
86
+ write resolves to in `prompt_context.file_path`, so a front-end can show
87
+ `/Users/you/shop2.txt` instead of a bare name. `args` still holds exactly the
88
+ model's `file_path`.
89
+ - **A web search's results reach the client.** The Agent UI listed no Sources
90
+ for a GAIA web search, because a `search_web` `tool_result` carried only a
91
+ 300-character summary. Its `data` now also carries `sources`, a list of
92
+ `{ title, url }` for each hit. Older binaries never send it.
93
+
94
+ - **An old failure in memory no longer stops a request you make now.** A note
95
+ like "this page returned 503, don't waste tool calls on it" was obeyed as a
96
+ standing ban, so the agent refused a URL you handed it. Memories now reach
97
+ the model as dated notes your request outranks, and a passing failure is
98
+ marked as one. A 429 or 502-504 "try later" failure is no longer saved as
99
+ an error memory at all.
100
+ - **Text from a file is not saved as your details.** The agent could save a
101
+ line from a document it read, or call it something you had saved. It now
102
+ saves text from a file, page or tool result only when you ask it to keep
103
+ something, and an empty memory search says that file text is not saved.
104
+
105
+ - **Pushed history that doesn't fit the model's window no longer overflows
106
+ it.** `/query` used the `context` you pushed as-is, but you size it without
107
+ seeing the agent's prompt and tools. On a 32K window the two together could
108
+ exceed the window and fail the turn. The agent now keeps the newest whole
109
+ turns that fit beside its prompt and streams a `status` event when older
110
+ ones drop out of view.
111
+
112
+ - **Homebrew tools are visible to the agent on a Mac.** An app opened from Finder
113
+ or the Dock starts with only the system folders on its search path, so the
114
+ agent could not run `gh`, `node` or anything else Homebrew installed, and its
115
+ prompt said they were "not installed". The agent now starts with the `PATH`
116
+ your login shell builds (only when opened that way: started from a terminal it
117
+ keeps the terminal's own `PATH`, so an activated virtualenv still wins), and a
118
+ tool it still cannot find is reported as not
119
+ reachable from its shell rather than missing from your machine. If your shell
120
+ startup is slow or fails, the agent logs a warning and keeps the old path.
121
+
122
+ ### For integrators: contract 2.20
123
+
124
+ - **A failed model request says which endpoint failed, worded for your
125
+ front-end** (contract **2.20**, #5295). A headless caller of `/query` whose
126
+ hosted model returned HTTP 502 was told the "cloud request through Lemonade
127
+ failed" and to check "the TUI provider settings", though no TUI was
128
+ involved. The error now names the provider and the `host:port` the request
129
+ went through. A local model on a base URL you set is reported as "the model
130
+ server at `host:port`" instead of "Lemonade on this machine", since GAIA
131
+ can't tell what serves it. The advice follows the `surface` field: a caller
132
+ that omits it is pointed at the model server the GAIA host uses; `"tui"`,
133
+ `"agent_ui"` and `"cli"` keep their own settings screens. Older binaries
134
+ refuse the field with `422`, so probe `/version` before sending it.
135
+ Version skew: a front-end older than this release never sends `surface`, so
136
+ against this agent it gets the headless advice (the model server's
137
+ `LEMONADE_BASE_URL`) instead of its own settings screen. GAIA ships the TUI,
138
+ the Agent UI and this agent together, so this only shows when one of them is
139
+ updated without the others, or when the TUI's `/version` probe times out and
140
+ it can't confirm the agent takes the field.
141
+ - **Answers stream over `/query`.** The HTTP sidecar ran its agent with
142
+ streaming off, so a relayed turn (the Agent UI, and the TUI's later sessions)
143
+ showed "Waiting on the model" until the whole answer landed at once, Stop could
144
+ not cut a model call short, and a stopped turn kept no text. Every `/query`
145
+ turn now streams its model calls and sends the answer as `token` events before
146
+ `final`, the same as the stdio transport. A run cancelled mid-answer stops
147
+ within a token and ends with an empty `final`, as stdio does; text not yet
148
+ sent when the cancel lands is dropped.
149
+ ### Fixed
150
+
151
+ - **"Save it to my Documents folder" saves to the user's Documents folder.**
152
+ The system prompt told GAIA that "my documents" meant its own documents
153
+ folder (`~/.gaia/documents`), so a new file the user asked for in Documents
154
+ went into GAIA's hidden folder, where they would never find it. Finding an
155
+ existing file still checks GAIA's folders first.
156
+ - **Secrets stay out of memory and the conversation log.** A bank PIN was saved
157
+ as a memory, because the filter knew passwords and API keys but not PINs. The
158
+ conversation log also kept the PIN, a password the agent had refused, a card
159
+ number and an SSN verbatim, where `search_past_conversations` read them back.
160
+ PINs, passcodes, card security codes, Luhn-valid card numbers and SSNs are now
161
+ refused as memories, and every credential-shaped span is replaced with
162
+ `[secret removed]` before a turn is logged.
163
+ - **"How much free disk space do I have?" gets the right number, first try.**
164
+ On a Mac, GAIA said a nearly full disk had ~233 GB free: its system-info
165
+ tool reported only the share the system volume uses, so 97.8% used read as
166
+ 5%. It now reports free space as macOS counts it, and says it answers
167
+ free-space questions, so GAIA no longer tries a shell command that is refused.
168
+ - **Full access in the Agent UI asks before a gated shell command instead of
169
+ refusing it.** With `/sessions/{id}/bypass` on, a command such as a delete or
170
+ `git add` was refused outright, so a Full access chat could not run it at
171
+ all. On a run someone can answer it now emits `needs_confirmation` and runs
172
+ only on an allow from `/tool_decision`. The shell gates still stay on over
173
+ HTTP, commands that need no approval still run unasked, and a run nobody can
174
+ answer still refuses.
175
+ - **Local models with a large window can write longer replies.** The output
176
+ cap is a quarter of the loaded window (16K at 64K, between 8K and 32K)
177
+ instead of a flat 8K, and a reply cut off at the cap is told to write the
178
+ file in smaller parts.
179
+ - **`search_file_content` searches the workspace.** A relative or default
180
+ directory resolved against the sidecar's own folder and reported "0 files";
181
+ it now resolves against the workspace, searches text files of any extension,
182
+ and says when nothing was searched.
183
+ - **Token counts are exact in the published binary, offline too.** The binary
184
+ could not load its tokenizer, so every turn trimmed history and sized
185
+ context from an estimate that overcounts, and logged `Unknown encoding
186
+ cl100k_base`. The tokenizer and its data now ship inside the binary, so it
187
+ no longer downloads anything to count tokens.
188
+
189
+ ### For integrators: contract 2.20
190
+
191
+ - **`/query` takes `surface`** (contract **2.20**): `"agent_ui"`, `"tui"` or
192
+ `"cli"`. Asked to run something on a schedule from the Agent UI, the agent
193
+ said it had no scheduler and sent the user to Windows Task Scheduler; with
194
+ `"agent_ui"` it points them at the **Scheduled tasks** page instead. Older
195
+ binaries `422` the field, so probe `/version` before sending it.
196
+ - **The agent knows which folders it can work in.** The system prompt now names
197
+ the session's folders and labels GAIA's documents folder, so "summarize X in
198
+ my documents folder" looks there first instead of trying `~/Documents` and
199
+ the home folder.
200
+
201
+ ### For integrators
202
+
203
+ - **A tool result keeps the tool's own status.** When a tool's result had no
204
+ structured payload, the `tool_result` event's `data` carried only `summary`
205
+ and `success`, so a client could not tell a skipped `remember` (a private
206
+ chat saves nothing) from a saved one, and the Agent UI listed it as saved.
207
+ `data` now also carries `status` when the tool returned one. Additive, so
208
+ the contract version is unchanged.
209
+
210
+ - **An MCP tool call says which connector it used and what came back.** A Git
211
+ connector call reached a client as a bare `mcp_git_git_log`, and its result
212
+ as "Tool 'git_log' returned data". `tool_call` gains optional `mcp_server`,
213
+ `mcp_server_label` ("Git") and `mcp_tool` ("git_log"), and the result's
214
+ `data` carries the tool's text in `mcp_output` (`{ text, truncated }`, capped
215
+ at 16,000 characters). Clients that ignore the fields see the same events.
216
+
217
+ ### For integrators: contract 2.19
218
+
219
+ - **`/query` can record a turn's file changes for undo** (contract **2.19**).
220
+ Desktop chats run in this agent and the Agent UI relays them, so a file the
221
+ agent wrote never reached the chat's Changes view or its Undo. With
222
+ `changes_turn_id` (and `session_id`), the agent copies each file before
223
+ changing it into the snapshot store the Agent UI reads, and finishes the
224
+ recording before the terminal event. Older binaries refuse the field with
225
+ `422`, so probe `/version` before sending it.
226
+ - **A confirmation's `args` are only what the model sent.** `needs_confirmation`
227
+ `args` also carried keys the agent adds to its own prompt — a risk note, a
228
+ scratch-folder marker, and the folder a shell call runs in — so a policy
229
+ client auto-approving on `args` matched fields the model never sent. `args`
230
+ is now exactly the call's arguments; the folder and risk note moved to a new
231
+ `prompt_context` object.
232
+ - **A tool result names the file it wrote.** When a tool's result carries
233
+ `file_path` or `image_path`, the `tool_result` event's `data` now keeps it, so
234
+ a client can list the files a turn produced.
235
+
236
+ ## [0.3.1]
237
+
238
+ Released with GAIA 0.25.1, and requires it. Integrators: the sidecar
239
+ contract is now **2.18**; clients built for 2.17 keep working, and the new
240
+ `/query` fields are refused with `422` by older binaries, so probe
241
+ `/version` before sending them.
242
+
243
+ ### Linux
244
+
245
+ - **The Linux agent runs on glibc 2.34 or newer.** The `linux-x64` agent is
246
+ now built against glibc 2.34 (#5545), so it starts on Ubuntu 22.04, Debian 12
247
+ and RHEL 9. Before, it needed glibc 2.38 and failed at launch on those.
248
+
249
+ ### For integrators: contract 2.18
250
+
251
+ - **`/query` takes the chat's file scope and memory mode** (contract **2.18**).
252
+ `allowed_paths` lets the Agent UI hand the agent the same scope its session
253
+ panel shows. `memory` fixes private chats saving to memory: the relayed turn
254
+ never said the chat was private or that memory was off, so the agent went on
255
+ saving the errors and lessons it records on its own. `"private"` or `"off"`
256
+ now turns off every memory write for the turn.
257
+ - **A confirmation carries the call it asks about.** `needs_confirmation` now
258
+ has `args` (each value capped at 64,000 characters, with `args_truncated`
259
+ when one was cut) and `tool_label`, so a client can show all of the code it
260
+ is approving rather than the shortened `summary`, and word a path prompt for
261
+ a file or folder that exists.
262
+ - **A turn the model gave up on ends as failed, not done.** When the model
263
+ stopped responding or refused mid-turn (a stall, a 404, every retry spent),
264
+ the turn ended on the model's opening sentence and the Agent UI listed the
265
+ chat as done. The final answer now names the step, the provider and the
266
+ cause, what already ran, and what is unfinished, and the `final` event
267
+ carries `failed: true`.
268
+ - **A turn queued for the model says so on the stream.** When another process
269
+ or request is using the model, `/query` now sends `status` events with
270
+ `phase: "model_queue"` every ~2 s, carrying a `queue` object with the turn's
271
+ place in line, who holds the model and how long it has waited, then one
272
+ `granted` update. A turn queued this way leases ahead of background work, and
273
+ `/query/{run_id}/cancel` takes it out of the queue. Before, the stream went
274
+ silent for the whole wait, so a client could not tell a queued turn from a
275
+ dead one.
276
+ - **Needs core 0.25.1.** The chat agent this one builds on imports the
277
+ reasoning-effort tool, which first ships in core 0.25.1, so its
278
+ `amd-gaia` floor and `min_gaia_version` rise to 0.25.1 with that release.
279
+
280
+ ### File access and privacy
281
+
282
+ - **Full access in the Agent UI grants the folders you name.** Turning it on
283
+ over `/sessions/{id}/bypass` refused every path outside the chat's scope with
284
+ nobody asked. On a run the caller can answer for, Full access now grants the
285
+ path without a prompt, as it does in-process; Ask mode asks. Unattended runs,
286
+ the home folder and drive roots are still refused.
287
+ - **No more approval prompts for files that aren't there.** Naming a missing
288
+ file or folder outside the allowed paths opened a 10-minute approval prompt,
289
+ and only after it did the agent learn the file didn't exist; a retry asked
290
+ again. The tool now says the file wasn't found straight away, without asking,
291
+ and names an allowed or attached file with the same name. `analyze_data_file`
292
+ given a bare file name uses the attached file of that name instead of asking
293
+ about one in the working folder. Secret and protected paths are refused
294
+ exactly as before, whether or not they exist.
295
+ - **A turn's file changes can be undone.** The agent saves a copy of every
296
+ file before a tool writes, edits, creates or deletes it, so the Agent UI
297
+ can show the turn's changes and put every file back, even after a restart.
298
+ A turn that also ran a shell command, Python or an MCP tool says undo may
299
+ be incomplete.
300
+ - **Saving a download asks about the file, not its folder.** A download into
301
+ the home folder failed without asking, because the agent asked to grant the
302
+ whole folder. It now asks about the one file it is about to create.
303
+ - **A document another program has open is re-indexed once it is free.** On
304
+ Windows, a watched file that Word, PowerPoint or another program held locked
305
+ was read once, reported as corrupted, and never re-indexed. It is now retried
306
+ a few times, and if it stays locked the log says to close the program and
307
+ save the file again.
308
+
309
+ ### Long and busy turns finish
310
+
311
+ - **A context overflow no longer throws away the evidence.** A task that read
312
+ many documents used to fill a 32K–64K window, after which the overflow retry
313
+ dropped every older result and the answer was built on whatever was left
314
+ (#2780). The retry now keeps each result whole behind a handle the model can
315
+ re-read, and retries only when the request will then fit.
316
+ - **Token counts no longer undercount when the tokenizer data can't load.** On
317
+ an offline or locked-down machine the counter fell back to characters ÷ 4.28,
318
+ which undercounts JSON and CJK text, so history that should take half the
319
+ window could fill it (#5066). It now warns and counts at least one token per
320
+ three UTF-8 bytes.
321
+ - **Opening a session or switching its model no longer freezes the other
322
+ sessions.** The sidecar built a new session's agent, and ran a `/model`
323
+ switch (which builds a new client and checks its server), on its event
324
+ loop. Every other session's stream stopped for that long, heartbeats
325
+ included, so the TUI and the daemon relay saw an idle connection. That
326
+ setup now runs on a worker thread, and a request that goes away mid-setup
327
+ still releases its session.
328
+ - **Background memory upkeep no longer wipes the chat's cached prompt.**
329
+ Memory consolidation, reconciliation and skill distillation ran on the
330
+ model slot the conversation uses, so the next message re-read the whole
331
+ ~19K-token prompt (~45 s on Gemma-4-E4B). They now run on the side slot,
332
+ as memory extraction already did.
333
+ - **A turn cut short by closing the TUI is saved as interrupted.** The session
334
+ history got a turn only once it ended, so closing the TUI mid-turn saved it
335
+ as an ordinary "stopped" answer, or, if the TUI had to kill the agent, lost
336
+ the question entirely. The question is now saved when the turn starts, and a
337
+ turn the TUI's closing cut short ends with "This answer was interrupted when
338
+ GAIA closed." A resumed session (`GAIA_HISTORY_FILE`) sees it. Questions
339
+ queued before the close are saved as they ended.
340
+ - **A busy, restarting or sleeping model server no longer fails the turn.**
341
+ The agent waits for a shared Lemonade that is loading another app's model,
342
+ waits up to 60 s for GAIA's own server to come back after a restart, and a
343
+ PC that sleeps mid-answer resumes instead of reporting a stall. A shared
344
+ KV-cache collision is no longer reported as "conversation too long".
345
+ - **Nothing a tool waits on can hang the turn for good.** A hung MCP server,
346
+ a web server sending one byte at a time (page fetches stop at 120 s,
347
+ downloads at 30 min) and a busy embedder during indexing (one 300 s wait
348
+ per batch, with a message saying why) all end with a clear error. One bad
349
+ batch of parallel tool calls no longer trips the failure breaker and ends
350
+ the task with no answer.
351
+ - **The agent's own scripts get time to run.** A script run through an
352
+ interpreter (`python analyze.py big.csv`) gets a 600 s default instead of
353
+ the 30 s kill for quick commands.
354
+ - **Web search survives DuckDuckGo rate limits.** A refused search is retried
355
+ with backoff and through DuckDuckGo's lite endpoint, or answered by Tavily
356
+ when that connector is set up, instead of failing and being saved to memory
357
+ as a known error.
358
+
359
+ ### Memory you can trust
360
+
361
+ - **Memory keeps what the user says, and keeps it current.** Facts come only
362
+ from what the user says about themselves, a forgotten fact is not re-learned
363
+ from old chats, a newer fact outranks the one it replaced, and a write that
364
+ carries tool-call markup or model reasoning is refused instead of saved
365
+ corrupted. Relevant memories now surface in the chats they are about.
366
+
367
+ ### Models and answers
368
+
369
+ - **gpt-oss 20B and 120B are supported models.** On a model that grades its
370
+ reasoning, the agent gets `set_reasoning_effort` (low, medium or high) to
371
+ choose how hard it thinks for the rest of the request; every new message
372
+ starts again at medium. It is not registered on other models, so the
373
+ agent's 95 tools on Gemma and Qwen are unchanged.
374
+ - **gpt-oss runs the agent.** Every array tool parameter now declares
375
+ `items`, without which gpt-oss's chat template rejected every request
376
+ with HTTP 500, and gpt-oss control markers inside a file or page the agent
377
+ reads are broken up so the model no longer answers with nothing.
378
+ - **Answers are checked more honestly.** A claim such as "all 55 tests pass"
379
+ is checked even when the same sentence says "but" or "not", and asking the
380
+ agent to run a shell command runs it rather than reading the shell's state.
381
+
382
+ ### Diagnostics
383
+
384
+ - **The turn log says how busy the model server was.** With `GAIA_TURN_LOG`
385
+ set, each model call records the server's own prefill, decode and cache-reuse
386
+ figures and the time spent waiting on the model-slot lease, the slot lock and
387
+ the status probe; each turn records its server compute, its non-model time,
388
+ and what filled the gaps between model calls. `GET /v1/gaia/debug/turns`
389
+ returns the last records while recording is on (off the versioned contract).
390
+
391
+ ## [0.3.0]
392
+
393
+ Released with GAIA 0.25.0, and requires it.
394
+
395
+ ### Changed
396
+
397
+ - **Requires `amd-gaia>=0.25.0` and `gaia-agent-chat>=0.2.0`.** Every file tool
398
+ now checks the allowed-folders rule, and that check ships in core 0.25.0; an
399
+ older core cannot import the chat agent this one builds on.
400
+ - **`~/.gaia/logs/gaia-agent.log` stays bounded.** It rotates like `gaia.log`
401
+ (10 MB, three backups; `GAIA_LOG_MAX_MB`, `GAIA_LOG_BACKUPS`) instead of
402
+ growing without limit.
403
+
404
+ - **Everyday questions get short, plain answers.** "Why is the sky blue?" got
405
+ 140 words with an equation, and a Wi-Fi question got diagnostic shell runs.
406
+ The voice skill now caps an everyday answer at three plain sentences, goes
407
+ one level deeper only when asked, honours a stored short/detailed preference,
408
+ and answers general-knowledge questions without running tools.
409
+ - **Memory off no longer loads the embedding model.** A private chat, or one
410
+ with memory switched off, used to load the ~300 MB embedder on its first turn
411
+ only to validate it and to score the always-on `gaia-voice` skill. It now
412
+ loads when memory is first used, such as when memory is switched back on or
413
+ the agent recalls something. A turn with only always-on skills loaded embeds
414
+ nothing.
415
+ - **Every tool is offered on every turn again, as in the Agent UI.** Per-turn
416
+ tool selection swapped about a dozen tools in and out at its cap, which broke
417
+ the local model's prompt cache (17s to first token on a one-line question,
418
+ 0.4s without it) and left out the tool a question needed: a CSV question was
419
+ given web tools and fetched an unrelated page. `GAIA_DYNAMIC_TOOLS=1` turns
420
+ selection back on. The registered count is 95: `load_tools`, the selector's
421
+ escape hatch, registers only while selection is on.
422
+ - **A turn's silent opening now says what the model is doing.** A thinking
423
+ model sat on "Getting started" for 10-20 s while it read the prompt and then
424
+ reasoned in a paragraph released only once finished. `status` events gain an
425
+ optional `phase` (`loading_model`, `downloading_model`, `reading`,
426
+ `reasoning`, `tool_call`) with a `words` or `chars` count, sent when each phase
427
+ actually starts; the terminal UI shows them as "Reading your request",
428
+ "Reasoning · 214 words" and so on. Clients that ignore the field see the same
429
+ sentence in `message`.
430
+ - **GPU models no longer load at 32K on an NPU-profile machine.** The NPU's
431
+ 32,768-token ceiling was applied to every model whenever `default_device` was
432
+ `npu`, so a GGUF model ran at half its window and long tasks overflowed. It now
433
+ binds NPU (FLM) models only. A model can also opt in to a window sized to the
434
+ machine's memory, up to its native maximum.
435
+ - **A stale `GAIA_SKILL_SET` now stops startup.** An undeclared name used to be
436
+ dropped silently, so the agent came up healthy with no skills. The sidecar
437
+ and the stdio entry now exit non-zero before serving, with a message naming
438
+ the valid sets; leave the variable unset to start without one.
439
+ - **The code index is built on first search, not at task start.** In 32
440
+ SWE-bench tasks the agent never searched it, yet every task embedded the whole
441
+ repository in the background: about 2,000 local embedding requests per six
442
+ tasks. The first `search_code_index` now builds it; `GAIA_PROJECT_MAP_AUTO_INDEX=1`
443
+ restores building at task start.
444
+ - **The first answer on a local model starts in seconds, not after a ~20 s
445
+ silence.** The terminal UI now shows a "Getting GAIA ready" stage before the
446
+ chat: the agent starts, loads its model and reads its system prompt there,
447
+ step by step. New stdio sentinel `warm_up` (answers `warmed_up`, or
448
+ `warm_up_skipped` for a remote model).
449
+ - **Permission prompts say what a command does, once.** Running the tests is
450
+ labelled `RUNS CODE`, not `DESTRUCTIVE`; the command appears once, relative to
451
+ the project; and `a` ("always this session") is offered for shell commands and
452
+ Python too, covering the command's family — `pytest` covers
453
+ `python -m pytest`, `cd proj && pytest 2>&1 | tail`. Deletes never offer it.
454
+ `needs_confirmation` gains an optional `risk` field.
455
+ - **Shift+Tab permission modes in the terminal UI**: ask → accept edits → full
456
+ access. Accept edits lets file edits inside the starting folder run unasked;
457
+ the stdio control verb is `accept_edits`, and `--accept-edits` starts in it.
458
+ Full access is still never turned on by a stray keypress.
459
+ - **An unanswered prompt is reported as a timeout.** `tool_decision` accepts
460
+ `timeout`; the agent tells the user the request expired rather than that they
461
+ refused it.
462
+ - The default chat model now follows the hardware. On a PC whose GPU has
463
+ ~27 GB for models — a 64 GB+ Strix Halo or a 32 GB GPU; the 23.3 GB model also
464
+ needs its context cache — `gaia init` sets up Qwen3.6 35B A3B (a 23 GB Lemonade
465
+ built-in MoE, run with thinking on) and records it as `default_model`; the
466
+ agent and its `GET /v1/gaia/init` readiness check use it for chat. Gemma 4 E4B
467
+ is still downloaded for vision. Every other PC, including a CPU-only one, keeps
468
+ Gemma alone.
469
+ - **Qwen3.6 gets the longest context this PC's memory holds.** Up to its native
470
+ 262,144 tokens on a Strix Halo (a 5.4 GB KV cache), about 152K on a 32 GB GPU,
471
+ never under 64K. Gemma stays at 64K.
472
+ - Qwen3.8 Flash Next (82 GB, multimodal, thinking on) is available on a
473
+ 128 GB Strix Halo and never picked as a default; it needs ~90 GB for models.
474
+ Choose it with `gaia config set default_model user.Qwen3.8-Flash-Next-GGUF`;
475
+ `gaia init` refuses it on a PC that cannot hold it.
476
+ - **Bypass permissions is now called full access, everywhere.** `--full-access`
477
+ and `/full-access` replace `--bypass-permissions` and `/bypass`; the old names
478
+ fail with a message naming the new one. `/full-access always` (or
479
+ `gaia config set full_access true`) keeps it on across launches.
480
+ - **The agent has to read a file before it changes it.** `edit_file`, and
481
+ `write_file` on an existing file, now refuse a file the agent hasn't read with
482
+ `read_file` in this session, or one that changed on disk since it did. Benchmark
483
+ runs caught the agent patching files it had never opened, from a grep snippet
484
+ or a guess; now it has to look first. A partial read counts, creating a file
485
+ needs no read, and the refusal comes before any approval prompt. It applies
486
+ with confirmations bypassed too.
487
+ - **The agent sees every installed skill and loads the one that fits.**
488
+ Previously a per-turn matcher scored the request against skill descriptions
489
+ and loaded a skill on 0 of 24 benchmark tasks, so most GitHub requests never
490
+ learned `gh` was available. The system prompt now lists each installed skill
491
+ in one line (~1,000 tokens for the starter pack), and refusing a skill-gated
492
+ CLI names the skill to load. `GAIA_SKILL_DISCOVERY=0` still hides the list.
493
+ **Removed:** `GAIA_SKILL_DISCOVERY_TAU` is now ignored, and
494
+ `GaiaAgentConfig(skill_discovery_threshold=…)` raises `TypeError` — drop the
495
+ argument. See the Agent Skills spec, "Skill catalogue".
496
+ - Contract `apiVersion` is now **2.14** (2.13 added `GET /memory`) for the two new routes and
497
+ the `claude` provider value. A differing major still raises
498
+ `VersionMismatchError`; a higher minor is accepted.
499
+ - **Changing `model` on a live `session_id` switches in place** instead of
500
+ returning 409, so the conversation and any loaded skills survive it. A switch
501
+ that fails still returns 409 and leaves the session on its previous model.
502
+
503
+ ### Fixed
504
+
505
+ - **Answering the agent's question from the Agent UI or the TUI works.**
506
+ `POST /query/{run_id}/respond` only took the answer as `response`, while
507
+ both front-ends send `{ request_id, value }` as the contract specifies, so
508
+ every answer was refused and the run waited until the question timed out.
509
+ It now takes `value`. `response` is still accepted; sending both, or
510
+ neither, is a 422.
511
+ - **A file you allow is usable by every tool, including document Q&A.** Indexing
512
+ or querying a file outside the chat's scope was refused with no prompt, and
513
+ approving it through another tool still left it unreadable to the document
514
+ index. Indexing now asks the same question `read_file` does, and one approval
515
+ covers both. A tool waiting on that question is no longer abandoned at its
516
+ 180 s limit while the question is still on screen. A refusal now tells the
517
+ model not to copy or move the file elsewhere to get around it.
518
+ - **`--use-claude` works with the downloaded binary.** The release build left
519
+ out the Anthropic client, so every Claude launch from the terminal UI, and
520
+ every `/model` switch to Claude, failed with "The 'anthropic' package is
521
+ required", which a frozen binary cannot act on. The client is now bundled, and
522
+ the release build fails if it is missing.
523
+
524
+ - **Code search works in an Agent UI chat that is not inside a project.** It
525
+ started in GAIA's own documents folder, which usually does not exist yet, so
526
+ every `search_code_index` failed with "repo_path does not exist". It now starts
527
+ in a repository the chat can reach, else any folder it can reach that exists.
528
+
529
+ - **`/model` no longer offers speech or other non-chat models as chat
530
+ targets.** Whisper was listed as a "chat-capable" local model; switching to it
531
+ reported success and broke the next turn. Transcription, speech, music,
532
+ classification, upscaling and 3D models are excluded; a model labeled `chat`
533
+ still qualifies even if it also transcribes.
534
+ - **The agent no longer starts an unrelated job after answering.** A bugfix
535
+ request loaded the `coding` skill, whose "find every call site" tip switched
536
+ on document inventorying; after the fix was done and verified, the agent spent
537
+ minutes extracting every file it had read until the user cancelled. Only a
538
+ skill built on the extraction tool turns inventorying on now. Separately,
539
+ once a turn has answered, a tool call on nothing the request touched is not
540
+ run and a second one ends the turn, and a tool that keeps failing with new
541
+ arguments is stopped like an identical repeat.
542
+ - A "no" now covers what an action does, not the one tool it was asked
543
+ through. After you decline `pytest`, or leave its prompt unanswered, the
544
+ agent no longer writes `run_tests.py` and runs it with another tool: any
545
+ call that would run the tests, reach the same host, or change the same file
546
+ is stopped for the rest of that request. Where the surface can ask, you get
547
+ the exact command and why, with Allow once / Don't run it; otherwise the
548
+ agent stops and asks in its reply.
549
+ - `/v1/gaia/query` now honours `provider` on an existing session. It used to
550
+ matter only when the session was created, so `provider: "lemonade"` could keep
551
+ sending a Claude session's conversation to Anthropic, and `provider: "claude"`
552
+ could run locally. A different provider now switches the session in place.
553
+ Naming a `model` that belongs to the other provider is a 400, on new and
554
+ existing sessions alike. Omitting `provider` and naming a Claude `model` now
555
+ starts a Claude session, the way it already switched an existing one — it used
556
+ to point the local backend at an id it cannot serve.
557
+ - "Lemonade is not reachable" errors no longer tell users to run
558
+ `lemonade-server serve`, a command current Lemonade installs don't have. The
559
+ `GET /v1/gaia/init` hint, run errors, and `/model` now say how to start
560
+ Lemonade on the user's own install (tray app, macOS app, service, or CLI).
561
+ `/model <unknown>` with nothing downloaded likewise names the download command
562
+ the host actually has, instead of the removed `lemonade-server pull`.
563
+ - `gaia serve` no longer exits 0 when Ctrl+C fails to stop the sidecar. The
564
+ error naming the surviving process and how to kill it was discarded, so the
565
+ next `serve` hit an unexplained port conflict. It now prints that error and
566
+ exits 1.
567
+ - Conversation state is saved under `~/.gaia/sessions` instead of the directory
568
+ the agent was started from. A `session_id` must be 1–128 characters from
569
+ `A-Z a-z 0-9 . _ -`; any other value is a 400 on `/query` and
570
+ `/sessions/{session_id}/bypass` instead of a 500. A corrupt saved session fails
571
+ the request instead of being silently replaced.
572
+ - `gaia hub install gaia` no longer refuses Intel Macs: the hub manifest now
573
+ lists `darwin-x64`, which the release already builds and the lock already ships.
574
+ - The hub install card advertises the declared npm package instead of an unpublished PyPI wheel.
575
+ - The readiness check (`GET /v1/gaia/init`) and the terminal session's health
576
+ report name GAIA's own Lemonade Server instead of Lemonade's default port.
577
+ - Clearing a TUI conversation now also clears the flagship stdio agent’s prior
578
+ conversation context, while preserving the selected model, skills, and permissions.
579
+ - Internal session deletion (not yet exposed by a route) refuses busy agents instead of closing them mid-turn.
580
+ - Scratch files no longer land in the user's project. The system temp dir was
581
+ out of scope, so the agent wrote throwaway test runners and intermediate files
582
+ into the repository instead. It now gets its own scratch directory, named in its
583
+ prompt and deleted when the agent closes; the rest of the temp dir stays denied.
584
+ - Every file tool now checks the same allowed-folders rule as `read_file`:
585
+ browsing, folder and content search, recent files, document indexing, folder
586
+ watching, code indexing, and where screenshots, transcripts and exports are
587
+ saved. A folder outside the scope gets the usual approval prompt, and a folder
588
+ you approve is readable by document indexing too.
589
+
590
+ ### Added
591
+
592
+ - **A committed, machine-readable `/query` contract.** `openapi.gaia.json` in
593
+ the Python package is generated from the live routes
594
+ (`python -m gaia_agent.export_openapi`) and checked for drift in CI, so a
595
+ typed client no longer has to reverse-engineer the body from prose —
596
+ `query`, `run_id`, and `context` are required, `run_id` must be a UUID, and
597
+ the bearer-auth posture is declared in the schema. Swagger UI (`/docs`) is
598
+ disabled on the sidecar — it loads its JS from a CDN, an unexpected network
599
+ call for an offline embedder — but `/openapi.json` is still served.
600
+ - **Programs the agent starts no longer inherit GAIA's internal credentials.**
601
+ Shell commands, MCP servers, CLI installs and sign-ins, native hub agents,
602
+ media tools and the Lemonade server get the sidecar's environment minus
603
+ GAIA's own tokens. Your own variables (`GH_TOKEN` and the like) still pass through, so CLI skills
604
+ keep working. An embedding app can withhold more names with
605
+ `GAIA_CHILD_ENV_DENY` (comma or space separated), and can stop GAIA loading
606
+ `.env` files with `GAIA_NO_DOTENV=1` — read from the real environment, so a
607
+ `.env` cannot set it.
608
+ - **The agent can drive a real browser.** Pages behind JavaScript or a login
609
+ used to be out of reach — `fetch_page` is one HTTP GET, so a signed-in inbox
610
+ or a dashboard came back empty. Eight new tools open a real Chromium, read
611
+ it, click and type in it, and sign in to a site; the password goes to the
612
+ human, never the model, and the session is stored encrypted. Acting inside a
613
+ session you signed in to asks first. Ships behind the optional `browser`
614
+ extra; without it none of the eight register. Registered tool count goes
615
+ 88 → 96.
616
+ - **Fast mode, for a session that's only conversation.** `GAIA_FAST=1` drops
617
+ the flagship to a plain conversational surface for the whole session —
618
+ 3,110 tokens of fixed prompt instead of 17,942 — so saying "hi" no longer
619
+ costs as much as a repo search. Session-scoped and one-way: a fast session
620
+ has no documents, files, web or skills and cannot pick them up mid-way.
621
+ - **`chat`, `doc` and `file` are no longer offered as agents.** New users saw
622
+ four entries in the picker where only one is the product. The three ids still
623
+ resolve, so existing sessions, `*-lite` aliases and eval scenarios keep
624
+ working — they are hidden, not deleted, and `ChatAgent` remains the
625
+ flagship's base class. A session created without an explicit agent now lands
626
+ on the flagship rather than a hidden agent.
627
+ - **Complete inventories from long documents.** Asking for every exercise,
628
+ action item or finding in a transcript now returns all of them, each with its
629
+ source quote, instead of a condensed list. The opt-in `document-extract` skill
630
+ drives new `extract_document_items` and `save_extracted_items` tools; a save is
631
+ reported only after the exact file is written and read back, and anything
632
+ unfinished is reported as incomplete. `gaia-voice` gains one routing line
633
+ (702 tokens).
634
+ - **The agent can set up a skill's CLI instead of handing the job back.** Asking
635
+ it to triage GitHub issues on a machine without `gh` used to end the
636
+ conversation. Three new tools — `check_cli_setup` (read-only), `install_cli`
637
+ and `sign_in_cli` — let it report exactly what is wrong, install the CLI with
638
+ the machine's package manager, and drive the browser sign-in. Both mutating
639
+ tools are confirmation-gated on every call and no skill grant pre-approves
640
+ them; over `/v1/gaia/query` they are refused, like every other gated tool
641
+ (§8). Registered tool count goes 83 → 86.
642
+ - **A shell command's `cd` now survives to the next one.** Every
643
+ `run_shell_command` call used to start from scratch, so `cd build` in one
644
+ call was invisible to the next. `get_shell_state` reads the session's
645
+ current directory, and `reset_shell_session` returns it to where the task
646
+ started. Registered tool count goes 86 → 88.
647
+ - **Say something while the agent is still working.** `POST
648
+ /v1/gaia/query/{run_id}/followup` hands a live run a message the user typed
649
+ after it started (contract **2.15**). The run is not interrupted and no
650
+ second turn starts — the agent folds the text into the turn already running
651
+ at its next step boundary, so a correction during a five-minute task changes
652
+ that task instead of arriving after it finished. Unknown run → `404`, an
653
+ agent that cannot take one → `409`; both loud, because the caller has already
654
+ taken the message from the user. See SPEC §5.6 and SKILL §7.
655
+ - **Approve a gated tool over HTTP.** `write_file`, `run_shell_command` and the
656
+ seven other confirmation-gated tools can now run through `/v1/gaia/query`:
657
+ the stream stays open on `needs_confirmation` and
658
+ `POST /v1/gaia/query/{run_id}/tool_decision` answers it. Previously the only
659
+ possible answer was a refusal, so those tools were unreachable over HTTP.
660
+ `POST /v1/gaia/sessions/{session_id}/bypass` turns the asking off for a
661
+ session. A run that cannot answer — no `session_id`, or
662
+ `can_answer_questions: false` — is still refused. See SKILL §8.
663
+ - **Claude as an inference backend.** `provider: "claude"` sends the
664
+ conversation to Anthropic's API instead of the local server; `model` then
665
+ names a Claude model. Anything outside `lemonade` / `claude` is still a 400.
666
+ - **`gaia-agent --serve` works from a pip install.** The console script pointed
667
+ past the transport dispatcher, so the documented HTTP mode exited with
668
+ "unrecognized arguments".
669
+ - **Tracked eval scorecard ([`SCORECARD.md`](./SCORECARD.md)).** The agent now
670
+ ships a per-release scorecard: judged-scenario pass rate (the aggregate)
671
+ plus per-category rates and the judge's average score across the
672
+ 13-category eval corpus (`eval/scenarios/gaia_*`), generated by
673
+ `hub/agents/gaia/python/packaging/gen_scorecard.py` from real
674
+ `gaia eval agent --agent-type gaia` runs. CI runs a PR subset
675
+ (`test_gaia_agent_eval.yml`), the weekly sweep runs the full corpus, and the
676
+ release pipeline gates on the committed card
677
+ (`scorecard-gate` + a judged eval subset in `release_agent_gaia.yml`).
678
+ The initially committed card is a harness validation measured with the
679
+ agent on `claude-haiku-4-5` (the dev environment cannot run Lemonade); the
680
+ first full runner refresh (`gaia_scorecard_refresh.yml`) replaces it with
681
+ the Gemma-4-E4B product baseline.
682
+ - **`capture_skill` — capture a skill from pasted `SKILL.md` text, a URL, or a
683
+ local folder, with code inert until trusted.** The agent can now bring a
684
+ skill into `~/.gaia/skills` straight from the conversation (68 registered
685
+ tools, up from 67). Every capture is confirmation-gated, security-audited (a
686
+ `BLOCK` verdict refuses it), SSRF-guarded on the URL path, and lands at the
687
+ `experimental` tier. Instructions load immediately; any `tools.py`/scripts
688
+ the bundle carries stay **inert** until the user runs
689
+ `gaia skill promote <name>` in a terminal, which re-audits and binds trust
690
+ to the audited bytes. Over `/query`, `capture_skill` is gated like the
691
+ other confirmation tools (SKILL §8; SPEC §5.2 documents the load-time
692
+ deferral).
693
+ - **`run_python`, always on.** A quick calculation or data transform is now one
694
+ confirmation-gated call that runs from the project root and returns what it
695
+ printed, instead of a throwaway script left in your repository. It joins the
696
+ always-on tool set (about 250 more prompt tokens per call) and the `shell`
697
+ bundle.
698
+ - Opt-in developer-mode skill and consent-gated MCP handoffs to Claude Code/Codex,
699
+ with managed worktrees, approved feedback snapshots and reported preview results.
700
+ Python `[mcp]` installation is required for the bridge; normal mode has no access.
701
+ - **The shell, always on inside a code repository.** When the project map
702
+ resolves to a repository (a VCS directory or a known manifest at its root),
703
+ `run_shell_command` is offered on every turn instead of only when the request
704
+ happens to sound like a shell request. Coding tasks such as "skip these tests
705
+ on PRs" previously ran without a shell and did every grep through `run_python`.
706
+ It follows the *same* root the map already uses, so the sidecar needs
707
+ `GAIA_PROJECT_ROOT=/path/to/repo` (or `GaiaAgentConfig(project_root=...)` when
708
+ embedding) to see your repository — its own working directory is whatever
709
+ started it, not yours. With no repository nothing changes, and the shell's
710
+ approval gate still applies either way. See SKILL §11.
711
+ - **`sleep`, always on.** The agent can now wait before retrying, e.g. until a
712
+ rate limit resets, instead of giving up; before, its only way to wait was
713
+ `time.sleep` inside a confirmation-gated `run_python`. Up to five minutes per
714
+ call, no approval needed, and Stop ends the wait within a second. It joins the
715
+ always-on tool set (about 190 more prompt tokens per call) and the
716
+ `loop_control` bundle (80 tools → 81).
717
+ - **`--bypass-permissions` now lifts the shell guardrails too.** It used to skip
718
+ only the confirmation prompt, which left the agent unable to run a build or a
719
+ test suite even with the user's blanket consent: no interpreter, test runner
720
+ or package manager was reachable, and nothing could write its output anywhere.
721
+ Under bypass, redirection (`>`, `>>`, `<`), backgrounding (`&`), substitution
722
+ (`` ` ``, `$()`) and the newline now parse and run — chaining with `&&` / `||`
723
+ / `;` / `|` already worked by default — the
724
+ read-only allowlist is replaced by a developer set (`node`, `npm`, `make`,
725
+ `cmake`, `go`, `cargo`, `sed`, `awk`, `curl`, `sleep`, `timeout`, `export`,
726
+ `cp`, `mv`, plus `python` / `python3` / `pytest` / `gh` / `git`), and the
727
+ shell rate limit is dropped. Off by default and byte-identical to before when
728
+ off. `git` in that set means its policy's outright refusals — push, reset,
729
+ rebase — also stop applying under bypass. `rm` stays excluded. Every command run this way is audit-logged with its full
730
+ arguments. Stdio only — an HTTP session's `/bypass` stops its approval prompts
731
+ but never lifts the shell gates, and the request body cannot ask for it.
732
+ Redirection has one exception: a command that
733
+ is nothing but a skill-granted CLI runs argv-only, so `>` there is refused
734
+ with an explanation instead of reaching the binary as text. See SPEC §5.5.
735
+
736
+ ### Also in 0.3.0
737
+
738
+ These were still listed under Unreleased when 0.3.0 was tagged, so they
739
+ shipped in it.
740
+
741
+ - **Finished work is no longer replaced by "I can't confirm this is done".** A
742
+ redaction task that loaded the `document-extract` skill had its answer swapped
743
+ for a coverage warning about its own `redaction_log.csv`, and a task with two
744
+ named outputs only knew about the last one. Every file the request names, and
745
+ every file the turn wrote, is now an output and never a source; the skill
746
+ checks coverage only when the request names a source document or asks for
747
+ every item. No check replaces a non-empty answer any more: an unproven
748
+ save, test result or extraction keeps the answer and adds a short "I
749
+ couldn't confirm all of this" list after it; a turn that ends early keeps
750
+ what it said ahead of its report; and a tool that keeps failing ends with the
751
+ model's answer from what it found, then the failure. A failed image request
752
+ is no longer rewritten into advice to start GAIA with an `--sd` flag that
753
+ does not exist. `load_skill` no longer tells the model the extraction tools
754
+ cannot run when it is about to register them, and a rejected extractor reply
755
+ is now logged.
756
+ - **`run_python` works in the Agent UI without a project.** It ran from the
757
+ server's own folder, which is not an allowed path, so every approved snippet
758
+ was refused and the agent fell back to slower shell commands. With no project
759
+ and a working directory you did not allow, a snippet now runs in the agent's
760
+ scratch directory, and its result says so. A project outside the allowed
761
+ paths is still refused.
762
+ - **An "always" answer for a shell command no longer covers code in the
763
+ scratch folder.** A command run there or naming a path there — `cd` into it
764
+ then `python -m explore`, or `pytest`, `make`, `pip install`, `uv run` or
765
+ `go run` pointed at it — and a script handed a scratch path as an argument
766
+ now ask every time, with no `always_scope`, the same as a script there.
767
+ `always_scope` labels for commands that run code they do not show now say so:
768
+ `pytest (runs the test code it finds)`, `make (runs the Makefile's
769
+ commands)`, `python -m explore (runs that Python module)`.
770
+ - **Exploring data no longer asks twice per step.** Each step wrote a helper
771
+ script into the agent's own scratch folder and ran it, so a data task asked
772
+ for approval about 30 times. Writes inside that folder now run unasked
773
+ (writes anywhere else still ask). Running a script from it asks each time
774
+ and offers no `always_scope`, since what is in that folder changes without
775
+ a prompt.
776
+ - **A command no loaded skill grants asks you instead of failing.** `python
777
+ script.py`, `git commit` or `pip install` with no skill granting them used to
778
+ come back as "needs a skill grant … declares 'shell:execute:git' in its
779
+ SKILL.md", which nobody could act on. They now raise the approval prompt; a
780
+ skill grant still skips it for reads. A prompt's `summary` for a write or
781
+ code-running command ends with one plain line on what it can do, and the
782
+ `in <folder>` line also appears when an earlier `cd` moved the session. A
783
+ call you decline tells the agent not to reach the same result another way,
784
+ and a run nobody can answer refuses in one plain sentence.
785
+ - **Commands GAIA's checks don't cover ask once instead of failing.** `git
786
+ push`, `git fetch`, `python -c`, PowerShell the checks can't read, a line with
787
+ shell operators, or a path outside the allowed folders used to be refused
788
+ outright. They now raise a prompt whose `summary` is the exact line the shell
789
+ will run, its full folder and a risk sentence, with no `always_scope`; an
790
+ approval runs that line once. Still refused with no prompt: an encoded
791
+ PowerShell command or invisible characters, a line whose quoting can't be
792
+ split the way the shell would, such a line that also deletes or discards work
793
+ (`git push --force`, `git reset --hard`, `rm` outside the project), and
794
+ folders no approval can open.
795
+ - **Long Python data jobs can finish.** `run_python` gave up after 60 s and
796
+ the agent abandoned `execute_python_file` at 180 s even when it had asked
797
+ for 15 minutes, while the script kept running and left a corrupt workbook
798
+ behind. Python runs now get 120 s by default and up to 1800 s on request,
799
+ the agent waits that long, and a run that runs out of time is killed with
800
+ every process it started; the result names the files that changed while it
801
+ ran so the agent checks them instead of reporting them finished.
802
+ - **Document search says when it could not search.** With the embedding
803
+ model or Lemonade Server down, `query_documents` and `query_specific_file`
804
+ answered "no relevant information found", so the agent told the user their
805
+ documents held nothing on the topic. They now return an error naming the
806
+ cause (Lemonade unreachable, or the embedding model failing) and how to fix
807
+ it. `index_document` and `index_directory` report the same cause, and
808
+ `index_directory` stops at the first such file and reports an error when no
809
+ file could be indexed. Hints for a missing optional package (RAG, PDF, Excel,
810
+ HTML parsing) say in a frozen build that it isn't bundled, and from source
811
+ give the install command for the running Python.
812
+ - **A failed tool call is reported as a failure.** `run_shell_command` returned
813
+ `status: success` for a command that exited non-zero, so the TUI and Agent UI
814
+ showed a failed build or test run as a passed step. It is now `status: error`
815
+ with an `error` naming the failing step, its exit code and the last stderr
816
+ line; `stdout`, `stderr` and `return_code` are unchanged. grep's no-match and
817
+ diff's "inputs differ" (exit 1) stay a success and say so in `expected_exit`.
818
+ An MCP tool that answers `isError`, a DuckDuckGo search that was blocked, a
819
+ `tasklist`/`wmctrl`/`osascript` window listing that failed, a notification
820
+ whose PowerShell died, and an `open_url` with no browser to open are errors
821
+ too. Install hints in a frozen build no longer name the binary as a Python to
822
+ run pip with.
823
+ - **Reviewing a few documents reads them in full.** `read_file` on a Word,
824
+ PDF or Excel file returned `[Binary file, N bytes]`, so to compare a term
825
+ sheet against a draft agreement the agent indexed them and ran a handful of
826
+ searches, and missed a closing date that differed between the two because no
827
+ search asked for it. `read_file` now returns the extracted text, in parts sized
828
+ to the model's budget that say where the next part starts, and the prompt
829
+ tells the agent to read a few documents in full for a review, comparison or
830
+ reconciliation and keep indexing for large collections and single lookups.
831
+ - **`fetch_page` no longer drops the middle of a long page.** Text past
832
+ `max_length` was cut to its head and tail, which is where a product page keeps
833
+ its menus and footer, not its price. It now returns the first part with a
834
+ marker naming the offset of the next, takes `offset` to continue and `find` to
835
+ jump to the passages containing a word, says so when a word is not on the
836
+ page, and flags a page with almost no static text as rendered by JavaScript.
837
+ `Length:` now reports the whole page rather than the excerpt.
838
+ - **Long desktop tasks finish with their deliverables instead of a bare "I
839
+ can't confirm this is done".** Picking a controller from nine datasheets and
840
+ pricing a 40-unit BOM ran out of its 50 steps while still searching for
841
+ prices, and the reply dropped the recommendation the agent had already
842
+ written. The agent's default step limit is now **150** (a `/query`
843
+ `max_steps` or `GAIA_AGENT_MAX_STEPS` still wins); at 20, 10 and 5 steps left
844
+ it is told to write the requested files from what it has, marking unverified
845
+ values, and a turn that still runs out keeps its findings and lists what is
846
+ missing after them.
847
+ - **The model notice is one line.** Switching or restoring a model printed a
848
+ four-sentence paragraph that named the model twice and said "via Lemonade".
849
+ It now reads like "Switched to **DeepSeek-V4.1-Flash** on the AMD LLM Gateway
850
+ (cloud). Your messages, and anything read from files or memory, are sent
851
+ there." The `/model` list drops "via Lemonade" from its headings and marks
852
+ the configured default model with `(default)`.
853
+ - **Single-file search results name their file.** `query_specific_file` put the
854
+ path only at the top of its result, so each chunk arrived with no source and
855
+ the chunk cards showed none. Every chunk now carries `source_file`, and the
856
+ result lists it in `source_files`, as `query_documents` already did.
857
+ - **The turn log counts the answer of a streamed turn.** With `GAIA_TURN_LOG`
858
+ set, a turn whose answer streamed out recorded `answer_chars: 0`. It now
859
+ records the length of the answer the user saw.
860
+ - **`run_python` and `execute_python_file` work in the released binary.** The
861
+ binary has no Python interpreter, so it handed every script to its own
862
+ argument parser, which rejected it, and no calculation, chart or `.xlsx`
863
+ could be produced. It now runs scripts itself, with pypdf, pymupdf,
864
+ python-docx, python-pptx, openpyxl, xlsxwriter, reportlab, pandas, numpy,
865
+ matplotlib and the full standard library bundled for them, and both tools
866
+ name those libraries to the model. A script that starts `sys.executable`
867
+ (`-m`, `-c`, a file) runs too; `-m pip` says packages can't be installed
868
+ and lists what is bundled. The Windows binary grows from 147 MB to 168 MB.
869
+ - **A Python script that fails is reported as a failure.** A non-zero exit
870
+ came back as `status: success`, so the TUI showed a failed run as
871
+ successful. It is now `status: error`, with an `error` naming the exit code
872
+ and the last stderr line; `stdout`, `stderr` and `return_code` are unchanged.
873
+ - **`GAIA_ALLOWED_PATHS` confines a run to the folders you name.** The agent
874
+ could read anything under the user's home and nothing narrowed that short of
875
+ embedding it, so an evaluation run could read the graders' answer keys. Set
876
+ to absolute folders, it narrows every file tool, search, index and shell path
877
+ check to them — it never widens, an invalid value stops startup, and code the
878
+ agent runs (`run_python`, shell) is not confined.
879
+ - **The sidecar's start-up warm-up now makes the first question fast.** It
880
+ primed only the agent's own instructions, without the tool list or the rest
881
+ of the system prompt, so the first question re-read all ~19K prompt tokens
882
+ (34 s on Qwen3.6-35B-A3B). It now sends exactly what a turn sends, and the
883
+ first question reads only its own ~50 tokens (5 s). A warm-up that fails is
884
+ logged as a warning with its cause instead of an info line.
885
+ - **`/model` names the command that connects a cloud provider.** With no
886
+ Fireworks or AMD gateway connection, the list told users to "connect this
887
+ provider in the TUI provider settings", a screen with no obvious way in. It
888
+ now says to run `/provider`, the command that opens it.
889
+ - **The TUI's provider picker works after GAIA's Lemonade restarts.** When the
890
+ agent ran as the TUI's own child, its model-state ping kept naming the port
891
+ Lemonade started on, so after a restart the picker said "Lemonade did not
892
+ respond" while chat worked. With a local or cloud chat model the ping now
893
+ reports the port the agent talks to, and it still never starts a stopped
894
+ server. A Claude session still reports the port it started with.
895
+ - **The Agent UI's Skills settings list this agent's skills.** With the agent
896
+ installed from the Hub, the page said the agent package was not installed
897
+ and to run `gaia init`, which changed nothing: the bundled skills live
898
+ inside the binary, where the UI could not read them. `GET /v1/gaia/skills`
899
+ (contract **2.17**) now returns them.
900
+ - **A message sent right after Stop is answered instead of refused.** A stopped
901
+ turn holds its session until its model call returns, so the next `/query`
902
+ got `409 … is already running a turn` for as long as the stopped answer would
903
+ have taken — about 40 s for a long one. It now waits for the stopped turn to
904
+ finish (up to 240 s) and then runs. A turn that was not cancelled is still
905
+ refused at once.
906
+ - **Documents attached to a chat now reach the agent.** In the Agent UI, a
907
+ Hub-installed agent answered "no documents are indexed" about a file the user
908
+ had attached, because the relayed turn never carried the chat's files.
909
+ `/query` now takes a `documents` field (contract **2.16**): the agent indexes
910
+ them before the turn, granting each exact file and not its folder, including
911
+ a file attached partway through a conversation.
912
+ - **The first chat after the agent starts uses its own tools.** A session built
913
+ while the start-up warm-up was still building could end up running the
914
+ warm-up agent's tools, so a file it had just indexed read as access denied.
915
+ Agents are now built one at a time.
916
+ - **Web requests work behind a corporate TLS-inspecting proxy.** HTTPS now
917
+ trusts the operating system's certificate store, as pip does, instead of only
918
+ Python's bundled list, so a proxy root such as Zscaler's no longer fails every
919
+ fetch with `CERTIFICATE_VERIFY_FAILED`.
920
+ - **Starting the agent no longer downloads a model you skipped.** The HTTP
921
+ sidecar's start-up warm-up skips the default local model when it is not
922
+ downloaded, so someone using a cloud model is not handed a multi-GB download
923
+ they never asked for.
924
+
925
+ ### Notes
926
+
927
+ - Tracks sidecar contract `apiVersion` **2.17**; a differing major raises
928
+ `VersionMismatchError`.
929
+ - `GET /v1/gaia/memory` (contract 2.13) answers the same read-only snapshot the
930
+ stdio transport's `/memory` sentinel produces, so a daemon-supervised
931
+ install of the flagship exposes `/memory` too, not just a subprocess one.
932
+
933
+ ## [0.2.0] — 2026-09-16
14
934
 
15
935
  ### Fixed
16
936
 
@@ -29,7 +949,6 @@ the terminal UI meant building it from source.
29
949
  on the previous image.
30
950
  - TUI provider setup for Local, Fireworks AI, and AMD LLM Gateway, with masked
31
951
  runtime API keys, discovered models, and remote-inference status.
32
-
33
952
  - **A project map at task start.** In a code repository the agent now opens
34
953
  every task knowing the directory shape, the likely entry points, which
35
954
  commands are installed, and the three platform differences that change
@@ -38,10 +957,6 @@ the terminal UI meant building it from source.
38
957
  starts one in the background; `GAIA_PROJECT_MAP_AUTO_INDEX=0` turns that off,
39
958
  and `GAIA_PROJECT_ROOT` picks the project when the working directory is not
40
959
  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
960
  - **Three further client-visible refusals from `/query`.** Reusing a `run_id`
46
961
  that is still in flight gets `409` — it used to replace the live run, leaving
47
962
  it with no way to be cancelled. Supplying a `model` that differs from the one
@@ -49,21 +964,17 @@ the terminal UI meant building it from source.
49
964
  the old model. A request with an absent or empty `Host` header gets `400`
50
965
  rather than being served, closing a DNS-rebinding check that failed open.
51
966
  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
967
  - **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
968
+ profile.** The model is sent about 28 of its 84 tools on any one call — a
60
969
  fixed core plus whichever cohesion bundles the query matched — instead of the
61
970
  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.
971
+ hatch the model calls mid-turn to pull in a bundle the selector missed; that
972
+ bundle is appended for the rest of the turn (briefly above the cap, which the
973
+ next turn restores) so the prompt already sent stays cached.
63
974
  `GAIA_DYNAMIC_TOOLS=0` turns the selection off, `GAIA_DYNAMIC_TOOLS_MAX`
64
975
  moves the cap and `GAIA_DYNAMIC_TOOLS_TAU` the match threshold.
65
976
  - **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
977
+ entry, so it is always on and rendered in full on every LLM call — 702 tokens
67
978
  of every prompt, and it declares no tools. It is the agent's honesty floor
68
979
  (don't claim work you didn't do, don't present empty output as a result,
69
980
  don't substitute a near-miss and report success), which is why it is not in an
@@ -75,46 +986,6 @@ the terminal UI meant building it from source.
75
986
  behavioural rules intact. It had been a rationale document — every rule
76
987
  followed by the incident that motivated it — and the model needs the rule,
77
988
  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
989
  - **The `.installed` record is written after a verified sidecar install.**
119
990
  Staging the binary was only half an install: the daemon and the terminal UI
120
991
  both key "this agent is installed" on `~/.gaia/agents/gaia/.installed`, and
@@ -205,14 +1076,83 @@ the terminal UI meant building it from source.
205
1076
  that killed only the launcher: the cancelled tool call ran to completion and
206
1077
  the surviving process consumed the next message. The first Esc now sends the
207
1078
  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
1079
+ loaded skills, "always" grants, history and full access. A second Esc stops
209
1080
  the whole process tree.
210
- - **A restart after a hard stop no longer turns bypass permissions back on.**
1081
+ - **A restart after a hard stop no longer turns full access back on.**
211
1082
  The replacement agent is launched in the session's current permission mode
212
1083
  instead of from the original flags, and the TUI says what the restart lost.
213
1084
 
214
1085
  ### Notes
215
1086
 
1087
+ - `gaia_agent` enforces a per-session caller-auth bearer on every `/v1/gaia/*`
1088
+ request, plus a loopback `Host` allowlist and non-loopback `Origin` rejection.
1089
+ This package mints no token, so a sidecar it spawns comes up in dev mode (token
1090
+ check skipped, loudly warned, Host/Origin still enforced) — pass your own
1091
+ through `spawnSidecar`'s `env` to turn it on. See SPEC §5.4.
1092
+
1093
+ ## [0.1.1] — 2026-08-21
1094
+
1095
+ First working release. `npx @amd-gaia/gaia` is now the single command that gets a
1096
+ user running GAIA: it fetches and verifies everything GAIA needs and drops them
1097
+ into the terminal UI. Before this there was no packaged path at all — the flagship
1098
+ agent had to be run from a repo checkout with a Python environment, and reaching
1099
+ the terminal UI meant building it from source.
1100
+
1101
+ ### Added
1102
+
1103
+ - **`503` from `/query` at session capacity.** When every retained session
1104
+ slot is busy and none is idle enough to evict, starting a new session
1105
+ returns `503` with the reason in `detail` — retryable, distinct from a
1106
+ bug-shaped `500`. See SPEC §5.2.
1107
+ - **Per-turn skill-body selection.** A loaded skill stays loaded, but its body
1108
+ only renders in the prompt on turns whose query matches its description; the
1109
+ rest collapse to a one-line menu the model re-activates with `load_skill`.
1110
+ `GAIA_DYNAMIC_SKILLS=0` turns the selection off, `GAIA_DYNAMIC_SKILLS_TAU`
1111
+ overrides the match threshold, and an embedder outage disables it for the
1112
+ session (every body renders — capability is never lost to a failed match).
1113
+ - **`gaia run` (the default command)** — resolves the host platform, fetches and
1114
+ SHA-256 verifies both binaries, then launches the terminal UI and propagates its
1115
+ exit code. Arguments after a bare `--` are forwarded to the TUI verbatim.
1116
+ - **Dual-binary delivery.** The package installs two published artifacts: the
1117
+ frozen agent sidecar (`gaia-agent`), published by this package's own release,
1118
+ and the terminal UI (`gaia-tui`), which is the published **`terminal-hub`**
1119
+ component. The TUI is consumed, not rebuilt — it is byte-for-byte the binary a
1120
+ full GAIA install runs as `gaia tui`, so an npm user and a core user cannot end
1121
+ up on terminal UIs that behave differently. A second build under this package's
1122
+ own lane would have been the same bytes at a different version under a third
1123
+ naming convention, and the two would have drifted.
1124
+ - **`binaries.lock.json` `schemaVersion` 3.0** — a component-keyed checksum
1125
+ manifest where **each component carries its own `componentVersion`, `baseUrl`
1126
+ and `platforms`**. Component-first rather than the email agent's flat `binaries`
1127
+ map because the two differ in every dimension: hub lane, version, and platform
1128
+ coverage (terminal-hub covers arm64 Linux and arm64 Windows; the PyInstaller
1129
+ sidecar does not). A single shared base URL cannot address two lanes, so a
1130
+ `1.x`- or `2.x`-shaped lock is rejected at load with an error naming the schema.
1131
+ - **Terminal-hub artifact naming is handled in data.** That lane names its Windows
1132
+ builds `gaia-win-x64.exe` / `gaia-win-arm64.exe`, while platform keys come from
1133
+ `process.platform` and say `win32`. The lock keeps the `win32-*` key and carries
1134
+ the hub's spelling in `filename`, so nothing branches on platform to construct a
1135
+ URL. The mapping is asserted on both sides (`TUI_ARTIFACT_NAMES` in
1136
+ `src/platform.ts` and in the lock generator) because a wrong name there is not a
1137
+ build failure anywhere — it is a 404 on a user's first run.
1138
+ - **Mandatory SHA-256 verification.** Every download is hashed and compared
1139
+ against the lock before it is written. A mismatch deletes the download and
1140
+ raises `IntegrityError` naming expected vs actual. A placeholder hash blocks the
1141
+ fetch before any network call. There is no flag that relaxes either.
1142
+ - **`gaia fetch`** — download and verify without launching; prints JSON. Supports
1143
+ `--component` and `--platform` for cross-platform staging in CI.
1144
+ - **`gaia serve`** — run the agent sidecar alone on `127.0.0.1:8141` for
1145
+ integrators who want the REST surface without a daemon or a UI. Health-polls
1146
+ `GET /health`, checks the contract version, and tree-kills on exit. Port `4001`
1147
+ is refused.
1148
+ - **`gaia version`** — prints, per component, its version, the URL it is fetched
1149
+ from, and its platform matrix.
1150
+ - **Programmatic exports** — `fetchAll`, `startSidecar`, `shutdown`, `runTui`, the
1151
+ platform helpers, and the typed error classes, for embedding GAIA in another
1152
+ app.
1153
+
1154
+ ### Notes
1155
+
216
1156
  - The sidecar is installed into `~/.gaia/agents/gaia/`, the GAIA daemon's own
217
1157
  cache directory. The daemon spawns and supervises the sidecar; putting an
218
1158
  already-verified binary where it looks turns its fetch into a cache hit instead
@@ -229,16 +1169,9 @@ the terminal UI meant building it from source.
229
1169
  building its own TUI. Each terminal-hub artifact is additionally cross-checked
230
1170
  against the hub's own server-side SHA-256 before its hash enters the lock.
231
1171
  - 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.
1172
+ inference, and the `gaia` Python CLI 0.25.2+ on `PATH` for the daemon the TUI
1173
+ starts. 0.25.2 is the first core that can run the current release; on an
1174
+ earlier core the UI starts with nothing behind it.
235
1175
  - The sidecar has no arm64 Linux or arm64 Windows build. On those platforms the
236
1176
  run stops with an error naming the platform and the supported set rather than
237
1177
  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`.