Skip to content

test(installer): expect the not-executed flag on a refused MCP tool call - #3736

Merged
kovtcharov-amd merged 1 commit into
mainfrom
fix/mcp-harness-executed-flag
Sep 14, 2026
Merged

kovtcharov-amd merged 1 commit into
mainfrom
fix/mcp-harness-executed-flag

Conversation

@kovtcharov-amd

Copy link
Copy Markdown
Collaborator

The custom-agent MCP harness has been failing on main since #3703, which is why unrelated PRs are showing a red Custom agent MCP harness job.

#3703 made a refused tool call declare that it never ran. The harness compares the whole result dict, so the added executed: False broke the assertion. It went unnoticed because this file lives under tests/installer/ and runs in its own workflow rather than the unit suite — so it turned main red instead of failing on the PR that changed the shape.

I pinned the flag rather than loosening the comparison: a refused call reporting itself as not-executed is exactly the contract #3703 added, and this is the only harness that exercises it through a real agent.

Test plan

#3703 made a tool refusal declare that it never ran, so `_execute_tool`'s
unknown-tool path returns `{**NOT_EXECUTED, "status": "error", ...}`. This
harness compares the whole result dict, so the new `executed: False` broke
it — and because the file lives under `tests/installer/` it runs in its own
workflow rather than the unit suite, so it went red on main instead of on
the PR that changed the shape.

Pinning the flag here rather than loosening the comparison: that a refused
call reports itself as not executed is the contract #3703 added, and this is
the only harness that exercises it through a real agent.
@github-actions github-actions Bot added the tests Test changes label Sep 12, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Verdict: Approve with suggestions

This pins the "I refused before running anything" flag that #3703 started returning, so the custom-agent MCP harness stops failing on main and stops painting unrelated PRs red. The expectation matches what the agent actually returns today, and pinning the flag (rather than loosening the comparison to a subset match) is the right call — it keeps the harness as the one end-to-end check that a refused call reports itself as not having run.

