Framework guides

Connect Block Buzz to Contro1

Give Block Buzz agents human approvals, role-based routing, safe retries, and a complete audit trail before high-impact actions run.

Updated Aug 2, 2026

Connect a Buzz identity, choose which actions need review, and show the right person the exact action before it runs. Start in decision-only mode, then add the protected webhook executor when you want the connector to carry out approved actions.

Key takeaways

  • Give each Buzz agent an accountable owner in Contro1 and a required human approval before it changes anything outside Buzz.
  • Choose which actions stop, which are logged without review, and which wait for the right person to approve.
  • Retries do not create duplicate requests, and approval stays tied to the action the agent signed.
  • Start in decision-only mode, then add the guarded HTTPS webhook when you are ready for the connector to perform approved actions.

What you get from this integration

Use the connector when a Buzz agent is about to change something outside Buzz: deploy a release, call a protected webhook, update a customer system, spend money, or perform another action that needs organizational control.

Buzz remains the workspace and signed identity layer. Contro1 supplies the agent record, reviewer routing, quorum, deadlines, callbacks, and evidence. The connector verifies the signed Buzz event, derives the action from event content, applies your policy, and stores the exact proposal.

Validation status: the automated test suite passes on Node.js 20 and 22. The connector stays experimental until we have run it end to end against a real Buzz relay and a real Contro1 organization, including callback delivery and recovery after a restart.

Open the connector repository · Requests API · Webhooks

How a Buzz action reaches a governed outcome

  1. Buzz

    Sign the action

    Buzz signs the target and parameters so they cannot be replaced later.

  2. Connector

    Verify and apply policy

    The connector checks identity and chooses block, log, or human review.

  3. Contro1

    Ask the right people

    Contro1 routes the exact action by role, quorum, and deadline.

  4. Connector

    Recheck the action

    It continues only on an explicit approval, and only if the stored action still matches.

  5. Outcome

    Return or execute

    Return the decision by default, or call the protected webhook you configured.

Before you start

Run the connector on Node.js 20.19 or newer. You need a reachable Buzz relay, a connector Buzz key, a Contro1 organization API key, and a stable 32-byte envelope key for encrypted action envelopes.

Use CONTRO1_API_KEY from a scoped organization API key. A CLI token is a browser-issued credential tied to a human identity, has expiry and ownership filters, and cannot provide the persistent server identity this bridge needs.

  • Keep CONTRO1_API_KEY, CONTRO1_WEBHOOK_SECRET, BUZZ_PRIVATE_KEY, BUZZ_AUTH_TAG, the ingress token, and destination credentials outside source control.
  • Keep CONTRO1_BUZZ_ENVELOPE_KEY stable. Losing or changing it makes existing encrypted pending actions unreadable.
  • Set CONTRO1_WEBHOOK_SECRET and CONTRO1_BUZZ_PUBLIC_BASE_URL when using signed callbacks.
  • Set CONTRO1_BUZZ_INGRESS_TOKEN before running the HTTP server.
  • Do not put secrets or credentials inside action.parameters; the proposal parser rejects secret-looking field names.

1. Install the connector and run doctor

The connector executable is contro1-buzz. These commands belong to the connector repository and do not add a buzz command to the existing contro1 CLI.

terminal
git clone https://github.com/contro1-hq/contro1-buzz-connector.git
cd contro1-buzz-connector
npm install
npm run check
cp .env.example .env

# Build and install the executable from this checkout:
npm run build
npm install --global .

# Load .env with your deployment platform or shell, then run:
contro1-buzz doctor

2. Bind a Buzz identity

The stable connector identity key is the normalized relay origin plus the verified Buzz pubkey. The same pubkey on two relay origins intentionally creates two bindings and, by default, two claimed Contro1 agents.

Without --event, bind uses the configured connector key. With --event, it verifies the event ID and signature before binding the event actor. If NIP-OA is absent, the binding is owner_unverified; the connector never fabricates ownership.

terminal
contro1-buzz bind --name "Buzz deployment agent"

# Or bind the independently verified actor from a signed event:
contro1-buzz bind --name "Buzz deployment agent" --event signed-event.json

3. Define the action policy

Policy is connector-owned. Each rule can block an action, allow it with an audit record, or send it to Contro1 for review. Rules match action type, resource prefix, and environment. If you do not provide a policy file, the built-in default sends every action to review.

