Buzz is Block’s open-source (Apache 2.0) agent runtime, announced by Jack Dorsey. Buzz’s own agent, buzz-agent, speaks three separate protocols: ACP (Agent Client Protocol) over stdio to whatever is driving it, model calls over HTTPS, and tool calls over stdio MCP. This tutorial wires the HTTPS leg to NativePort’s OpenAI-compatible endpoint, so buzz-agent runs on a model you don’t have to host yourself. It covers that model connection in depth; Buzz’s own Nostr relay and agent-identity setup are covered separately below, per Buzz’s official documentation, since they’re a different piece of the system from the model connection this tutorial focuses on.
What you’ll need
- A NativePort API key (sign up, $5 of credit is seeded automatically), exported as an environment variable, never hardcoded:
export NATIVEPORT_API_KEY="np_..."
- Buzz built from source, following the official quick start. Docker and Hermit are the two build/runtime prerequisites Buzz’s own quick start documents. This tutorial doesn’t reproduce that guide, since the toolchain pins and local-relay bootstrap are Buzz’s own to maintain:
git clone https://github.com/block/buzz.git
cd buzz
Follow the quick start in the repo from here to build buzz-agent and buzz-admin for your platform. This tutorial targets buzz-agent v0.1.0.
Point buzz-agent’s model calls at NativePort
buzz-agent reads its model provider from environment variables. To route through NativePort’s unified OpenAI-compatible endpoint, set the exact contract Buzz’s own OpenAI-compatible provider expects:
export BUZZ_AGENT_PROVIDER=openai
export OPENAI_COMPAT_API_KEY="$NATIVEPORT_API_KEY"
export OPENAI_COMPAT_MODEL="openai/gpt-5.4-mini"
export OPENAI_COMPAT_BASE_URL="https://api.nativeport.ai/inference/v1"
export OPENAI_COMPAT_API=chat
Every one of these five variables is load-bearing:
BUZZ_AGENT_PROVIDER=openaitellsbuzz-agentto use its generic OpenAI-compatible client rather than a provider-specific one; this is what makes pointing it at a gateway instead of OpenAI itself possible at all.OPENAI_COMPAT_API_KEYcarries your NativePort key, not an OpenAI key. NativePort is the only thingbuzz-agentever authenticates to here.OPENAI_COMPAT_MODEL="openai/gpt-5.4-mini"is NativePort’s canonical model id: theopenai/prefix selects the route, everything after it is OpenAI’s own model name.OPENAI_COMPAT_BASE_URLmust point at/inference/v1, NativePort’s unified inference path, not the account or docs host.OPENAI_COMPAT_API=chatpinsbuzz-agentto the chat-completions wire format. Leave it unset and the client may default to a different API shape the gateway doesn’t serve; see Errors you’ll actually hit.
buzz-agent also reads its output and context-window caps from the environment. Set them explicitly rather than relying on whatever Buzz ships as a default:
export BUZZ_AGENT_MAX_OUTPUT_TOKENS=32768
export BUZZ_AGENT_MAX_CONTEXT_TOKENS=1047576
BUZZ_AGENT_MAX_OUTPUT_TOKENS=32768 is buzz-agent’s default output cap; setting it explicitly here just pins the value instead of trusting the default to stay put across a future build. BUZZ_AGENT_MAX_CONTEXT_TOKENS=1047576 isn’t a Buzz default; it matches NativePort’s current context-window setting for gpt-5.4-mini in the model catalog. Neither number is universal: if you point OPENAI_COMPAT_MODEL at a different model, update both to that model’s real limits, not gpt-5.4-mini’s. A cap sized for the wrong model is a common source of truncated replies, covered below.
Confirm the model can actually drive tools
buzz-agent calls tools over stdio MCP mid-conversation: a tool-call request comes back from the model, buzz-agent dispatches it to an MCP server, and the result feeds back into the same turn. None of that works if the model behind OPENAI_COMPAT_MODEL can’t emit structured tool calls in the first place; it’ll either ignore the tools it’s offered or hallucinate a text description of calling one instead of actually calling it. Check before you rely on it, rather than assume:
curl -s https://api.nativeport.ai/inference/v1/models \
-H "Authorization: Bearer $NATIVEPORT_API_KEY" | \
python3 -c "
import json, sys
data = json.load(sys.stdin)['data']
for m in data:
if m.get('capabilities', {}).get('tools'):
print(m['id'])
"
openai/gpt-5.4-mini (the model used throughout this tutorial and the only one verified here) reports capabilities.tools: true. Stick to a model that reports the same before wiring it into buzz-agent; a route can list a model without it being ready for production tool-driving traffic, so don’t reach for whatever’s newest in your own /models listing without checking this field first.
What this connection supports
buzz-agent v0.1.0 (ACP protocol v2) supports the full ACP-over-stdio, HTTPS-model, MCP-tool architecture against NativePort: initialize, session/new, a complete tool-call lifecycle against an MCP tool server (request, dispatch, result), a final assistant reply, and stopReason: "end_turn". Usage is billed at NativePort’s real, metered rate for whichever model you point OPENAI_COMPAT_MODEL at; openai/gpt-5.4-mini is cataloged at $0.75/1M input tokens and $4.50/1M output tokens.
This tutorial covers the model connection and the MCP tool-call loop. It doesn’t cover Buzz’s own relay bridge (buzz-acp) or its Nostr identity plumbing; those are documented separately below, per Buzz’s own docs, and aren’t part of the connection wired up above.
Wiring buzz-agent into the relay bridge (buzz-acp)
buzz-acp is Buzz’s bridge between its Nostr-based relay (where messages to and from an agent actually travel) and an ACP-speaking agent process. In Buzz v0.1.0, buzz-acp defaults to spawning goose as its ACP backend, not buzz-agent. To have it drive buzz-agent instead:
export BUZZ_ACP_AGENT_COMMAND="/path/to/buzz-agent"
export BUZZ_ACP_AGENT_ARGS=""
BUZZ_ACP_AGENT_ARGS is set explicitly empty here, not left unset. Leaving it unset can let a default argument list meant for goose leak through, which buzz-agent won’t understand. The model environment variables from the previous section still need to be set wherever buzz-acp spawns buzz-agent from; buzz-acp doesn’t forward or synthesize them for you.
This is the configuration Buzz’s own documentation describes for swapping the ACP backend. If you’re standing up the relay for the first time, Buzz’s own quick start (linked above) covers the Docker-based local relay it expects.
Everything from here on is governed by your own Buzz deployment, not the NativePort model connection configured above. Confirm channel routing and key pickup behave as you expect in your setup before enabling tools on this identity.
Giving the agent its own relay identity
Each agent identity on Buzz’s relay is a Nostr keypair. Per the official docs:
- Generate a keypair with
buzz-admin. - Register the resulting public key as a member of the channel(s) the agent should participate in, using a stable
BUZZ_RELAY_PRIVATE_KEYfor the registering identity (typically the channel owner). - Give the agent process its own identity via
BUZZ_PRIVATE_KEYand point it at the relay withBUZZ_RELAY_URL.
export BUZZ_PRIVATE_KEY="nsec1..."
export BUZZ_RELAY_URL="wss://your-relay-host"
Generate a separate keypair per agent. Reusing one identity across multiple agents means the relay (and anyone reading it) can’t tell them apart, and revoking access for one agent revokes it for all of them.
Security
- Never hardcode
NATIVEPORT_API_KEY,BUZZ_PRIVATE_KEY, orBUZZ_RELAY_PRIVATE_KEY. Export them from your shell environment or a secrets manager, not a config file that gets committed. - Scope channel membership deliberately: only add an agent’s public key to the channels it actually needs to operate in. A relay identity with broad membership has a correspondingly broad blast radius if the agent misbehaves or its key leaks.
- Leave Buzz’s default owner-only inbound gate enabled unless you specifically intend the agent to respond to senders other than its owner. It’s the default for a reason, and disabling it widens who can trigger tool calls (including
dev__shell) on the agent’s behalf. - Keep Nostr identity secrets (
BUZZ_PRIVATE_KEY,BUZZ_RELAY_PRIVATE_KEY) and the NativePort API key in separate stores. They protect different things, relay identity versus model spend, and a leak of one shouldn’t automatically compromise the other. - Never put any of the above in an agent’s persona file or other public-facing metadata that gets published to the relay or a channel.
Errors you’ll actually hit
401:NATIVEPORT_API_KEY(passed through asOPENAI_COMPAT_API_KEY) is missing, malformed, or revoked.402: either the NativePort balance is at $0, or, if you’ve pinnedopenai/gpt-5.4-minito a specific upstream account elsewhere in your setup, the upstream provider funding behind that pin is exhausted. Both fail closed rather than degrading output.- Connection or
404errors on every request:OPENAI_COMPAT_BASE_URLisn’t set tohttps://api.nativeport.ai/inference/v1exactly, or has a stray trailing path segment. - Requests going out in the wrong shape, or failing before they reach the model:
OPENAI_COMPAT_API=chatis missing.buzz-agent’s OpenAI-compatible client supports more than one wire format; this variable is what pins it to the one the gateway actually serves. buzz-acpstill launchesgoose, orbuzz-agentexits immediately with an argument error:BUZZ_ACP_AGENT_COMMANDwasn’t picked up (check it’s exported in the same environmentbuzz-acpruns in), orBUZZ_ACP_AGENT_ARGSwas left unset instead of explicitly emptied, so it inherited arguments meant forgoose.- Replies come back empty or visibly cut off mid-thought:
BUZZ_AGENT_MAX_OUTPUT_TOKENSis sized too low for the model behindOPENAI_COMPAT_MODEL, especially on turns that include a tool call, since the call itself consumes part of that budget. Raise it. - The agent never receives messages on a channel it should be part of: its public key wasn’t actually registered as a member of that channel; the relay doesn’t route to identities it doesn’t recognize.
- The agent ignores messages from everyone but its owner: that’s the default owner-only inbound gate working as intended, not a bug. Only change it if that’s a behavior you deliberately want.
Where to go next
- Give Buzz agents web search and page reading with MCP: extend this same
buzz-agentsetup with two more MCP tools, using the same NativePort key. - OpenAI provider page: scope and pricing range for the models behind this route, including the
/inference/v1contract this connection runs on. - Pricing: the full billing model.