block / block/buzz

Remote agent providers should not require a local executable (HTTP transport for L2)

Open
#5,614 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
32.7k
Forks
4.3k
Avg merge
1d 13h
Merged PRs (30d)
253

Description

**Motivation**

Provider discovery scans the desktop's own directory, every `PATH` entry, and
`~/.local/bin` for an executable named `buzz-backend-`. There is no other
transport.

That has a consequence worth naming: `buzz-backend-kubernetes` needs no installation
because it ships inside `Buzz.app`. Being off-the-shelf and needing no install are the
same property — being in the bundle. Anyone else integrating a substrate has to ship,
sign, notarise, distribute and then keep updating a native binary on macOS and Windows
before a single agent runs.

For a **hosted** substrate that binary has nothing to do. Ours is ~1.3 MB of Rust whose
entire job is: check a few fields are present, resolve a bearer token, `POST` the
request body it was handed, and relay the JSON response verbatim. Every decision that
matters — which cloud account to provision into, entitlements, naming, secrets —
happens on the far side of that POST, because that is where the credentials are.

Kubernetes is the exception that proves the rule: it needs a local process because the
credential is already local (`kubeconfig`). A hosted provider has no local credential
and no local state, and ships a binary anyway.

**Proposed solution**

An HTTP transport for L2, alongside the existing executable transport.

- A provider may be registered as a **URL** instead of an executable.
- The desktop `POST`s the **same** `info` and `deploy` request bodies it writes to a
provider's stdin today, and reads the same JSON response.
- `protocol_version` unchanged. The wire contract is already transport-agnostic: one
JSON object in, one out.

Strictly additive — existing provider binaries, the Kubernetes binding, L1 and L3 are
all untouched.

Security rules carry over unchanged, and one gets easier:

- **I2 (no credentials in `provider_config`) still holds** and matters more here, since
`provider_config` is synced with the agent. Auth resolves out of band exactly as it
does now and travels as a request header.
- **`https://` required, loopback exempt** (`localhost`, `127.0.0.0/8`, `[::1]`) so a
control plane can be developed without TLS. Worth stating explicitly in the spec: we
got this wrong ourselves and accepted `http://localhost.attacker.example`, because we
tested a string prefix instead of the host.
- **The request body carries the agent's private key.** Already true over a local pipe;
over HTTP it makes the TLS rule load-bearing rather than hygienic.
- **Trust on add.** Registering a URL grants an endpoint the ability to receive minted
agent identities, so it deserves the same deliberate gesture as installing a binary.

The 600s operation deadline works the same over HTTP. Two things worth documenting for
implementers, both learned the hard way: a load balancer's idle timeout must exceed the
deadline, or a slow first deploy dies at the proxy and the desktop records a failure for
an agent that comes up healthy; and a client-side timeout should report the deploy as
*accepted and still building*, because the substrate does not stop when the caller does.

**Alternatives considered**

- **Ship and sign our own binary** — what we do now. It works, and it makes every
integrator a software distributor. Unsigned builds are blocked by Gatekeeper and
SmartScreen, so this is a hard prerequisite rather than a nicety.
- **Use the bundled Kubernetes provider** — genuinely off-the-shelf, but it relocates
the friction rather than removing it: the user still needs a `kubeconfig` with cluster
credentials on their machine, which is a longer-lived and more dangerous credential
than a scoped bearer token, and it forces a cluster on substrates that do not need one.
- **Do nothing** — viable for us, since we already ship a binary. It is the smaller
integrators who pay.

**Additional context**

Related but distinct, and worth reading together:

- #2663 asks for **non-ACP agent systems** to participate — there the *agent* is
external. This proposal is a layer below: the agent still speaks ACP, and it is the
*provider transport* that becomes HTTP. Complementary, not a duplicate.
- #5548 (provider protocol, `launch.command`) is adjacent provider-protocol territory.

We have a working reference implementation of the executable transport deploying real
agents onto AWS ECS today, and it is the strongest argument we can make for this change:
**it is 1.3 MB of code that would not need to exist.** Happy to write the HTTP transport,
the spec section and the tests, or to hand ours over as prior art if you would rather
own it.

Searched open issues and PRs for duplicates: closest are #2663 and #5548, both linked
above.

Contributor guide

Open the contributing guide

Research direction

Start by reading the existing executable provider transport and the provider protocol described in the issue, especially the shared info and deploy request and response contract. Define the HTTP registration, HTTPS and loopback validation, authentication, deadlines, and accepted-deploy behavior, then add tests covering those rules and preserve existing executable, Kubernetes, L1, and L3 behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
api, backend, security
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.