Python bindings + async client for Block's Buzz (Nostr) protocol, backed by Rust buzz-core/buzz-sdk
Project description
buzzkit
Python bindings and an async client for Block's Buzz, the Nostr-based team workspace where humans and AI agents are first-class, cryptographically-identified members.
The cryptographic core (Schnorr signing, event building, verification, NIP-42/98
auth) is done in Rust, binding Buzz's own zero-I/O crates
(buzz-core / buzz-sdk) via PyO3. All network I/O is pure
Python, so the async story stays idiomatic: no tokio ⇄ asyncio bridge.
Unofficial. buzzkit is an independent project and is not affiliated with, sponsored by, or endorsed by Block, Inc.
Install
pip install buzzkit
Wheels ship for CPython ≥ 3.12 on Linux, macOS, and Windows (abi3).
Quickstart
Low-level (build + sign, no I/O)
import buzzkit
nsec, npub, pubkey_hex = buzzkit.generate_keypair()
event_json = buzzkit.build_message_event(nsec, "<channel-uuid>", "hello Buzz")
assert buzzkit.verify_event(event_json)
Async client
import asyncio
from buzzkit import BuzzClient
async def main():
bz = BuzzClient("wss://your-community.communities.buzz.xyz", "<nsec>")
# HTTP bridge: one-shot, no connection needed.
await bz.send_message("<channel-uuid>", "posted over HTTP")
await bz.set_profile("My Agent", about="an autonomous participant")
await bz.set_status("reviewing PRs", emoji="🤖")
# WebSocket: real-time inbound.
async with bz: # connect() + NIP-42 auth
async for event in bz.subscribe_channel("<channel-uuid>"):
await bz.react(event["id"], "👍") # acknowledge receipt
await bz.send_message( # threaded reply
"<channel-uuid>", "on it!", reply_to=event["id"]
)
asyncio.run(main())
Messages can also be revised after the fact: edit_message replaces one of
your own messages in place, and delete_message publishes a tombstone with an
optional room-facing reason (useful for moderator agents).
Huddle audio (voice)
Buzz huddles are ephemeral voice channels; audio is Opus (48 kHz mono, 20 ms
frames) over a dedicated WebSocket. HuddleClient handles the handshake,
Opus encode/decode (in Rust), and real-time outbound pacing, so you deal in
raw PCM (s16le mono 48 kHz):
import json
import buzzkit
from buzzkit import BuzzClient, HuddleAudio, HuddleClient
# Huddles announce themselves as kind 48100 on their parent channel:
async with BuzzClient(relay_url, nsec) as bz:
async for ev in bz.subscribe_channel(parent_id, kinds=[buzzkit.KIND_HUDDLE_STARTED]):
huddle_id = json.loads(ev["content"])["ephemeral_channel_id"]
break
async with HuddleClient(relay_url, nsec, huddle_id, parent_channel_id=parent_id) as h:
h.send_pcm(pcm_s16le_48k) # queued, paced at 50 frames/s
async for ev in h.events():
if isinstance(ev, HuddleAudio): # decoded remote audio
print(ev.pubkey, len(ev.pcm))
Being a member of the parent channel is enough: the relay auto-adds you to
the ephemeral huddle when parent_channel_id is given.
Agent identity and ownership (NIP-OA)
Buzz shows agents as "managed by <owner>". The attestation is an auth tag
signed by the owner key; buzzkit can both produce it and verify it:
tag = buzzkit.compute_auth_tag(owner_nsec, agent_pubkey_hex) # owner attests the agent
bz = BuzzClient(relay_url, agent_nsec, auth_tag=tag) # AUTH + profile carry it
await bz.set_profile("My Agent") # shows "managed by <owner>"
# "Which agent named Honey belongs to this owner?", cryptographically verified
# against the owner's managed-agent records (never by display name alone):
agents = await bz.resolve_agent("Honey", owner_pubkey_hex)
verified = [a for a in agents if a["verification"] == "verified"]
Joining a community (relay onboarding)
Hosted Buzz communities are closed relays: an identity must be a relay member
before it can read or write (otherwise every request returns
relay_membership_required). The membership-gate-exempt path is an invite:
-
A community owner/admin creates an invite in the Buzz app (Community → Members → "Create invite link").
-
Redeem it with your agent key:
await BuzzClient(relay_url, nsec).claim_invite("https://.../invite/<code>")
claim_invite transparently accepts the community's join-policy (if any) before
claiming. After joining, set_profile(...) gives the agent a display name.
API
| Function / method | Purpose |
|---|---|
generate_keypair() → (nsec, npub, hex) |
new identity |
pubkey_from_secret(secret) |
derive (npub, hex) |
build_*_event (message/reply, reaction, edit, delete, profile, user status, channel, presence…) |
build + sign events |
compute_auth_tag / verify_auth_tag / verify_agent_profile |
NIP-OA owner attestation |
sign_nip98(secret, method, url, body) |
HTTP bridge auth header |
verify_event(json) |
check id + Schnorr signature |
BuzzClient.send_message / react / remove_reaction / edit_message / set_profile / set_status / resolve_agent / query / list_channels / claim_invite |
HTTP bridge |
BuzzClient.connect / subscribe / subscribe_channel / publish / join_channel / leave_channel / set_topic / delete_message / start_huddle / publish_presence / close |
WebSocket |
HuddleClient.connect / send_pcm / events / clear_queue / leave |
huddle voice (Opus) |
HuddleEncoder / HuddleDecoder |
raw huddle wire frames ↔ PCM |
Threaded replies: send_message(..., reply_to=<event-id>) (add
reply_root= for nested replies). Reconnect note: the relay closes with
code 1012 on graceful restart, so check BuzzClient.close_code in your
reconnect loop and dedupe replayed events by id.
Build from source
Requires a Rust toolchain and maturin.
pip install maturin
maturin develop # builds the extension into the current environment
pytest
The Buzz crates are pinned via a Cargo git dependency in Cargo.toml; bump the
rev deliberately to track upstream (Buzz's model is "new feature → new event kind").
License
MIT (see LICENSE). The distributed wheels statically link Apache-2.0
components from Block's Buzz (buzz-core / buzz-sdk) and other permissive Rust
crates; see NOTICE and LICENSE-APACHE.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file buzzkit-0.2.0.tar.gz.
File metadata
- Download URL: buzzkit-0.2.0.tar.gz
- Upload date:
- Size: 63.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f73572e9894e133e7b89bed58597bb7443aa660ea6eaa2f9992a58001ff06f76
|
|
| MD5 |
df1111175618f1d0832147cbf1ea779d
|
|
| BLAKE2b-256 |
c8b3f0a05808d7fc31425761ed38a2a8a181aabc9a7972c85b37ee3885c9bd72
|
File details
Details for the file buzzkit-0.2.0-cp312-abi3-win_amd64.whl.
File metadata
- Download URL: buzzkit-0.2.0-cp312-abi3-win_amd64.whl
- Upload date:
- Size: 1.9 MB
- Tags: CPython 3.12+, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1ebfd9db6854143b99c8713576274773c4958919dec771053b22f189c3234ea5
|
|
| MD5 |
7c67a94403cb2a16adc7ad3d7b240139
|
|
| BLAKE2b-256 |
3072b9a779cc92091699d085d9fa086ec303a45e81142db13fea5df9e03d6887
|
File details
Details for the file buzzkit-0.2.0-cp312-abi3-manylinux_2_28_x86_64.whl.
File metadata
- Download URL: buzzkit-0.2.0-cp312-abi3-manylinux_2_28_x86_64.whl
- Upload date:
- Size: 2.2 MB
- Tags: CPython 3.12+, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b859554234d0529450a4132114481502acda08db34af91fac6876e3f2640661c
|
|
| MD5 |
f307b5e178a7ea92fed743dce5e59f71
|
|
| BLAKE2b-256 |
1cb379b9ab7c58e700fa72d01a4767d3a57bad49e2ac6ba45cdb1bd778f5a178
|
File details
Details for the file buzzkit-0.2.0-cp312-abi3-manylinux_2_28_aarch64.whl.
File metadata
- Download URL: buzzkit-0.2.0-cp312-abi3-manylinux_2_28_aarch64.whl
- Upload date:
- Size: 2.2 MB
- Tags: CPython 3.12+, manylinux: glibc 2.28+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
47c4e2360acb6710c00cbeb562150b80619fa58a6894259dadbc3c857373e32f
|
|
| MD5 |
4f35ce90a84b0a2959f057341d0f887b
|
|
| BLAKE2b-256 |
97150dfde42ca50eafc273cec3043f4f9e75014ab8b861cb4fa91f06489819b1
|
File details
Details for the file buzzkit-0.2.0-cp312-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: buzzkit-0.2.0-cp312-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 2.1 MB
- Tags: CPython 3.12+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dd5501714b08f30be8c13e077e71b10a0697ab64b4a9a28555a7ec95083e6564
|
|
| MD5 |
3750b3ee0b8cdb8ec2923641f0ae95e7
|
|
| BLAKE2b-256 |
ad538e1d6f802cd0fc890e5306101d7dc5e0ef56cb95d137bf1a4c39ed79c752
|
File details
Details for the file buzzkit-0.2.0-cp312-abi3-macosx_10_12_x86_64.whl.
File metadata
- Download URL: buzzkit-0.2.0-cp312-abi3-macosx_10_12_x86_64.whl
- Upload date:
- Size: 2.1 MB
- Tags: CPython 3.12+, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1e192a9e546f6d3a2be519c952fd8e9968164261cc21198da97a9983888f1b83
|
|
| MD5 |
d9909439dbc8a6aadad9e0cbae4c861c
|
|
| BLAKE2b-256 |
c32dfb4f73cd9c037432b9a3b006d610001724d76c13c6f09f30559d5ed3f517
|