These notes describe the GDK-backed buzz-agent implementation reviewed at Buzz commit d2cc2e177 (the hardened integration head prepared from the micn/buzz-agent-goose-core work).
This is an internal swap, not a new executable or runtime:
- the binary and ACP identity remain
buzz-agent; - Buzz still owns the ACP server and agent loop (
crates/buzz-agent/src/loop_drive.rs); - Goose GDK crates now provide model streaming, provider implementations, system-prompt/skill composition, compaction, and common tool types;
- Buzz still owns its MCP registry/dispatch, permissions, lifecycle hooks, cancellation semantics, steering, and relay-facing contract.
Consequently, packaging should still bundle the ordinary buzz-agent sidecar. Do not add a second “GDK” binary or runtime entry.
At the reviewed head, crates/buzz-agent/Cargo.toml pins several Goose GDK crates to Goose commit:
5a9a13b72aaf8f9aa17ce064bd4d4d761d656982
That revision was outside Goose main when the work was reviewed. A clean build needs network access to fetch it. Before updating that pin, rerun all checks below: a Goose revision bump is behaviorally significant, not a routine lockfile refresh.
From the Buzz repository root:
. ./bin/activate-hermitUse the repository-pinned Hermit Rust/Node tooling. This matters for local commands and hooks; do not work around an unactivated shell by rewriting hook commands.
For automated tests and the hand-test driver (debug paths are intentional):
cargo build -p buzz-agent -p buzz-dev-mcpFor the production-shaped agent binary:
cargo build --release -p buzz-agentFor a Desktop bundle, use the repository's normal Desktop/sidecar build flow. The GDK work does not change the sidecar name or packaging contract.
Run the full package suite, not a filtered module/test:
cargo test -p buzz-agentThis suite exercises real buzz-agent subprocesses and fake provider/MCP processes. It covers the ACP wire and key regressions without spending real provider tokens, including:
- provider failures and malformed streams;
- MCP discovery, dispatch, restart, and real
buzz-dev-mcpuse; - cancellation and terminal tool-call state;
- mid-turn steering;
_Stopveto and reply guard behavior;- skills/hints and system-prompt composition;
- permission boundaries;
- compaction/memory recovery;
- Databricks auth coordination.
Before proposing or pushing a Buzz change, also run the repository-wide gate:
just ciIf relay/database/auth code was changed as well, run the integration suite documented by the repo (just test, with PostgreSQL and Redis available).
The automated provider tests use a local fake server. They do not prove that a live provider accepts the generated requests. The branch includes a direct ACP driver:
cargo build -p buzz-agent -p buzz-dev-mcp
export ANTHROPIC_API_KEY='...'
python3 crates/buzz-agent/scripts/handtest.py --all \
--provider anthropic \
--model claude-sonnet-4-6Never commit the API key. The script isolates HOME, XDG_CONFIG_HOME, and XDG_DATA_HOME in a temporary directory, starts a fresh agent process per mode, prints PASS/FAIL, and exits nonzero on failed assertions.
Useful focused modes:
python3 crates/buzz-agent/scripts/handtest.py --basic
python3 crates/buzz-agent/scripts/handtest.py --tools
python3 crates/buzz-agent/scripts/handtest.py --stop-veto
python3 crates/buzz-agent/scripts/handtest.py --cancel
python3 crates/buzz-agent/scripts/handtest.py --steerWhat they establish:
--basic: the client-supplied persona and checkoutAGENTS.mdreach the model, and the model catalog is populated;--tools: the live model discovers and invokes the realbuzz-dev-mcpshell tool, every announced tool call terminates, and output returns to the model;--stop-veto: open todos trigger_Stop, but the rejection cap prevents an infinite turn;--cancel: cancellation during a long tool returns promptly and leaves no tool call spinning;--steer: a message injected during a running turn is absorbed without restarting the turn.
The checked-in source of truth is crates/buzz-agent/HANDTEST.md and scripts/handtest.py.
The normal product workflow is the final integration test:
just devOr use separate terminals:
just relay
just gooseDespite the historical recipe name goose, this flow uses the swapped buzz-agent implementation. In Desktop, check these behaviors:
- The agent answers with its saved persona rather than a generic Goose identity.
- Streaming feels normal; watch for stalls, duplicated text, or bursts.
- A long-running tool can be cancelled without a stuck spinner.
- A second message sent mid-turn steers the existing run rather than restarting it.
- The model picker contains the provider's catalog; catalog failure should degrade selection UX, not kill the session.
- An open todo can veto stopping, but the turn eventually exits at the configured cap.
- Watch logs for the model directly calling
_Stopor_PostCompact. Those hook tools are visible because Goose uses one allowlist for advertisement and dispatch; the system prompt tells the model not to invoke them directly.
- Anthropic was the only provider hand-tested end-to-end. Databricks chat used Goose and had not received the same live-provider smoke test; Databricks model discovery remained Buzz-owned and separately tested.
- Relay-mesh MoA behavior was automated against a fake router, not a live multi-model mesh. With a real mesh, an
autorelay-mesh agent should switch to virtual modelmeshafter at least two models are live, then fall back toautoafter the mesh shrinks; inspect logs forrelay-mesh auto:. - The agent binary grew materially (the branch notes measured roughly +22.7 MiB raw / +6.0 MiB gzip). Recheck release artifact size when the Goose revision or feature set changes.
Some older prose in crates/buzz-agent/README.md still describes the pre-GDK implementation as non-streaming and refers to deleted monolithic test files. For this integration, trust the current code, focused test suites, and HANDTEST.md over those stale passages.
Also, a green fake-provider suite and a successful live workflow answer different questions. For meaningful provider or user-visible changes, do both.