policy.json
{
  "version": "deploy-policy-v1",
  "default_effect": "block",
  "rules": [
    {
      "id": "production-deploy",
      "effect": "review",
      "reason": "Production deploys require release approval",
      "action_type": "deploy",
      "environment": "production",
      "required_roles": ["release-manager", "security"],
      "required_approvals": 2,
      "separation_of_duties": true,
      "sla_minutes": 15,
      "risk_level": "critical"
    },
    {
      "id": "staging-deploy",
      "effect": "audit",
      "reason": "Staging deploys are logged",
      "action_type": "deploy",
      "environment": "staging"
    }
  ]
}

4. Create the signed action content

Write the action that will become the signed Buzz event content. action_id must identify the same proposed side effect across retries, such as workflow run plus step or tool-call ID. Do not derive it from retry time.

Do not add relay origin, event ID, or actor pubkey to this file. The sign command creates the event, and the connector derives those identity fields from the verified signed submission.

action.json
{
  "contract": "contro1.buzz.signed-action.v1",
  "source": {
    "action_id": "release-42:deploy-payments",
    "workflow_run_id": "release-42"
  },
  "action": {
    "type": "deploy",
    "resource": "service:payments-api",
    "environment": "production",
    "parameters": {
      "release_digest": "sha256:efefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefef"
    }
  }
}

5. Sign and submit without blocking a Buzz channel

sign creates a Buzz event whose canonical content is the action file, then wraps it with the normalized relay origin. gate verifies that event and derives the proposal solely from its signed content.

Sign shortly before submission. By default, a new event may be up to 300 seconds old and 60 seconds ahead of the connector clock; both limits are configurable for a known queue delay.

The normal Buzz/ACP path is asynchronous. The bridge stores the gate and Contro1 request, returns pending, releases the channel turn, and continues waiting independently. Use --wait only for a dedicated CLI or CI process whose single job is to guard one action.

After restart, the server resumes durable gates that are still awaiting review. Query status by gate ID instead of asking the agent to resubmit the action.

terminal
contro1-buzz sign --file action.json > signed-submission.json
contro1-buzz gate --file signed-submission.json
contro1-buzz status <gate-id>

# Dedicated CLI/CI flow only:
contro1-buzz gate --file signed-submission.json --wait

6. Connect a Buzz or ACP adapter over HTTP

POST /v1/gates accepts the same signed-action submission produced by contro1-buzz sign. The connector verifies the event before deriving its proposal. POST /v1/gates and GET /v1/gates/:id are connector-local routes protected by CONTRO1_BUZZ_INGRESS_TOKEN. POST /v1/callbacks/contro1 verifies Contro1 signature, timestamp, request ID, replay state, pending gate, and action binding.

These /v1 routes belong to the connector process you deploy and run inside your own network. They are not part of the Contro1 API.

terminal
contro1-buzz serve --host 127.0.0.1 --port 8787

curl --request POST http://127.0.0.1:8787/v1/gates   --header "Authorization: Bearer $CONTRO1_BUZZ_INGRESS_TOKEN"   --header "Content-Type: application/json"   --data @signed-submission.json

curl --header "Authorization: Bearer $CONTRO1_BUZZ_INGRESS_TOKEN"   http://127.0.0.1:8787/v1/gates/<gate-id>

How the proposal maps to Contro1

The connector creates a normal Integration Protocol v1 approval request through createProtocolRequest(), the same call every other Contro1 integration uses.

Relay origin comes from the signed submission envelope. Event ID, actor pubkey, timestamp, and action content come from the verified event. Published @contro1/sdk 1.1.0 types expose action data as context.tool_name and context.tool_input, while verified Buzz facts live under metadata.machine_observed.

Those metadata facts are available in the dashboard/request record. Current Slack and Teams cards read context.machine_observed, which is not exposed by the published SDK 1.1.0 types, so those cards do not yet render the Buzz relay, event ID, actor key, attestation fingerprint, or action digest.

Buzz or connector valueContro1 field
Stable Contro1 bindingactor.agent_id
Buzz workflow and runsource.workflow_id and source.run_id
Action type and parameterscontext.tool_name and context.tool_input
Resource and environmentcontext.resource and context.environment
Verified relay, event, pubkey, and digestmetadata.machine_observed
Customer policy resultpolicy_trigger and policy_context
Stable external action identityexternal_request_id
Broader workflow or casecorrelation_id

