Veritas Kanban can map a Buzz community channel to Squad Chat and move signed
root messages and replies in both directions. The integration uses Buzz’s
native Nostr HTTP and WebSocket contracts. It does not spawn buzz,
buzz-acp, or buzz-agent for delivery.
Buzz is a communication adapter, not an AgentProvider. It does not create a
Veritas task, start an ACP agent, synchronize DMs or forums, or read Buzz
Desktop’s internal state. An operator may separately materialize selected
public Buzz persona and team definitions as disabled Veritas profiles and
roster members. Definition import is data-only and never starts a process.
Task execution is a separate seam. A disabled-by-default buzz-agent
configuration uses provider acp-stdio and the generic ACP client. It never
turns relay delivery into task completion and never launches buzz-acp.
Selected task tools are exposed only through the provider-neutral
veritas-run bridge, with an opaque task/attempt/catalog/manifest binding;
native server credentials and the global Veritas MCP inventory are not passed
to Buzz.
See Buzz Agent ACP.
The adapter is fixture-pinned to:
0.4.24710ed9fff57878a1d69f809b80a6ee0416c53fc41https://github.com/block/buzz11, 29, and 4243The initial event projection is:
| Buzz surface | Veritas behavior |
|---|---|
Kind 9 root message |
Creates one Squad Chat message in the mapped target. |
Kind 9 reply |
Creates one threaded Squad Chat reply using Buzz root/reply tags. |
| Veritas root | Signs and publishes one kind 9 event with the mapped h channel tag. |
| Veritas reply | Publishes a direct or nested reply with the exact Buzz root/reply markers. |
Kind 40003 edit |
Records bounded audit metadata. Existing Squad Chat text is unchanged. |
Kind 9005 or NIP-09 kind 5 delete |
Records bounded deletion metadata. Local content is not removed. |
| Unknown or malformed kind | Ignores it with a redacted delivery audit entry. |
| Reactions, files, canvas, forums, DMs | Not projected. |
An unknown Buzz version is unsupported. Veritas may still read public NIP-11
metadata, but it will not connect the worker or send messages until the pinned
compatibility contract passes.
Use a dedicated Buzz/Nostr identity. Add that public identity only to the community and channels that Veritas must bridge. Veritas does not need channel creation, moderation, desktop storage, or broad community administration.
Keep the private key in the Veritas server environment and store only its environment-variable reference:
BUZZ_PRIVATE_KEY=<set outside source control>
BUZZ_AUTH_TAG=<optional NIP-OA owner attestation>
The signing key may be 64-character private-key hex or nsec. It must match
the configured 64-character public-key hex. BUZZ_AUTH_TAG is needed only
when an agent identity receives membership through a NIP-OA owner.
Never put an nsec, private-key hex, auth tag, token, authorization header, or
raw signed event in a Settings field, API response, task, log, screenshot, or
support packet.
In Settings -> Notifications -> Buzz Connection, configure:
https://community.example.comenv:BUZZ_PRIVATE_KEYenv:BUZZ_AUTH_TAGbuzz, buzz-acp, or buzz-agent executable for version
diagnosticsHTTP and WebSocket endpoints must have the same host, port, path, and TLS posture. Credentials, query strings, and fragments are rejected. A configured path and non-default port are preserved because Buzz binds the community to the request authority.
The Settings save writes the reference-only adapter first, then writes the Squad Chat channel mapping. Changing a channel disables the old mapping before enabling the new one. Conflicting enabled mappings for the same target are rejected.
settings:write is required to configure, map, send, reconcile, disable, or
disconnect. settings:read can read adapters, mappings, health, and delivery
history.
Configure the connection:
curl -X PUT http://localhost:3001/api/integrations/communication/adapters/buzz-default \
-H 'Content-Type: application/json' \
-H 'X-API-Key: <veritas-api-key>' \
--data '{
"kind": "buzz",
"displayName": "Buzz",
"enabled": true,
"relayHttpUrl": "https://community.example.com",
"expectedCommunity": "community.example.com",
"publicKey": "<64-hex-public-key>",
"credentialRef": "env:BUZZ_PRIVATE_KEY",
"authTagRef": "env:BUZZ_AUTH_TAG"
}'
Map one Buzz channel to Squad Chat:
CHANNEL_ID=123e4567-e89b-42d3-a456-426614174000
curl -X PUT \
"http://localhost:3001/api/integrations/communication/adapters/buzz-default/buzz/channels/${CHANNEL_ID}" \
-H 'Content-Type: application/json' \
-H 'X-API-Key: <veritas-api-key>' \
--data '{
"target": { "kind": "squad" },
"enabled": true,
"actor": "operator"
}'
Run the compatibility probe:
curl \
http://localhost:3001/api/integrations/communication/adapters/buzz-default/health \
-H 'X-API-Key: <veritas-api-key>'
vk doctor --json
POST .../buzz-default/test runs the same read-only probe. It never sends a
message.
In Settings -> Agents -> Buzz Persona and Team Definitions, an operator can list, preview, and explicitly import public Buzz definition heads:
30175 persona definitions keyed by (author, kind, d tag);30176 team definitions keyed the same way; andcreated_at, using the
lowest event ID to break a tie.The importer reuses the signed, DNS-pinned Buzz /query transport and requires
current healthy compatibility evidence. Every candidate has bounded Nostr
shape, tags, content, JSON depth, arrays, strings, and batch size. Its
signature is reconstructed and verified before it can appear in Settings.
Invalid envelopes contribute only to a rejected count. A signature-valid
current head with rejected content appears as a non-importable coordinate and
field-level validation reason, so Veritas never silently falls back to an older
definition. Unsafe source values are not echoed into the UI or logs.
Preview classifies each field before mutation:
| Buzz definition field | Import behavior |
|---|---|
Persona display_name |
Source-owned profile display name. |
Persona system_prompt |
Source-owned profile prompt when present. |
Persona avatar_url |
Validated public metadata only. Veritas does not fetch it. |
Persona runtime, model, provider |
Source preferences only, never runtime evidence or active provider configuration. |
Persona name_pool |
Bounded source metadata only. |
| Persona reserved response fields | Source-only. Veritas does not apply them. |
Team name, description |
Source-owned roster fields for create or refresh. |
Team persona_ids |
Same-author persona slugs resolved to linked profiles and disabled roster members. |
| Unknown fields | Ignored with a field-level forward-compatibility explanation. |
| Secrets, environment, commands, paths, managed process state, MCP, hooks, skills, engrams | Rejected. |
The available actions are:
create: use the deterministic buzz-<slug> profile ID or
buzz-team-<slug> roster ID;link: attach provenance to an explicitly selected existing profile or
roster without replacing local fields;refresh: replace only the saved source-owned fields after a new preview;
andskip: record no local mutation.Create, link, and refresh require collision-free preview. A preview returns an optimistic local revision and exact source event ID. Import rejects a changed local target or replaced source, so the operator must review the current diff instead of overwriting concurrent edits. Native profile/roster fields remain authoritative; refresh preserves local-only fields and existing routing rules.
New persona profiles, new rosters, and imported roster members are disabled.
Import never launches, enables, routes, installs, fetches, or writes back to
Buzz. Removing or replacing a Buzz definition changes its linked-source status
to missing or changed; it does not delete the materialized local object.
Definition API:
GET /api/integrations/communication/adapters/:adapterId/buzz/definitions
GET /api/integrations/communication/adapters/:adapterId/buzz/definitions/links
POST /api/integrations/communication/adapters/:adapterId/buzz/definitions/preview
POST /api/integrations/communication/adapters/:adapterId/buzz/definitions/import
Reads and preview require settings:read. Import requires settings:write.
There is no continuous synchronization and no Buzz write-back endpoint.
A buzz-workflow-trigger/v1 rule can bind one active channel mapping to one
Veritas workflow. The first supported event is a root kind 9
message.posted. Replies, edits, deletes, reactions, adapter-originated
echoes, disabled rules, and predicate mismatches do not launch a run.
Create a rule with the mapping ID returned by the channel-mapping API:
curl -X POST \
http://localhost:3001/api/integrations/communication/adapters/buzz-default/buzz/workflow-triggers \
-H 'Content-Type: application/json' \
-H 'X-API-Key: <veritas-api-key>' \
--data '{
"mappingId": "buzz_map_example",
"workflowId": "triage-external-request",
"contentIncludes": "help"
}'
An exact 64-character author public key may be supplied as authorPubkey.
Content matching is a bounded, case-insensitive substring check. There is no
regex, expression, code, shell, or arbitrary Nostr-kind filter.
Rule creation requires settings:write and execute permission on the
destination workflow. The mapping alone does not grant workflow or task
mutation rights.
Veritas persists the accepted causal key
buzz:{community}:{eventId}:{ruleId} before dispatch through the
provider-neutral workflow.pre-external-trigger hook. Workflow context
retains the community, channel, event, author, mapping, rule, and sanitized
message. A replay returns the existing run. After restart, Veritas searches
the destination workflow’s run context for the causal key before launching
another run.
List or disable rules and inspect bounded disposition history:
GET /api/integrations/communication/adapters/:adapterId/buzz/workflow-triggers
POST /api/integrations/communication/adapters/:adapterId/buzz/workflow-triggers/:ruleId/disable
GET /api/integrations/communication/adapters/:adapterId/buzz/workflow-trigger-audits
Disabling a rule retains its prior audits and linked workflow runs.
Send a root and associate it with a local Squad Chat message:
curl -X POST \
http://localhost:3001/api/integrations/communication/adapters/buzz-default/send \
-H 'Content-Type: application/json' \
-H 'X-API-Key: <veritas-api-key>' \
--data '{
"target": {
"kind": "squad",
"squadMessageId": "msg_local_root"
},
"message": "Root message from Veritas",
"actor": "VERITAS"
}'
Send a reply by identifying both the new local message and the local parent:
curl -X POST \
http://localhost:3001/api/integrations/communication/adapters/buzz-default/send \
-H 'Content-Type: application/json' \
-H 'X-API-Key: <veritas-api-key>' \
--data '{
"target": {
"kind": "squad",
"squadMessageId": "msg_local_reply"
},
"replyToSquadMessageId": "msg_local_root",
"message": "Reply from Veritas",
"actor": "VERITAS"
}'
The parent must already have a durable Buzz event mapping. A missing parent is blocked instead of publishing a detached root.
Each outbound event includes the mapped h tag, a client=veritas-kanban
marker, and a stable veritas-id delivery marker. Veritas persists the signed
event and event ID before submitting it to /events.
One supervised WebSocket worker runs per enabled, compatible Buzz connection. It:
22242 and the optional NIP-OA auth
tag;9, 40003,
9005, and 5;(created_at, event_id) only after the
projection and audit are durable.Deduplication uses (community, event_id), never timestamp alone. Squad Chat
uses the deterministic local ID msg_buzz_<event-id>, so a crash after the
chat write but before adapter-state persistence replays safely. The original
Buzz author public key, source timestamp, event kind, channel, community,
event ID, and buzz://message link remain attached as external metadata.
An out-of-order reply is persisted but does not advance the cursor past its
missing root. When the root arrives, queued replies are replayed in
(created_at, event_id) order. A root that never arrives remains bounded
pending state rather than becoming a detached Squad Chat message.
Adapter-originated event IDs are retained and ignored when echoed by the subscription, preventing a reply loop.
Network failure after a write can leave delivery status unknown. Veritas does not blindly retry:
delivery_unknown;POST .../buzz-default/poll queries /query by the signed event ID;success;Before query or resubmission, the persisted event is re-verified against its signature, configured public identity, mapped community/channel, and event ID. A corrupted record is failed and never retried.
Health separates:
Compatibility can be healthy while runtime status is degraded, such as when
no channel is mapped or the subscription is still connecting. canSend
requires an enabled adapter, current healthy compatibility evidence, and at
least one mapped channel. canReceiveReplies additionally requires an active
subscription.
Delivery history exposes queued, success, delivery_unknown, replayed,
ignored, failed, blocked, and skipped. It retains bounded coordinates
and redacted details, not credentials or raw authorization material.
Public HTTPS/WSS is the default. Plain HTTP/WS requires an explicit localhost or private-network allowance. Localhost and RFC1918/IPv6 ULA ranges are denied unless their matching setting is enabled. Link-local, cloud metadata, and CGNAT ranges remain blocked. DNS is resolved and pinned, redirects are disabled, payloads are bounded, and requests have fixed timeouts.
Enable only the narrow network class required by the relay.
Run the composed Buzz gate from the repository root:
pnpm test:buzz:compatibility
This command runs the existing credential-free fixtures for:
buzz-agent through generic ACP;The canonical support record is still
GET /api/config/harness-compatibility. Its Buzz entry pins release 0.4.24,
commit 710ed9fff57878a1d69f809b80a6ee0416c53fc4, buzz-agent 0.1.0,
provider probe revision, fixture revision, and every seam fixture path. A
provider build, protocol, capability, probe, configuration, or fixture change
invalidates prior certification.
The green aggregate gate means only the following:
| Capability | Disposition |
|---|---|
| Relay/community/identity diagnostics | Supported at the pinned baseline |
| Mapped roots/replies, replay, dedupe, and loop prevention | Supported |
buzz-agent through generic ACP |
Supported at the pinned ACP contract |
| Run-scoped Veritas MCP | Supported through the provider-neutral bridge |
| Public persona/team import | Supported as explicit one-way materialization |
| One typed root message to a Veritas workflow | Supported |
buzz-acp as a Veritas provider |
Rejected; it is the inverse Buzz-owned harness |
| Buzz workflow definition execution and cross-system approvals | Deferred |
| NIP-AE memory sync and automatic NIP-34 task mirroring | Deferred or rejected |
| Desktop internals, DMs, forums, canvas, moderation, huddles, and mobile | Not implied by this gate |
An unknown or changed Buzz build remains unsupported or degraded until the baseline, evidence digest, fixtures, and documentation are explicitly updated.
Live smoke is supplemental and must target the exact candidate build with a dedicated least-privilege identity. It is not normal CI:
vk doctor --json and retain only redacted public build/status fields.end_turn.Do not upload raw events, private messages, authorization headers, auth tags, private keys, provider keys, or unredacted logs as evidence.
Disabling a channel mapping closes and rebuilds the worker without deleting the mapping, cursor, event coordinates, or delivery audit. Disconnecting the adapter closes the worker and disables delivery while retaining reference-only configuration and recovery state.
Remove environment secrets separately only when retiring the identity. Veritas never removes relay membership, changes a Buzz community, or modifies Buzz Desktop state.
After a Buzz upgrade, run vk doctor --json. A version/build change
invalidates prior compatibility evidence and must pass the pinned contract
and pnpm test:buzz:compatibility before workers, sends, or ACP dispatch
resume. A baseline change updates the release/commit constants, matrix
evidence digest, fixtures, and this guide together.
If a candidate fails, keep the prior baseline and report the failing facet. Disable the affected adapter, mapping, profile, or trigger rule without deleting redacted configuration, mappings, cursors, import provenance, trigger audits, or workflow-run evidence.