hive-acp: run a harness in a container, as a Buzz harness - #4
Merged
Conversation
Moves hive from the "where to run" seam to the "harness" seam. As a backend provider, hive competed with Buzz's own notion of location — which is why buzz-backend-hive had to reimplement remote deployment over ssh. As a harness, `harness=hive` composes with whatever Buzz already does about location: local, a remote provider, or this box acting as a provider for a laptop. Location stays Buzz's axis; the environment becomes hive's. Buzz v0.5.0 added BYOH (block/buzz#2773), so a Tier-3 custom harness is a JSON file in `custom_harnesses/` — no fork required. examples/ has one. It does NOT parse the protocol, deliberately. Everything that would justify parsing is decided before the first byte moves: the agent from HIVE_AGENT, its harness from its spec, its credentials and MCP servers from hived. Nothing is left to choose, so there is nothing to intercept — and a proxy that re-frames JSON-RPC it does not need to read can corrupt a stream it was only meant to carry. ACP framing is also not something to assume; a byte pipe stays correct whether messages are newline-delimited or length-prefixed. When routing between several backends is wanted, this becomes a real router; until then being a pipe is the feature. The harness comes from the SPEC rather than the environment, because the spec is what hived reconciled the container from. Reading it from the environment would let the two disagree, and the symptom would be a harness that starts, answers initialize, and has none of the credentials the container was built for. Verified against a real container: a real ACP initialize proxied through to claude-agent-acp 0.63.0, which answered with full capabilities — including mcpCapabilities {http, sse}, the thing Buzz itself cannot configure and `hive mcp` now provides. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gw5rgVt1CQ8EYrLpZtQjdM
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Moves hive from the "where to run" seam to the "harness" seam.
Why the seam matters
As a backend provider, hive competes with Buzz's own notion of location — which is exactly why
buzz-backend-hivehad to reimplement remote deployment over ssh. As a harness,harness=hivecomposes with whatever Buzz already does about location: local, a remote provider, or this box acting as a provider for a laptop.Location stays Buzz's axis. The environment becomes hive's.
Buzz v0.5.0 added BYOH (block/buzz#2773), so a Tier-3 custom harness is just a JSON file in
custom_harnesses/— no fork required.examples/buzz-custom-harness.jsonhas one ready to edit.It deliberately does not parse the protocol
It could — intercept
initialize, route by session id, gain mid-conversation harness switching. That's a real feature and it isn't this one.Everything that would justify parsing is decided before the first byte moves: the agent from
HIVE_AGENT, its harness from its spec, its credentials and MCP servers fromhived. Nothing is left to choose, so there's nothing to intercept — and a proxy that re-frames JSON-RPC it doesn't need to read is a proxy that can corrupt a stream it was only meant to carry.ACP's framing is also not something to assume. A byte pipe is correct whether messages are newline-delimited or length-prefixed, and stays correct when that changes. When routing between several backends is wanted, this becomes a real router. Until then, being a pipe is the feature.
A detail worth keeping
The harness is read from the spec, not from the environment, because the spec is what
hivedreconciled the container from. Taking it from the environment lets the two disagree — and the symptom is a harness that starts, answersinitialize, and has none of the credentials the container was built for.Verified against a real container
A real ACP
initializeproxied through toclaude-agent-acp0.63.0, which answered with full capabilities — including:That's the thing Buzz itself cannot configure (its
McpServeris stdio-only) and thathive mcp(#3) now provides. The harness side was ready all along.Also checked: missing config exits
78(EX_CONFIG) with an actionable message rather than hanging, and all logging goes to stderr — one stray line on stdout would corrupt the ACP stream and present as a harness that connects then ignores everything.108 tests pass.
Follow-ups, not in this PR
buzz-backend-hiveonce this has run in angerhive mcp refresh)🤖 Generated with Claude Code
https://claude.ai/code/session_01Gw5rgVt1CQ8EYrLpZtQjdM