What happens after a reviewer responds

A status of approved is never enough on its own. The connector requires an explicit decision_type of approve, or response.approved set to true, so a free-text reply can never be read as an approval.

In the default decision-only mode, a valid approval ends with state approved, disposition approved, and execution_status not_executed. The caller may continue using that action-bound decision. The callback path separately verifies HMAC freshness, request IDs, durable replay state, the pending gate, and the stored action digest.

  • Denial, cancellation, timeout, API failure, invalid callback, replay, and ambiguous free text fail closed.
  • Nonce and expires_at are generated once and reused on retries.
  • The stored encrypted action is loaded and re-hashed before the final approved outcome or configured execution.
  • A material mutation becomes binding_mismatch and nothing executes.
  • Audit policy uses logAction() and skips human review. In decision-only mode it ends approved with execution_status not_executed.

Choose what happens after approval

Decision-only is the default because it separates the approval decision from destination access. If this connector should perform the side effect, webhook mode sends the exact stored action to one fixed HTTPS URL and signs the body with HMAC. Mock mode is only for an explicit demo.

ModeConfigurationOutcome
Decision onlyCONTRO1_BUZZ_EXECUTION_MODE=decision-onlyReturns approved with execution_status not_executed. Your trusted caller decides how to continue.
WebhookSet mode=webhook, CONTRO1_BUZZ_EXECUTOR_URL, and CONTRO1_BUZZ_EXECUTOR_SECRET.POSTs the stored action to one fixed HTTPS endpoint with an HMAC signature and records the external result.
MockCONTRO1_BUZZ_EXECUTION_MODE=mockRecords a harmless mock result for demos; it does not call a destination.

What the connector does not control

  • It does not yet keep a persistent Buzz WebSocket subscription open, so it cannot replay missed events on its own. Your adapter submits the actions you want governed.
  • It does not define a new ACP reply-event format. Deployments map their existing verified Buzz event contract into the action proposal.
  • It does not revoke Buzz keys, rotate Buzz identities, manage channel membership, or infer cross-relay identity linking.
  • It does not issue a portable asymmetric decision receipt. Current evidence and callbacks use Contro1 organization signing material.
  • It does not govern actions that bypass its HTTP, CLI, or guarded-executor boundary.

Verified compatibility baseline

SurfaceVerified baseline
Contro1 TypeScript SDK@contro1/sdk 1.1.0
Contro1 CLIv0.1.4 plus commit 535adaa
Buzz source28ae6cd2174309529305724e455c7ca082f6fe4b
Node.jsCurrent Node.js 20 and 22 releases

Frequently asked questions

Is the Block Buzz connector production-validated?

Not yet. The automated TypeScript, unit, integration, build, and Node.js 20/22 checks pass, but the live matrix against a real Buzz relay and Contro1 organization has not completed. Treat it as an integration preview until live callback, restart, and executor-idempotency scenarios pass.

Does Contro1 expose a Buzz-specific API?

No. The connector uses the existing /api/centcom/v1 runtime API through @contro1/sdk. The /v1/gates routes documented here are local to the connector server.

Is contro1-buzz part of the contro1 CLI?

No. contro1-buzz is the executable shipped by the standalone connector repository. Existing Contro1 CLI commands remain unchanged.

Can an approved status or free-text answer execute an action?

Not by itself. The connector requires an explicit canonical approval decision and then verifies that the stored action, digest, gate state, and expiry still match.

Does an approved gate execute the action by default?

No. Decision-only is the default and returns execution_status not_executed. Configure the fixed HTTPS webhook executor when the connector should perform the action, or choose mock mode explicitly for a harmless demo.

Why use an organization API key instead of contro1 auth login?

The connector is a persistent server process. Browser-issued CLI tokens are tied to a human login, expire, and apply ownership filters, so they are not an appropriate server identity.

Related resources

Contro1 JavaScript and TypeScript SDK

Install and use @contro1/sdk in Node, TypeScript, Express, Fastify, or Next.js backends to create approval requests, verify webhooks, and write audit records.

Block Buzz AI agent governance

Add business ownership, human approval, and audit evidence before Block Buzz agents deploy, send, spend, or change external systems.

How to choose the owner of an AI agent

A short practical guide for assigning an AI agent owner: who should be accountable, when a VP or department head should own it, and how to record fallback ownership.