One thing to know before merging: the job this PR fixes does not run on this PR. The harness lives in the installer-build workflow, whose pull-request trigger is path-gated to installer and Electron files — and tests/installer/** isn't on that list. The checks on this PR confirm it: there's no "Custom agent MCP harness" run. So the first test-plan checkbox can't be ticked here; you'll need a manual workflow run (or a local run) to prove it green before merging, or the fix lands on main unverified.

The same gap is why this broke in the first place. A change to the agent's tool-refusal shape doesn't trigger the harness either, so it turned main red instead of failing on the PR that changed it — exactly as the description says. Adding the installer test tree to that path list is a small change that makes this PR self-verifying and catches the next shape change on its own PR.

Real-world evidence

No evidence-bundle.md in the tree, and this reviewer image has no pytest, so I could not execute the harness. This is a test-only change with no user-facing surface, so the rubric's evidence requirement is N/A — but I did verify the expected dict against the source rather than taking it on trust:

  • src/gaia/agents/base/agent.py:3830 returns {**NOT_EXECUTED, "status": "error", "error": err} for the unknown-tool refusal, with that exact error string at line 3828.
  • src/gaia/agents/base/verification.py:66-69 defines EXECUTED_KEY = "executed" and NOT_EXECUTED = {EXECUTED_KEY: False}.

So the three-key dict the test now asserts is exactly what the refusal path produces. The verdict rests on that static match plus the CI-trigger check above — not on a harness run.

🔍 Technical details

🟡 The harness job isn't triggered by this PR's own path (.github/workflows/build-installers.yml:84-102)

build-installers.yml is the only workflow that runs tests/installer/test_custom_agent_mcp_harness.py (line 1207). Its pull_request.paths covers installer/**, the webui/electron-builder files, tests/electron/_helpers/**, tests/electron/*-smoke.test.mjs, tests/electron/fixtures/**, and src/gaia/version.py — not tests/installer/**. gh pr checks 3736 shows no "Custom agent MCP harness" job, so this fix merges without CI exercising it.

Minimal fix — add the harness tree to the filter so a PR editing the harness runs it:

      - 'tests/electron/fixtures/**'
      - 'tests/installer/**'
      - 'src/gaia/version.py'

Worth a separate discussion (not a blocker here): whether src/gaia/agents/base/** also belongs on that list. It would have caught #3703 on its own PR instead of on main, but it also puts the ~15-minute cross-platform build in front of a lot of ordinary agent PRs. A cheaper alternative is a unit-level assertion of the refusal dict's full shape in tests/unit/agents/ — that file already imports NOT_EXECUTED (tests/unit/agents/test_verification_scope.py:35), so the contract could be pinned where every PR runs it, leaving the installer harness as the end-to-end confirmation.

Strengths

  • Pinning executed: False instead of relaxing the equality preserves the assertion's value — a subset match would have silently accepted a regression that dropped the flag.
  • Hardcoding the literal "executed" rather than importing EXECUTED_KEY is the right choice for a black-box harness: it fails if the key is renamed, which is the observable contract an integrator depends on.
  • The inline comment explains why the flag matters (it's what keeps the verification footer honest) rather than restating the assertion — matches the repo's comment convention.

@kovtcharov-amd

Copy link
Copy Markdown
Collaborator Author

One thing to know before merging: the job this fixes does not run on this PR.

Custom agent MCP harness lives in build-installers.yml, which is reached by workflow_call on installer-path changes — it does not trigger when the harness test itself is edited. So a change to this file cannot be validated by the job that runs it, which is the same shape of gap that let the breakage reach main in the first place.

I verified the expected value against the source instead of guessing it: the unknown-tool path returns {**NOT_EXECUTED, "status": "error", "error": err}, and evaluating that gives {"executed": False, "status": "error", "error": "Unknown tool name. Use only the tools you were given."} — character-for-character what the assertion now expects, and what the failing run on #3342 reported as actual.

The real confirmation will be Custom agent MCP harness going green on #3342 once this lands.

@kovtcharov-amd
kovtcharov-amd added this pull request to the merge queue Sep 14, 2026
Merged via the queue into main with commit c11e2bf Sep 14, 2026
31 checks passed
@kovtcharov-amd
kovtcharov-amd deleted the fix/mcp-harness-executed-flag branch September 14, 2026 16:20
@kovtcharov-amd kovtcharov-amd mentioned this pull request Sep 14, 2026
11 of 12 tasks
github-merge-queue Bot pushed a commit that referenced this pull request Sep 16, 2026
# GAIA v0.24.0 Release Notes

## Breaking Changes

- **Thirteen per-task agents were removed** — `analyst`, `blender`,
`browser`, `code`, `doc-search`, `docker`, `docqa`, `emr`, `fileio`,
`jira`, `routing`, `sd`, `summarize`; it's a `SKILL.md` in `hub/skills/`
on the flagship now. Installing one by id fails — use `gaia hub install
gaia --trust` and load the matching skill. (PR
[#2995](#2995))
- **The TUI control API dropped its hub-browser fields** — `view` is now
`splash | preflight | chat`; `hub_tab`, `hub_tab_index`,
`selected_agent_id`, `visible_agent_ids`, `filtering`,
`can_return_to_hub` are gone, replaced by `blocker`. Anyone driving the
TUI over this API needs to update. (PR
[#3120](#3120))
- **`@tool(name=..., description=...)` no longer works** — the decorator
rejects unrecognized keywords instead of silently discarding them. Use
`@tool()`; name and description come from the function. (PR
[#3252](#3252))
- **`gaia telegram start` now requires `--allowed-users`**, no opt-out —
it used to start (and reply to anyone) without one. (PR
[#3306](#3306))
- **`gaia api --host` beyond loopback with no key now refuses to
start**, and `GAIA_API_KEY` gates chat completions too. (PR
[#3612](#3612))

## What's New

- **`gaia hub install gaia --trust` actually installs and runs the
flagship agent** — the daemon had no sidecar entry for it, the
installers didn't ship its binary, and `gaia init` set up the wrong
agent. All three are fixed. (PRs
[#3031](#3031),
[#3146](#3146),
[#3330](#3330),
[#3125](#3125),
[#3120](#3120))

- **The agent draws pictures, summarizes meetings, and orients itself
first** — "draw me a red bicycle" reaches the image tools; `summarize
this meeting: standup.mp4` returns a transcript with action items; and
every task scans the project first. Skills load themselves, and
corrections are learned into memory, not hand-edited into `SKILL.md`.
(PRs [#3073](#3073),
[#3597](#3597),
[#3405](#3405),
[#3010](#3010),
[#3023](#3023))

- **Every answer states whether it was checked** — the agent names what
it ran and what passed, not just reporting success. `--trace` in the TUI
records every tool call so a wrong answer can be replayed. (PRs
[#3397](#3397),
[#3579](#3579))

- **The TUI takes the mouse, draws to full width, and can go cloud** —
wheel-scroll, clickable links, no more 80-column wrapping, and a local,
Fireworks, or AMD Gateway model via Lemonade. (PRs
[#3699](#3699),
[#3006](#3006),
[#3672](#3672))

- **Run Lemonade without the machine-wide installer** — `gaia lemonade
embedded start` runs your own Lemonade Server, no admin rights needed.
(PR [#3121](#3121))

- **Mine your own Claude Code sessions for usage stats** — a
deterministic, LLM-free pipeline turns your `~/.claude/projects/`
transcripts into tool-usage, failure, and cost reports. See the [Session
Analytics guide](https://amd-gaia.ai/docs/reference/session-analytics).
(PRs [#3111](#3111),
[#3782](#3782))

## Security

- **Any web page you visited could drive GAIA's local servers** — a
cross-origin request could start a tunnel, poison your RAG store, or
send mail; a document link could make the chat agent fetch cloud
metadata or the daemon's loopback API. Middleware now enforces
`Origin`/`Host` checks everywhere, and web tools refuse private/loopback
redirects. (PRs [#3366](#3366),
[#3612](#3612))
- **A Telegram bot with no allowlist replied to anyone on the platform**
(the documented default) — off-allowlist users are now refused before a
session or model call; the bot's tool surface is chat-only. (PR
[#3306](#3306))
- **Attaching a document could silently widen the agent's read scope to
its whole parent directory** — the grant is now the file itself; reads
gained a credential denylist, and writes refuse shell rc files,
PowerShell profiles, and git hooks. (PR
[#3594](#3594))
- **A chat turn could plant `system`/`permission` rows into every future
prompt** — only onboarding/admin paths can write them now. (PR
[#3614](#3614))

## Bug Fixes

A selection of the user-visible fixes this release — the full list is in
the changelog below.

- **The flagship agent's core model floor now matches what can actually
run it** (PR [#3055](#3055)) — installs
no longer point at a Lemonade version too old to serve the agent.
- **A one-shot `/query` run no longer leaks an agent process** (PR
[#3079](#3079)).
- **The npm sidecar no longer attaches to a foreign server** (PR
[#3078](#3078)) — it now verifies the
server it finds is actually its own before using it.
- **A turn parked on a confirmation prompt no longer hangs when stdin
closes** (PR [#3080](#3080)) — the agent
ends the turn instead of waiting forever.
- **Telegram's background polling survives** (PR
[#3272](#3272)) — the adapter no longer
silently stops receiving messages.
- **`gaia uninstall --purge` removes the embedded Lemonade runtime it
installed** (PR [#3277](#3277)) —
previously a full purge left `~/.gaia/lemonade` behind entirely; a live
embedded daemon must be stopped first.
- **Outlook and Gmail search operators translate correctly for the email
agent** (PRs [#3042](#3042),
[#3562](#3562),
[#3619](#3619)) — a query that used to
fail silently or match the wrong messages against Outlook's Graph API
now works or fails loudly.
- **RAG indexing honors a document's actual success flag** (PR
[#3678](#3678)) — a failed index no
longer gets reported as indexed at every call site that checked it.
- **Claude tool-call history survives across turns** (PR
[#3410](#3410)) — a multi-turn tool
conversation no longer loses earlier tool results.
- **An ambiguous edit is refused instead of silently changing the first
match** (PR [#3396](#3396)) —
`edit_file` asks for a more specific match rather than guessing which
occurrence you meant.
- **A port collision between the MCP bridge, Agent UI, TUI, and Telegram
is resolved** (PR [#3604](#3604)) — the
four no longer fight over the same default port.
- **Telegram reports unsupported media types instead of failing
silently** (PR [#3263](#3263)).
- **`GET /health` reports real component status** (PR
[#2601](#2601)) — it used to report `ok`
even with a dead Lemonade backend; it now reports LLM and RAG status
too.
- **A `.bak` backup file could be imported as the module it backed up**
(PR [#3748](#3748)) — `.bak` now goes
last in the filename, so pytest no longer tries to collect a test file's
own backup.
- **A PowerShell sink could execute untrusted text instead of just
displaying it** (PR [#3359](#3359)) — an
apostrophe in an indexed document name, or in a `notify_desktop`
message, ran as code; both now pass values out-of-band.
- **`--scopes` could request an OAuth scope outside a connector's
declared ceiling** (PR [#3247](#3247)) —
the CLI's verbatim-scopes path skipped the check the Agent UI already
had; both now enforce it.

## Contributors

Thanks to the community members who contributed to this release:

- [@mikemikimike](https://github.com/mikemikimike) — Telegram
background-polling and media-handling fixes, embedded-Lemonade uninstall
cleanup, and TUI init-process reaping (PRs
[#3272](#3272),
[#3277](#3277),
[#3271](#3271))
- [@itomek](https://github.com/itomek) — custom-agent guide fixes and CI
reliability work, including provisioning the dev install in Claude Code
cloud sessions (PRs [#3317](#3317),
[#3033](#3033))
- [@Hashim1999164](https://github.com/Hashim1999164) — hub agent pages
showing the GAIA install path alongside npm, structured JSON for
unexpected email API errors, and Outlook Graph query-escaping fixes (PRs
[#3151](#3151),
[#3046](#3046),
[#3021](#3021))
- [@AmirF194](https://github.com/AmirF194) — Outlook/Gmail
search-operator translation for the email agent (PRs
[#3042](#3042),
[#3562](#3562),
[#3619](#3619))
- [@sujikathir](https://github.com/sujikathir) — the `/health`
component-status endpoint and a Claude tool-history preservation fix
(PRs [#2601](#2601),
[#3410](#3410))
- [@SIBTAIN-ASAD](https://github.com/SIBTAIN-ASAD) — Telegram
unsupported-media-type reporting and test coverage (PR
[#3263](#3263))
- [@wangzhengzhuo05](https://github.com/wangzhengzhuo05) —
MCP/Telegram/TUI port-collision fix across the bridge, Agent UI, and
daemon (PR [#3604](#3604))
- [@amd-pworfolk](https://github.com/amd-pworfolk) — stopped a non-LLM
model's `ctx_size` from leaking into `get_status()` (PR
[#3595](#3595))

## Full Changelog

**230 commits** since v0.23.0:

<details>
<summary>Expand full changelog (230 commits)</summary>

- `40e0dd89d` — docs(reference): add a user guide for Claude Code
session analytics (#3782)
- `f90fa5aae` — fix(docs): stop misclassifying GitHub anti-abuse resets
as broken links (#3800)
- `87313af75` — fix(daemon): reject a repo-root --dev-src-dir with a
corrected path (#3796)
- `cad3363f7` — fix(agents): isolate log records from abandoned
tool-timeout workers (#3795)
- `43dbce921` — fix(connectors): forward_connection uses the shared
scope resolver (#3792)
- `0c301bae3` — fix(tui): abandon queued follow-up on second Esc, add
stall nudge (#3798)
- `99caeaaf7` — fix(email-agent): close draft/RSVP/event gap in
fabricated-success guard (#3797)
- `8eb53c6b7` — fix(tui): name the buckets behind email pre-scan's +N
more (#3794)
- `5597e6a57` — fix(connectors): turn on include_granted_scopes for
Google OAuth (#3786)
- `76a7cde29` — fix(webui): show agent version in Hub Details modal
(#3784)
- `1474b12e9` — fix(tests): assert no render card for pre_scan_inbox
(#3785)
- `70de05022` — fix(email-agent): assert SCHEMA_VERSION, not a hardcoded
literal (#3787)
- `ddfdcabea` — fix(tests): skip live release-asset test on transient
network drops (#3788)
- `4740ec97f` — fix(email): point README at gaia init instead of removed
CLI (#3783)
- `ff62b4d54` — fix(agent): strip whitespace from tool names before
dispatch (#3744)
- `f39ead7ad` — fix(agent_loop): stop spending hourly budget on idle
no-op ticks (#3745)
- `1a93f3e20` — fix: apply reviewed maintenance repairs for #3372
(#3713)
- `fe863b5d9` — fix: apply reviewed maintenance repairs for #3613
(#3717)
- `fa02dc063` — fix: apply reviewed maintenance repairs for #3375
(#3714)
- `3c32386ce` — fix(security): put .bak last so a backup stops looking
like a Python module (#3748)
- `c11e2bf85` — test(installer): expect the not-executed flag on a
refused MCP tool call (#3736)
- `2cbde094b` — fix(vlm): raise when vision extraction fails instead of
indexing the error (#3722)
- `8c4661c38` — fix(agent,memory): let a bare recall() browse instead of
erroring (#3705)
- `7bd576723` — fix(agent): stop the verification footer claiming a
rejected command ran (#3703)
- `5bb9e53f0` — fix(tools): keep a finished edit reported as finished
when the diff won't render (#3702)
- `044a741b3` — fix(tools): search the user's project, not the directory
the sidecar was spawned in (#3711)
- `9fc740074` — fix(tools): describe the edit and write tools by what
agents actually edit (#3712)
- `eefd33dde` — fix(rag): stop indexing a damaged PDF page as a blank
one (#3723)
- `3d0dfbee1` — fix(ui): let a document on a reconnected drive come back
(#3727)
- `cd3dbe6de` — fix(talk): say when the microphone fails instead of
printing "Listening…" (#3724)
- `7c733bb01` — fix(hub): stop recording a failed first install as
installed (#3726)
- `140619559` — feat(tui): scroll with the wheel, click links, and print
only measured ttft/tok-s (#3699)
- `8113fd043` — fix(code-index): let a session index more than one
repository (#3728)
- `d311ac39e` — fix(tools): describe tool arguments at the slot the
model fills (#3583)
- `62e52f8e5` — fix(ui): let the operator declare document roots beyond
$HOME (#3586)
- `c57db1f0d` — fix(tools): honor find_files scope on the index path and
stop doubling "error:" (#3671)
- `cb77a334f` — fix(agents): retry instead of answering with raw
tool-call JSON (#3598)
- `41cd64ec2` — fix(llm): keep tool calls on a truncated assistant turn
during overflow retry (#3582)
- `36b8aa55d` — feat(skills): make image generation reachable from the
flagship (#3073)
- `600831f9e` — ci(vscode): drop the base-branch filter that now fails
the lint gate (#3719)
- `1c23713bd` — fix(ci): run the full suite on stacked PRs, not just PRs
into main (#3372)
- `b8e0496b1` — fix(eval): capture stdout when a scenario subprocess
fails (#3375)
- `d5d4a815c` — fix(tui,webui): stop the real agent on cancel; keep
answer content (#3627)
- `24c0ee4fd` — fix(agent-gaia): name a core floor that can actually run
the agent (#3055)
- `eee4666cd` — fix(security): make the file boundary the file, and hold
it on reads (#3594)
- `46a41f9ec` — fix(chat): restore recent context in long sessions
(#3651)
- `0d82616a9` — fix(tui): reject unsupported daemon permission bypass
(#3654)
- `c3284b464` — fix(npm): resolve Windows shims before launching the TUI
(#3653)
- `a07b87e40` — feat(skills): let a gh write ask instead of fail (#3009)
- `1070ed226` — fix(api,mcp,web): refuse foreign origins and internal
fetch targets (#3612)
- `e373a19df` — chore(lemonade): remove the dead `lemonade-server serve`
CLI from the last surfaces (#3617)
- `305ae88e9` — fix(rag): preserve indexed documents when persistence
fails (#3652)
- `b76647e72` — fix(mcp): retrieve complete Agent UI transcripts (#3667)
- `b7884b46d` — fix(rag): honor index_document's success flag at every
truthy call site (#3678)
- `1d3b2b415` — feat(tools): tell the agent its edit tools exist (#3602)
- `86071110a` — fix(eval): make the agent eval gate's report mode
actually report (#3613)
- `404107919` — fix(memory): refuse chat-minted privileged rows and
distil before pruning (#3614)
- `2fc19e5ee` — feat(tui): choose local, Fireworks, or AMD Gateway via
Lemonade (#3672)
- `a5e16d0b9` — test(lemonade): assert four external contracts the mocks
were faking (#3615)
- `947d05225` — fix(schedule): honor day constraints in recurring timers
(#3655)
- `5155591ad` — fix(chat): retain admission slots for detached runs
(#3657)
- `13f61aebc` — fix(broker): wake queued requests at lease expiry
(#3660)
- `cb8c847a7` — fix(vscode): preserve split streaming tool calls (#3661)
- `65499dabf` — fix(chat): load complete transcripts across message
pages (#3664)
- `d84f98474` — ci(eval): give the persistent Lemonade task the same
launch env as every other start path (#3577)
- `42377da7a` — fix(llm): don't let a non-LLM model's ctx_size leak into
get_status() (#3595)
- `e6a9efcf5` — Error when a named find_files folder is missing (#3580)
- `4d47ae9a9` — feat(agent): transcribe and summarize meeting recordings
locally (#3597)
- `cfc3d2959` — fix(email): don't treat a colon word inside a quoted
phrase as an Outlook operator (#3619)
- `e8f5bc898` — fix(mcp,telegram): resolve port 8765 collision across
bridge, agent-ui, tui and telegram health (#3604)
- `a2df094e3` — fix(llm): preserve Claude tool history (#3410)
- `d9e381b9d` — fix(tui): reap cancelled init processes (#3271)
- `d7cadd3e0` — fix(telegram): keep background polling alive (#3272)
- `b81f9e1b0` — fix: uninstall embedded Lemonade runtime (#3277)
- `146dd63cc` — fix(tui): send caller checkout to daemon ensure (#3268)
- `4ce7c2662` — fix(email): allow move_to_label to restore inbox (#3267)
- `36cab66de` — fix(connectors): preserve grants in device login (#3266)
- `176faf8eb` — fix(email): report calendar listing truncation (#3264)
- `ca2a5086d` — fix(email): honor sender preference ordering (#3257)
- `659cb0cde` — fix(email): surface briefing cache age (#3256)
- `7304f5e86` — ci(release): let the backend test step fail the release
(#3573)
- `07a3749c0` — fix(ci): report runner outages in minutes, not as a
silent cancel a day later (#3411)
- `68f10a8fa` — fix(agents): reject unknown @tool keyword arguments
(#3252)
- `c45593aed` — fix(email-tests): prevent headless keyring hangs (#3249)
- `543b11ec6` — fix(skills): make skill tools work on the Claude
provider (#3143)
- `f83e96c14` — feat(agent): materialize a project map at task start
(#3405)
- `29e5d977c` — feat(tui): add --trace to record what the agent actually
did (#3579)
- `38bc3669b` — docs(troubleshooting): explain the audit-module
antivirus false positive (#3348)
- `f3d739485` — fix(email): fail loudly on Outlook operators Graph
cannot translate (#3562)
- `af7d492ed` — fix(eval): drive the agent eval with the OAuth token,
and probe it for real (#3403)
- `0c23e13a9` — fix(tools): refuse an ambiguous edit instead of changing
the first match (#3396)
- `4ccaa0738` — feat(agent): state whether an answer was verified, on
every exit path (#3397)
- `4c229d434` — fix(api,web): repair gaia api chat completions, HTTPS
SNI, and download overwrite (#3364)
- `456aef994` — chore(deps): bump anthropics/claude-code-action from
1.0.210 to 1.0.216 in the github-actions group across 1 directory
(#3409)
- `a87c3f631` — chore(deps-dev): bump the agent-ui-dependencies group in
/src/gaia/apps/webui with 5 updates (#3407)
- `7e7a2684d` — docs(plans): measure GAIA's agent-loop gaps against 345
real sessions (#3391)
- `d09a7a64e` — feat(skills): learn a skill's corrections into memory,
never into the file (#3023)
- `c53918b75` — docs(claude): correct stale commands, the GaiaAgent
status, and the CLI list (#3311)
- `e274986a1` — fix(skills,tools): stop two tools deleting data while
reporting success (#3358)
- `74916c5f5` — fix(cli): stop uninstall and kill --port destroying what
they do not own (#3361)
- `0ec6ee13e` — fix(connectors): make the per-agent grant check real and
bounded (#3363)
- `9bd6bbadd` — chore(deps-dev): bump the python-dependencies group with
2 updates (#3408)
- `a65bc4556` — chore(deps-dev): bump electron from 44.0.0 to 44.1.1 in
the root-npm-dependencies group (#3406)
- `b4f2c096f` — fix(telegram): scope the bot's tool surface and stop the
allowlist failing open (#3306)
- `d7470a8fc` — fix(ci): stop the Claude audits re-filing the same
finding every run (#3310)
- `dd98c0ff4` — fix(security): stop PowerShell sinks from executing
untrusted text (#3359)
- `833ca3d06` — fix(ui): stop any web page from driving the Agent UI
backend (#3366)
- `e9f28b311` — fix(release): make the v0.23.1 tag pass its own publish
gates (#3354)
- `abe87edc3` — Devlab/dispatch passing (#3344)
- `5b284b4da` — feat(init): make `gaia init` the one setup path for the
flagship (#3330)
- `1ae7dad84` — fix(connectors): enforce catalog scope ceiling for
authorization (#3247)
- `0525d5b0a` — fix(chat): surface unavailable memory at startup (#3153)
- `695e92c58` — docs(custom-agent): make the guide's agent examples
actually run (#3317)
- `a75904de1` — chore(deps-dev): bump the agent-ui-dependencies group in
/src/gaia/apps/webui with 2 updates (#3314)
- `a6a25f29c` — chore(deps): bump zod from 4.4.3 to 4.5.4 in the
root-npm-dependencies group (#3313)
- `ed32a2d4d` — fix(daemon): treat an unreaped sidecar as stopped, not
as a survivor (#3229)
- `211f08c5b` — Use the workspace root lockfile for the example Electron
app (#3301)
- `1886dd363` — test(conftest): stop the unit suite opening the
developer's real browser (#3305)
- `72241b2f2` — Release v0.23.1 (#3054)
- `9b26827ca` — fix: keep source-less agents compatible with skill
discovery (#3244)
- `0fb49f1d6` — fix: preserve forwards across transient mint failures
(#3245)
- `1dec2462f` — fix(connectors): record only granted agent scopes
(#3248)
- `3e90f15d5` — fix(agent): use device profile for context overflow
(#3253)
- `18a8bcb89` — fix: guide daemon version skew upgrades (#3246)
- `39af8ef9f` — fix(ui): report Lemonade probe failures accurately
(#3250)
- `0db152ebc` — fix(daemon): honor extended agent query timeouts (#3251)
- `2dedc7654` — fix(tui): preserve partial-success batch outcomes
(#3255)
- `c5b00e85b` — fix(telegram): report unsupported media types (#3263)
- `bc613dc85` — fix(hub): stop calling an app's npm package a frozen
agent sidecar (#3299)
- `821667c76` — fix(skills): normalize common plural stems (#3270)
- `8ad4ee469` — fix(email): parse grouped Outlook duration queries
(#3269)
- `30b8246ad` — test: cover registered Telegram handlers (#3273)
- `80cf9eb00` — test: verify embedded backend install contract (#3274)
- `9b40c3522` — ci: run embedded Lemonade checksum guard (#3275)
- `5b45a7c11` — fix: keep skill discovery loader available (#3276)
- `1ff94ae6c` — fix: report RAG indexing failures accurately (#3278)
- `0c4d725a0` — fix: report missing API server on stop (#3279)
- `811e0bc04` — fix(talk): honor restart voice command (#3280)
- `869f0bf41` — fix: fail Telegram startup when dependency is missing
(#3283)
- `31fcdd03c` — fix(mcp): expose TUI state wait matcher (#3284)
- `f2dfcd8cb` — fix(hub): stop offering a GAIA install a non-agent card
rules out (#3232)
- `6ffee9e02` — chore(deps-dev): bump the agent-ui-dependencies group in
/src/gaia/apps/webui with 5 updates (#3156)
- `671000d8e` — chore(deps): bump the root-npm-dependencies group with 3
updates (#3155)
- `438733605` — chore(deps): bump anthropics/claude-code-action from
1.0.206 to 1.0.210 in the github-actions group (#3157)
- `0c28442a9` — fix(tui): preserve seeded transport for wheel agents
(#3285)
- `41a00915b` — fix(tui): gate Claude launches on credentials (#3286)
- `25dd767da` — fix(ci): the eval gate skipped every category when the
embedder failed (#3158)
- `fdcdbff4c` — fix(website): Mac visitors on Safari got no install
button (#3144)
- `95f874817` — perf(gaia): send the flagship only the tools a turn
needs (#3008)
- `eb764bf5a` — feat(installer): the one-line install now brings the
agent with it (#3146)
- `ea0e5d924` — feat(cpp): skill sets and gaia-agent.yaml wiring (#2931)
- `5b37cb138` — Route the Strix Halo jobs to the Ryzen Dev Lab pool
(#3262)
- `0047af97d` — ci(claude): skip Claude PR review for Dependabot PRs
(#3259)
- `11039b64e` — test(daemon): stop the hub stray-process test orphaning
a sleep child (#3230)
- `a338b94f4` — test(telegram): cover media ingest paths (#3150)
- `a7bcf5e11` — Show GAIA install alongside npm on hub agent pages
(#3151)
- `ecae8f183` — test(telegram): pin the _allowed truth table including
the fail-open (#3051)
- `8e57b5197` — docs(readme): note the Email agent's CLI install path
(#3041)
- `b9330deba` — fix(email): translate Gmail-style operators for Outlook
Graph search (#3042)
- `3b23ac2b3` — feat(skills): load the right skill without the user
knowing its name (#3010)
- `d4666b8bd` — feat(lemonade): run a private, self-contained Lemonade
Server (#3121)
- `793fb4d42` — perf(ci): cut the C++ dependency cache from 407 MB to
~109 MB (#3142)
- `2cd894579` — fix(telegram): apply the allowlist to every handler, not
just messages (#3148)
- `c128b18f6` — fix(cpp): unblock the C++ gate — split the third-party
skill corpus from the conformance one (#3129)
- `55c977006` — feat(factory): harvest Claude Code sessions into usage
statistics (#3111)
- `6db50643d` — chore(deps): bump the github-actions group across 1
directory with 3 updates (#3049)
- `c7989b953` — fix(mcp): port servers to MCP SDK 2 (#3047)
- `ee61b74fe` — Return structured JSON for unexpected email API errors
(#3046)
- `f2d8291c3` — feat(installer): double-click installers for the
terminal hub (#3125)
- `f601621d1` — fix(agent-gaia): stop one-shot /query runs leaking an
agent each (#3079)
- `4a6561c86` — chore(lemonade): pin Lemonade 11.8.1 (#3117)
- `c51a1c520` — test(telegram): cover access and session isolation
(#3052)
- `98043fb56` — feat(tui): boot straight into the flagship agent, retire
the hub browser (#3120)
- `5bb64a6ba` — chore(deps-dev): bump the agent-ui-dependencies group
across 1 directory with 8 updates (#3048)
- `51c298e1a` — fix(tui): stop --use-claude from starting Lemonade, and
name the Claude model (#3005)
- `38423c84c` — fix(ci): unblock the walkthrough's wheel install, rein
in the authz lens's subagents (#3109)
- `abb8ddea8` — ci(release): require GAIA_HUB_PUBLISH_URL for hub
publish, drop dead fallback (#3032)
- `88299ea49` — feat(website): lead with the flagship agent, and say
what it actually does (#3093)
- `eda11b778` — fix(llm): suggest gaia init on macOS (#3027)
- `11f4da758` — Escape quotes inside Outlook Graph search queries
(#3021)
- `1a3d0f0bd` — fix(packaging): add realtime dependencies to talk extra
(#2954)
- `ae0b64e9f` — chore(deps-dev): bump electron from 43.2.0 to 43.4.1 in
the root-npm-dependencies group across 1 directory (#2871)
- `b95c66dff` — test(memory): assert the reconcile 503 branch in every
environment (#2868)
- `708f806a0` — docs(playbooks): simplify index page (#2957)
- `4ac8f1075` — fix(cli): drop non-constructor CLI flags before creating
GaiaCliClient (#2976)
- `191a317f2` — feat(api): report component health (#2601)
- `40ed1513b` — chore(deps-dev): bump electron from 43.2.0 to 43.4.1 in
/src/gaia/apps/example/webui in the example-app-dependencies group
across 1 directory (#2869)
- `dac81b60c` — docs(tui): tell people how to install the terminal hub
(#3039)
- `643f78432` — feat(tui): lay out to the real terminal width (#3006)
- `ba64ed1e3` — fix(installer): install the extras the daemon needs to
start (#3056)
- `25c137275` — fix(ci): make the Claude audits produce output, not just
run green (#3063)
- `ee64d5cd2` — docs(agent-gaia): correct the npm sidecar docs against
the code (#3076)
- `625478393` — fix(tui): don't run an unverified binary from the hub
install root (#3075)
- `a6c68c8a4` — fix(agent-email): fail closed when a request omits its
Host header (#3077)
- `4b4de3a89` — fix(agent-gaia): stop the npm sidecar attaching to a
foreign server (#3078)
- `6692361d6` — fix(agent-gaia): end a turn parked on a confirmation
when stdin closes (#3080)
- `3ec80f141` — fix(tui): run an installed hub agent over the daemon,
not stdio (#3062)
- `c7c4cff17` — fix(agent): bill tool-approval time to the human, not
the tool (#3007)
- `b388562cc` — ci(installers): add job timeouts (#3020)
- `c4a4fef42` — fix(ci): the README CI badge is permanently red and
reports (#3050)
- `e2ec50523` — docs(cli): remove duplicate terminal hub section (#3045)
- `215477ab6` — ci: fix stale triggers and timeout left by the agent
collapse (#3067)
- `90c3132db` — docs: remove the Blender workshop left dead by the agent
collapse (#3068)
- `a4b84fae7` — perf(claude): cache the fixed prefill, and report the
cache counters (#3026)
- `fdd9f18c3` — refactor(agents): collapse per-task agents into flagship
skills (#2995)
- `5b4f1381d` — fix(ci): scheduled Claude audits were green but never
ran (#3053)
- `78bbc3076` — feat(website): TUI-first redesign — download the
terminal hub, lead with the flagship agent (#3030)
- `6faec485e` — ci(release): make the TUI binaries reproducible, drop
the R2 probe (#3040)
- `02691245e` — fix(hub): strip R2 credentials, and diagnose why R2
refuses them (#3037)
- `aae4a50ce` — ci(hub): require component manifests to match the
release tag again (#3036)
- `8ca0f7d98` — fix(hub): give the website redeploy a repo to dispatch
against (#3038)
- `20e081909` — fix(hub): unblock large-artifact publishing, and version
components independently (#3035)
- `9ad1cee3e` — ci(cloud): provision the dev install in Claude Code
cloud sessions (#3033)
- `0befe27ce` — ci(linux): install Lemonade from the PPA, not deleted
PyPI package (#3034)
- `db170b8a2` — fix(agent-gaia): make the flagship agent releasable —
RAG in the binary, 0.1.1 on npm (#3031)
- `85ba09230` — fix(hub): stop boto3's default checksums breaking every
R2 upload (#3029)
- `5f3e7bbf1` — feat(hub): publish oversized artifacts direct to R2,
bypassing the Worker body cap (#3025)
- `b254708f1` — ci(hub): one approval per component release, not two
(#3018)
- `a0ecb0f68` — ci(eval): pin the agent eval to Strix Halo, and record
which box measured (#3017)
- `672cd1c5f` — fix(init): fail loudly when the Agent UI build can't
produce a usable frontend (#2887)
- `29a87fd87` — ci(eval): capture llama-server's error so the embedder
failure is diagnosable (#3015)
- `c8987ca67` — fix(email): declare the sidecar bearer gate in the
OpenAPI contract (#3002)
- `62e5611d9` — fix(email): "0 messages" for mail that exists —
unsupported newer_than: duration unit (#2981)
- `746468274` — fix(cli): exit non-zero from gaia agent status \<id>,
add --json (#3001)
- `9c89cb472` — ci(hub): deploy the Agent Hub Worker before publishing
to it (#2991)
- `47e6bc908` — fix(gaia): keep a loaded skill alive across turns; stop
a control resize from wrecking the screen (#2932)
- `9ed3c3523` — test(telegram): isolate HOME so the pid test can't
clobber a live adapter (#2895)
- `225c69377` — test(init): stop init tests overwriting the real
~/.gaia/config.json (#2891)
- `8ed5b783d` — fix(release): emit release notes as short bullets, not
prose (#2967)
- `1beb714f3` — release(agent-email): 0.6.0 (#2933)
</details>

Full Changelog:
[v0.23.0...v0.24.0](v0.23.0...v0.24.0)

## Release checklist
- [x] `util/validate_release_notes.py` passes
- [x] `docs && npx mintlify validate` — could not run `mintlify
validate` locally (npm TLS cert error in this environment), but
`util/check_doc_links.py` passes internal + external link checks now
that #3782 is merged
- [x] `src/gaia/version.py` → `0.24.0`; `LEMONADE_VERSION` unchanged at
`11.8.1`
- [x] webui `package.json` / `package-lock.json` → `0.24.0`
- [x] Navbar label → `v0.24.0 · Lemonade 11.8.1`
- [x] Hub component manifests (`terminal-hub`, `agent-ui`) → `0.24.0`;
`check_component_core_api.py --release-version 0.24.0` passes
- [x] `hub/agents/gaia/python/{gaia-agent.yaml,pyproject.toml}`
min-version floor bumped 0.23.1 → 0.24.0 (0.23.1 was never tagged)
- [x] `docs/releases/index.mdx` corrected: 3 files → 5 (was missing the
hub-manifest and webui-package files)
- [x] Rebased onto current `main`; changelog regenerated from the real
range — 230 commits, no phantom SHAs, no missing merges
- [x] Every PR citation and contributor handle verified against `gh pr
view` (33 PRs + 8 contributor logins)
- [x] Full commit range swept for security/breaking markers not caught
by title alone
- [ ] Review from @kovtcharov-amd addressed

---------

Co-authored-by: Ovtcharov <kovtchar@amd.com>
kovtcharov-amd pushed a commit that referenced this pull request Sep 16, 2026
One conflict, in the docs nav version label: main moved the GAIA version to
v0.24.1 while this branch moved Lemonade to 11.9.0. Took both.

Also picks up #3736, whose MCP-harness fix this branch's CI was failing
without — a re-run could not reach it, since the run is pinned to the merge
commit from before that landed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

tests Test changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant