Xeo Forge v1.20.1 — Local-First Agent Workbench
v1.20.1 — The Honest Hotfix
Summary
This release exists because an audit ran real workloads against the
product instead of trusting its own tests. Every fix below was proven
against a live server before it shipped.
Your answer survives even when the run doesn't
The worst finding: a streamed chat reply lived only in the event log.
If the run failed or was cancelled, everything the user had already
read vanished from history — 6,280 characters of a real reply were the
proof. Now failRun and the cancellation path persist the accumulated
prose as the assistant message before the terminal status lands.
A greeting is not a work order
Chat still offered todo_update, git_op, and http_request — so the
model "worked" on a simple hello, mutating todos, until the progress
guard correctly killed the run as failed. Chat now offers read-only
inspection only (file_read, file_list, skill_view), and the chat
prompt orders zero tool calls for greetings. Live: greeting runs make
zero work-tool calls.
Cancel that actually cancels
A live test caught cancel reporting "no live loop found" while events
kept flowing for another 97 seconds — the registry was a per-bundle Map,
so the cancel route and the loop could hold different copies. The
registry is now anchored on globalThis: one instance per process,
verified with signalled: true and terminal state in under 5 seconds.
Provider errors speak human
Raw internals like 503 auth_unavailable (providers=...) are classified
into honest language with next steps — "The model provider rejected the
API key. Check the key in Settings → Providers, then retry." The full
technical text goes to server logs where it belongs.
Capability probes — proof, not promises
The audit demanded live evidence for every feature. These ship as
reusable scripts:
scripts/mcp-live-probe.ts— spawns a real MCP stdio server through
the project's own client: handshake, listTools (9 tools with full
schemas), tools/call — PASS. Server output arrives wrapped in the
untrusted-data quarantine block, exactly as designed.scripts/browser-live-probe.ts— starts the real browser bridge:
loopback token auth, honest empty state, andnavigateblocked by
the read-only default until explicit permission — PASS.scripts/tools-live-probe.ts—skill_viewreads a real imported
skill file through its manifest with the path-escape guard intact;
http_requestreturned HTTP 200 live;file_listworks — PASS.
Verification
tsc --noEmit clean · lint clean · 818/818 tests · every hotfix
exercised against a running dev server with DB-level confirmation ·
CI green on the merge.