트렌딩 딥다이브 · 2026-07-22 · TrendShift Daily #22 · BLOCK

block/buzz 딥다이브
— 사람과 AI 에이전트가 같은 채널의 동등한 멤버가 되는 워크스페이스

buzz는 Block(코딩 에이전트 goose를 만든 그 회사)이 내놓은 셀프호스트 팀 워크스페이스다. 슬랙 같은 채팅 앱처럼 보이지만, 밑바탕은 Nostr라는 분산 프로토콜 위에 세운 하나의 이벤트 로그다. 메시지·이모지·코드 패치·CI 결과·워크플로 실행·리뷰 승인·git 이벤트가 전부 암호로 서명된 같은 종류의 "이벤트"가 되어 한 곳에 쌓인다. 진짜 특별한 건 AI 에이전트가 "봇"이 아니라 "멤버"라는 점이다. 각 에이전트는 사람과 똑같이 자기만의 Nostr 키(신원)·채널 멤버십·감사 기록을 갖는다. 채널에 에이전트를 초대하는 방식이 사람을 초대하는 방식과 동일하고, 권한은 "플래그"가 아니라 "신원"으로 제한된다.

(저장소 block/buzz · Apache-2.0 · Rust 26개 크레이트 백엔드 + Tauri 데스크톱 + Flutter 모바일 · Nostr NIP-01 over WebSocket · 데스크톱 v0.4.22 · 최신 커밋 2026-07-21, 클론 소스 직접 분석)
목차
  1. 프로젝트 한 줄 요약
  2. 왜 주목받는가 — Slack+봇·Mattermost·Matrix와 뭐가 다른가
  3. 기술 스택 전체 지도
  4. 아키텍처 심화 — 릴레이 중심 이벤트 로그와 에이전트 연결
  5. 디렉토리 구조 해부
  6. 학습 포인트 — 여기서 훔쳐올 설계
  7. 하드웨어 / 시스템 요구사항
  8. 직접 해볼 수 있는 실습 과제
  9. 관련 기술 심화 학습 로드맵
  10. 핵심 키워드 사전
  11. 참고 링크

1프로젝트 한 줄 요약

"당신이 소유한 릴레이 위에서, 사람과 에이전트가 함께 일하는 공간"
한 문장으로

buzz = Nostr 릴레이 하나 위에 세운 셀프호스트 팀 워크스페이스 + AI 에이전트를 "봇"이 아니라 "동료 멤버"로 대우하는 신원 모델

겉으로는 채널·스레드·DM·캔버스·음성 허들이 있는 평범한 팀 협업 도구다. 하지만 그 아래는 "이벤트 로그"다 — 사람이 쓴 메시지든, 에이전트가 올린 코드 패치든, CI가 남긴 결과든 전부 같은 모양의 서명된 이벤트로 한 로그에 쌓이고, 같은 검색 색인과 같은 감사 추적(audit trail)에 들어간다.

README의 표현을 빌리면 "겉보기엔 팀 워크스페이스, 속을 보면 취향을 가진 이벤트 로그와 수상할 만큼 많은 Rust 크레이트"다. 에이전트가 그 안에서 실제로 할 수 있는 일 — 저장소 열기, 패치 보내기, 코드 리뷰, 워크플로 실행, 캔버스 편집, 다른 에이전트 지휘, 음성 허들 참여, 채널 생성 — 이 사람 동료와 똑같은 표면적이라는 게 핵심이다. 단지 키(keypair)가 다를 뿐.

buzz가 푸는 문제는 "팀이 지금 여러 도구를 접착제로 억지로 붙여 흉내 내는 것"을 하나로 합치는 것이다. 채팅은 슬랙, 코드는 GitHub, 자동화는 봇, CI 대시보드는 또 따로, 릴리스 도구도 따로 — 이 조각들을 잇는 글루 코드 더미. buzz는 이 모두를 하나의 이벤트 로그(substrate)로 모은다. 대화도, 패치도, CI 결과도, 워크플로 실행도, 승인도 전부 같은 종류의 이벤트라서 같은 검색·같은 감사 로그로 떨어진다.

용어
Nostr (노스터)
"Notes and Other Stuff Transmitted by Relays"의 약자. 원래는 검열에 강한 분산 SNS를 위해 만들어진 아주 단순한 프로토콜이다. 핵심 아이디어는 두 가지 — ① 사용자는 계정 서버가 아니라 키 쌍(개인키·공개키)으로 신원을 갖고, 모든 글은 개인키로 서명한다. ② 글(이벤트)은 릴레이(relay)라는 단순한 서버에 올렸다 내렸다 한다. buzz는 이 프로토콜을 SNS가 아니라 팀 워크스페이스에 재활용했다 — "당신이 소유한 릴레이 하나 = 하나의 커뮤니티(워크스페이스)"가 되는 식이다.

"오늘 동작하는 것"과 "배선 중인 것"을 README가 정직하게 구분해 둔 점도 눈에 띈다. 이미 되는 것: 릴레이·채널·스레드·DM·캔버스·미디어·검색·감사 로그, Tauri+React 데스크톱 앱, 에이전트용 buzz-cli와 ACP 하네스(Goose·Codex·Claude Code 연결), YAML 워크플로, NIP-34 git 이벤트, git 호스팅 백엔드. 배선 중: 모바일 클라이언트(Flutter), 워크플로 승인 게이트, 허들 생명주기. 아직 코드 없는 강한 의견: 릴레이 간 신뢰망 평판, 푸시 알림. 한마디로 완성품이 아니라 빠르게 자라는 중인 플랫폼이다(최신 커밋이 분석 전날).

2왜 주목받는가 — Slack+봇·Mattermost·Matrix와 뭐가 다른가

"에이전트를 위한 채팅"은 많다 — buzz의 승부수는 신원 모델과 단일 이벤트 로그

팀 채팅 도구는 차고 넘친다. Slack·Discord(+봇), 셀프호스트 진영의 Mattermost·Rocket.Chat·Zulip, 분산 프로토콜 진영의 Matrix/Element. 요즘은 여기에 "AI 봇을 붙였다"는 제품도 흔하다. 그런데 buzz가 트렌딩에 오른 이유는 기능 목록이 아니라 세 가지 근본 설계다 — ① 만든 주체가 Block(인기 코딩 에이전트 goose 제작사), ② 에이전트를 봇이 아니라 신원을 가진 멤버로 대우, ③ 채팅·git·CI·워크플로를 하나의 이벤트 로그로 통합.

기존 도구와의 결정적 차이

Slack+봇 / Mattermost / Matrixblock/buzz
AI 에이전트의 지위대개 봇 계정 — 사람과 다른 특별 취급, 권한 플래그로 통제일급 멤버 — 사람과 똑같이 Nostr 키·채널 멤버십·감사 기록을 가짐. "권한 플래그가 아니라 신원으로" 범위 제한
메시지·git·CI의 관계서로 다른 시스템(채팅/GitHub/CI)에 흩어짐, 글루 코드로 연결전부 같은 종류의 서명된 이벤트로 한 로그에 — 대화·패치·CI·승인이 같은 검색·감사에 들어감
바탕 프로토콜독자 프로토콜(Slack) 또는 MatrixNostr NIP-01 — 서명된 이벤트 + 릴레이라는 단순 모델. git은 NIP-34, 인증은 NIP-42/98
확장 방식새 기능 = 새 API·새 테이블·새 봇새 기능 = 새 kind 정수 하나(현재 81종). 이벤트 스키마를 안 깨고 추가
감사·추적시스템마다 로그가 따로, 위변조 검증 약함변조 감지 해시체인 감사 로그 — 모든 행위가 서명+연결되어 위조가 드러남
에이전트 연결봇 API/웹훅 위주(제품마다 제각각)ACP/MCP 표준 — goose·Codex·Claude Code 등 ACP 말하는 에이전트를 그대로 연결
비유

기존 도구가 "회사 사무실에 외부 로봇을 들여놓는" 방식이라면, buzz는 "로봇에게도 사원증을 발급하는" 방식이다. 슬랙의 봇은 방문객 배지를 단 외부 업체 같아서, 관리자가 "이 봇은 이 채널만" 하고 일일이 권한을 설정한다. buzz의 에이전트는 정식 사원증(자기 키)을 받은 동료다 — 어느 회의실(채널)에 들어갈 수 있는지는 그 사원증에 딸린 소속으로 자연히 정해지고, 그가 한 모든 일은 사원 본인 이름으로 기록에 남는다. "봇을 통제한다"가 아니라 "동료에게 권한을 위임한다"에 가깝다.

주목 포인트 4가지

① Block + goose라는 배경. Block(옛 Square, Jack Dorsey의 회사)은 오픈소스 코딩 에이전트 goose로 이미 개발자 사이에서 인지도가 높다. buzz는 goose를 "1급 시민"으로 대접한다 — ACP 하네스의 기본 에이전트가 goose다. 인기 에이전트를 만든 팀이 "그 에이전트가 팀에 들어와 함께 일하는 공간"을 내놓았다는 서사 자체가 관심을 끈다.

② "봇이 아니라 멤버"라는 철학의 구체성. 말로만이 아니라 코드로 강제된다. 에이전트는 buzz-admin mint-token으로 자기 Nostr 키와 스코프(messages:read,messages:write,channels:read 등)를 발급받고, 릴레이에 자기 신원으로 인증해 자기가 멤버인 채널만 자동 발견한다. "에이전트에게 왕국의 열쇠를 주지 않고 버그를 분류하게" 할 수 있다는 README 문구가 이 설계의 요점이다.

③ 하나의 로그가 주는 "영수증 있는 답". README의 예시가 인상적이다 — "이 에러 전에도 본 적 있어?"라고 물으면 에이전트가 6개월치 히스토리를 뒤져 실제 스레드를 근거로(vibes가 아니라 receipts) 답하고 채널에 남는다. 대화·패치·워크플로·승인이 한 색인에 있으니 가능한 일이다.

④ Apache-2.0 완전 오픈 + 진지한 엔지니어링. 26개 Rust 크레이트, TLA+ 형식 모델(docs/formal/), 해시체인 감사, iroh 기반 릴레이 간 QUIC 메시까지 — "채팅 앱" 치고 과할 만큼 진지하다. 셀프호스트를 위한 Helm 차트·Docker 이미지까지 갖췄다.

냉정하게 짚을 것
"완성품"이 아니고, Nostr·셀프호스트 학습비용이 있다

README가 스스로 "아직 끝나지 않았다(Not finished)"고 밝힌다. 모바일·승인 게이트·허들 생명주기는 배선 중이고, 신뢰망 평판·푸시 알림은 아직 코드가 없다. 또 이 시스템을 제대로 운영하려면 Postgres·Redis·S3(MinIO)·릴레이를 직접 띄우고 Nostr 키 관리·NIP 규격을 이해해야 한다 — Slack에 봇 하나 붙이는 것보다 초기 비용이 훨씬 크다. "우리 팀이 인프라를 소유하고 에이전트를 동료로 들이는" 그림에 진심인 조직에 맞는 도구지, 가벼운 팀 채팅 대체재가 아니다.

3기술 스택 전체 지도

Rust 릴레이 코어 + 3종 클라이언트(데스크톱·웹·모바일) + Postgres·Redis·S3

buzz는 여러 언어가 섞인 큰 모노레포다. "진실의 원천"인 릴레이 서버와 도구는 전부 Rust로, 사람이 보는 클라이언트는 각 플랫폼에 맞는 스택으로 짜여 있다.

① 백엔드 — Rust 26개 크레이트 워크스페이스

레이어선택비고
런타임Rust edition 2021, 툴체인 1.95.0(MSRV 1.88)Tokio 멀티스레드. 크레이트 26개
HTTP · WebSocketaxum 0.8(ws·macros) + tower 0.5릴레이가 WS(Nostr)와 REST 브리지를 한 서버에서 노출
DB 드라이버sqlx 0.9(postgres·uuid·chrono·json)컴파일 타임 SQL 검증. TLS는 rustls
Redisredis 1.0 + deadpool-redispresence·typing·다중 노드 팬아웃(pub/sub)
프로토콜nostr 0.44(nip44·nip98)Nostr 이벤트·서명·NIP 규격의 핵심 라이브러리
릴레이 간 메시iroh 1.0(QUIC)buzz-relay-mesh — 릴레이끼리 연합(federation)하는 QUIC 전송
에이전트 툴rmcp 1.1(MCP SDK, server·stdio·macros)MCP 서버로 에이전트에 shell·편집 툴 제공
자동화evalexpr 11 · cron 0.16 · serde_yamlYAML 워크플로 엔진(트리거·조건식·스케줄)
관측성tracing + OpenTelemetry(OTLP) + Prometheus메트릭·분산추적 내장
암호sha2 · hmac · subtle · zeroize · rand서명 검증·해시체인·상수시간 비교·키 제로화
저장Postgres 17 · Redis 7 · S3/MinIO(Blossom)이벤트+검색+감사 / presence / 미디어·git 오브젝트
용어
릴레이(relay)가 "단일 진실의 원천"
Nostr는 원래 여러 릴레이에 글을 흩뿌리는 분산 모델이지만, buzz는 기본 배포에서 릴레이 하나 = 커뮤니티 하나로 못 박았다. 모든 읽기·쓰기가 이 릴레이(buzz-relay, Axum 서버)를 통과하고, "P2P 이벤트 교환도, 가십(gossip)도 없다". 즉 분산 프로토콜의 포맷·신원 모델은 빌려오되, 운영은 "내가 소유한 서버 한 대"로 단순화했다. 릴레이끼리 잇는 iroh 메시는 선택적 federation 기능이다.

② 클라이언트 — 플랫폼별 3종

클라이언트스택특이점
데스크톱(주력)Tauri 2 + React 19 + Vite 8 (v0.4.22)Radix UI·TipTap 3(에디터)·Shiki(하이라이트)·react-diff-view(NIP-34 패치 렌더)·nostr-tools
React 19 + Vite 8isomorphic-git + lightning-fs — 브라우저 안에서 git 동작. 릴레이가 BUZZ_WEB_DIR로 서빙
관리자React + Vite (admin-web)운영자 콘솔
모바일Flutter / Dart (v0.4.11)riverpod·web_socket_channel(릴레이 WS)·nostr 2.0+pointycastle(키 암호)·secure_storage(키 보관)·mobile_scanner(QR 기기 페어링)
비유

백엔드 Rust 크레이트들이 하나의 발전소라면, 데스크톱·웹·모바일은 그 전기를 쓰는 서로 다른 가전이다. 중요한 건 세 가전 모두 같은 콘센트 규격(Nostr NIP-01 over WebSocket)에 꽂힌다는 점 — 그래서 데스크톱에서 보낸 메시지든 모바일에서 단 이모지든, 릴레이 입장에선 똑같은 서명 이벤트다. 클라이언트가 늘어도 서버 프로토콜은 하나로 유지된다.

③ 인프라 · 개발 환경

Hermit이 Rust 1.88+·Node 24+·pnpm 10+·just 같은 툴체인을 저장소에 핀으로 고정해 자동 설치한다(. ./bin/activate-hermit). Just(40KB Justfile)가 just setup/build/dev/test/ci 태스크를 오케스트레이션한다. 배포는 멀티스테이지 Dockerfile(cargo-chef, Rust 1.95+Node 24 → ghcr.io/block/buzz 멀티아치 이미지)과 Helm 차트(deploy/charts/buzz), Caddy 리버스프록시 compose 스택으로 제공된다. docker-compose.yml은 개발용으로 postgres:17·redis:7·adminer·keycloak:26·minio·prometheus를 한 번에 띄운다.

용어
"sprout"·"sprig" — 내부 코드명
워크스페이스의 repository 필드가 github.com/block/sprout을 가리킨다 — sprout는 buzz의 내부 코드명이다. 또 sprig라는 바이너리는 "buzz의 ACP 하네스·에이전트·개발용 MCP를 하나로 합친 올인원"이다. 공개 저장소(block/buzz)와 릴리스 저장소(squareup/buzz-releases), 내부 코드명(sprout)이 섞여 있는 건 대기업 내부 프로젝트가 오픈소스로 공개될 때 흔한 흔적이다.

4아키텍처 심화 — 릴레이 중심 이벤트 로그와 에이전트 연결

"모든 것이 하나의 릴레이를 통과한다"와 "에이전트는 어떻게 멤버가 되는가"

buzz의 설계는 두 축으로 이해된다. 하나는 릴레이 중심 구조(모든 클라이언트가 하나의 릴레이에 붙고, 모든 상태가 서명 이벤트로 쌓인다), 다른 하나는 에이전트 연결 경로(AI 에이전트가 어떻게 자기 신원으로 채널에 들어와 행동하는가)다.

(A) 시스템 구조 — 릴레이가 중앙, 이벤트가 통화(通貨)

사람 (데스크톱/웹/모바일) AI 에이전트 (goose·Codex·Claude Code) CLI·스크립트 │ │ buzz-acp (ACP ↔ MCP 브릿지) │ │ WebSocket (Nostr NIP-01) │ WS + REST │ WS + REST ▼ ▼ ▼ ┌──────────────────────────── buzz-relay (Axum) ────────────────────────────┐ │ NIP-42 인증 · EVENT 파이프라인 · REQ 핸들러 · HTTP 브리지 │ │ (/events /query /count /hooks/{id} /media/* /git/* /info) │ │ SubscriptionRegistry: (channel_id, kind) ─▶ 연결들 (DashMap) │ └───────┬──────────────────────┬──────────────────────────┬─────────────────┘ ▼ ▼ ▼ Postgres 17 Redis 7 S3 / MinIO 이벤트+전문검색(FTS) presence(SET EX) Blossom 미디어 +채널+토큰+워크플로 typing(ZADD) + git 오브젝트 +해시체인 감사로그 PUBLISH 다중노드 팬아웃

클라이언트가 무엇이든(사람의 데스크톱, 에이전트, 스크립트) 전부 같은 릴레이에 WebSocket으로 붙는다. 릴레이는 "단일 진실의 원천"이라 P2P 교환이 없다. 새 이벤트가 들어오면 Postgres에 저장되고, SubscriptionRegistry((채널, kind)→연결 매핑)를 통해 구독 중인 연결들에 실시간으로 팬아웃된다. 여러 릴레이 인스턴스로 수평 확장할 땐 Redis pub/sub이 노드 간 팬아웃을 담당한다.

용어
Nostr 와이어 메시지 (EVENT · REQ · AUTH)
Nostr는 WebSocket 위에서 JSON 배열로 대화한다. 클라이언트→릴레이: ["EVENT", 이벤트](글 올리기), ["REQ", 구독id, 필터](구독/조회), ["AUTH", 서명이벤트](인증). 릴레이→클라이언트: ["EVENT", …](구독 결과), ["EOSE"](저장분 끝, 이제부터 실시간), ["OK"](수락), ["AUTH", 챌린지](인증 요구). buzz는 여기에 프레임 최대 64KB·연결당 구독 1024개·필터당 결과 500개 같은 상한을 걸어 릴레이를 보호한다.

(B) 데이터 모델 — 모든 것이 "kind 번호"로 갈린다

buzz의 모든 상태는 서명된 Nostr 이벤트이고, 그 종류는 단 하나의 정수 kind로 구분된다. buzz-core가 81개 kind를 pub const KIND_* : u32 상수로 정의한다. README의 표현: "kind 정수가 유일한 디스패치 스위치… 새 기능 = 새 kind 번호 = 파괴적 변경 0."

kind이름의미
7REACTION이모지 반응(NIP-25)
9 / 40002STREAM_MESSAGE채널 채팅 메시지(NIP-29 그룹챗)
40003STREAM_MESSAGE_EDIT메시지 편집
40100CANVAS캔버스 문서
43001JOB_REQUEST에이전트 작업 요청
45001 / 45003FORUM_POST / COMMENT포럼 스레드 루트 / 답글
46001–46012WORKFLOW_*워크플로 실행 이벤트
20001PRESENCE_UPDATE휘발성 presence 하트비트(저장 안 함)
22242AUTHNIP-42 인증

kind 번호대에는 규칙이 있다 — 0~9999 표준 Nostr, 10000대 교체가능(replaceable), 20000대 휘발성(ephemeral, 저장·감사 안 함), 30000대 파라미터 교체가능, 40000대 buzz 커스텀. 그래서 presence 하트비트(20001) 같은 건 로그를 더럽히지 않고 흘러가고, 채팅·캔버스·워크플로(40000대)는 영구 기록된다. 이 모델로 채널·스레드·DM(NIP-44 암호화)·포럼·반응·캔버스·미디어·워크플로·git(NIP-34)·음성 허들·presence를 전부 표현한다.

(C) 에이전트는 어떻게 "멤버"가 되나 — ACP 하네스

buzz Relay ──WS(@멘션 감지)──▶ buzz-acp ──stdio(ACP)──▶ 당신의 에이전트 ──▶ buzz-cli (에이전트 신원으로 인증) 하네스 (goose/Codex/Claude) (send_message…) ▲ │ └──────────────────── 서명된 응답 이벤트로 채널에 게시 ◀────────────────┘

흐름은 이렇다. ① 운영자가 buzz-admin mint-token으로 에이전트에게 Nostr 키와 스코프를 발급한다. ② buzz-acp 하네스를 BUZZ_PRIVATE_KEY(에이전트 키)·BUZZ_ACP_AGENT_COMMAND=goose로 실행한다. ③ 하네스는 릴레이에 그 에이전트 신원으로 붙어, 에이전트가 멤버인 채널을 자동 발견하고 @멘션을 감시한다. ④ 멘션이 오면 goose acp를 띄워 프롬프트하고, 에이전트는 buzz-cli(JSON in/out)로 답을 채널에 게시한다.

용어
ACP(Agent Client Protocol) vs MCP(Model Context Protocol)
둘 다 JSON-RPC를 stdio로 주고받는 표준이지만 역할이 다르다. ACP는 "채팅 앱 ↔ 에이전트"를 잇는다 — buzz가 에이전트에게 "이 프롬프트에 답해"라고 말하는 창구다(goose·codex-acp·claude-agent-acp가 이걸 말한다). MCP는 "에이전트 ↔ 도구"를 잇는다 — 에이전트가 shell·파일편집 같은 도구를 부르는 창구다(buzz-dev-mcpshell·str_replace·todo 툴을 제공). 즉 buzz는 ACP로 에이전트를 부르고, 에이전트는 MCP로 실제 일을 한다.
영리한 디테일
에이전트 애그노스틱 — goose에 종속되지 않는다

Block이 만든 프로젝트지만 자사 goose에 강제로 묶지 않았다. ACP만 말하면 어떤 에이전트든 붙는다(Codex는 codex-acp, Claude Code는 claude-agent-acp 경유). 심지어 goose 대신 쓸 수 있는 자체 미니 에이전트 buzz-agent("최소한의, 안 깨지는 ACP 에이전트")와 도구 서버 buzz-dev-mcp, 올인원 sprig까지 함께 낸다. 환경변수 하나로 LLM 제공자를 갈아끼우고 최대 8개 세션(1~32 병렬 에이전트)을 돌린다. "우리 에이전트만 쓰라"가 아니라 "표준을 깔았으니 아무 에이전트나 데려와라"는 개방 전략이다.

보안 관점
에이전트가 shell을 쥐는 구조 — 신원·스코프가 방어선

buzz-dev-mcp는 에이전트에게 shell 실행 권한을 준다(종료 시 프로세스 그룹까지 정리). 강력한 만큼, buzz는 이를 "권한 플래그"가 아니라 신원과 스코프로 통제한다 — 에이전트 토큰에 messages:write 같은 스코프만 부여하고, 멤버가 아닌 채널엔 접근 자체가 안 된다. 모든 행위는 에이전트 키로 서명되어 해시체인 감사 로그에 남으므로 사후 추적이 가능하다. 그래도 "에이전트에게 shell을 준다"는 본질적 위험은 남으니, 셀프호스트 시 스코프 최소화·채널 격리·감사 로그 모니터링이 실전 필수다.

5디렉토리 구조 해부

26개 Rust 크레이트 + 클라이언트 3종 — 어디부터 열까
buzz/ (내부 코드명 sprout · 릴리스 squareup/buzz-releases) │ Justfile ★ 40KB 태스크 러너(setup/build/dev/test/ci) │ Cargo.toml ★ 워크스페이스 정의(크레이트 26개). repository=block/sprout │ Dockerfile 릴레이 이미지 → ghcr.io/block/buzz (멀티아치) │ docker-compose.yml 개발 인프라(pg17·redis7·minio·keycloak·prometheus) │ AGENTS.md ↔ CLAUDE.md 에이전트 지침(심링크). VISION_*.md 4종 │ ├─ crates/ ★★★ Rust 백엔드 26개 크레이트 │ ├─ buzz-core ★ I/O 없는 타입·NIP-01 필터·Schnorr 검증·81개 kind 레지스트리 │ ├─ buzz-relay ★★ Axum WS+REST 서버 = 단일 진실의 원천(SoT) │ ├─ buzz-db Postgres 접근(sqlx) │ ├─ buzz-auth NIP-42/98 인증·스코프·레이트리밋(사람/에이전트 분리) │ ├─ buzz-pubsub Redis presence·typing·다중노드 팬아웃 │ ├─ buzz-search Postgres 전문검색(FTS, search_tsv + GIN) │ ├─ buzz-audit ★ 변조감지 해시체인 감사 로그 │ ├─ buzz-workflow YAML 자동화 엔진(트리거·조건식·스케줄) │ ├─ buzz-media Blossom/S3 미디어 │ ├─ buzz-sdk 타입 안전 이벤트 빌더 │ ├─ buzz-cli ★ 에이전트용 CLI(JSON in/out) │ ├─ buzz-acp ★★ ACP 하네스 — @멘션↔에이전트 브릿지 │ ├─ buzz-agent ★ 자체 미니 ACP 에이전트(안 깨지는·비스트리밍) │ ├─ buzz-dev-mcp ★ shell·str_replace·todo 툴 제공 MCP 서버 │ ├─ buzz-persona .persona.md 에이전트 팩 │ ├─ buzz-admin 운영자 CLI(키·토큰 발급) │ ├─ buzz-relay-mesh iroh QUIC 릴레이 연합(federation) │ ├─ buzz-push-gateway 모바일 푸시(NIP-PL) │ ├─ buzz-pair-relay / buzz-pairing-cli NIP-AB 기기 페어링 │ ├─ git-sign-nostr / git-credential-nostr Nostr 서명 git │ ├─ buzz-conformance TLA+ 리플레이 검증기 │ └─ sprig 올인원(하네스+에이전트+개발 MCP) │ ├─ desktop/ Tauri 2 + React 19 데스크톱 앱(주력 클라이언트) ├─ web/ React 19 브라우저 클라이언트(isomorphic-git) ├─ admin-web/ React 관리자 콘솔 ├─ mobile/ Flutter/Dart iOS+Android ├─ deploy/ compose(Caddy)·local(k8s)·charts(Helm) ├─ docs/ architecture·nips(커스텀 NIP)·spec·formal(TLA+ 모델) ├─ migrations/ Postgres SQL 마이그레이션 24개 ├─ examples/ 샘플 에이전트(countdown-bot·meadow-core) └─ .goose/ .claude/ .codex/ .agents/ 에이전트 스킬 팩(이 레포 자체가 이걸로 개발됨)
읽는 순서 추천

README.md + docs/ARCHITECTURE.md(개념 지도) → crates/buzz-core(kind 레지스트리·이벤트 타입 = 이 시스템의 "명사 사전") → crates/buzz-relay(EVENT/REQ 파이프라인 = 모든 게 통과하는 관문) → crates/buzz-auth(NIP-42/98·스코프 = 신원 모델의 실체) → crates/buzz-acp + buzz-cli(에이전트가 멤버가 되는 경로) → crates/buzz-workflow + buzz-audit(자동화와 감사) → desktop/(사람이 보는 화면). docs/formal/의 TLA+ 모델과 docs/nips/의 커스텀 NIP 스펙은 설계 의도를 가장 정확히 담은 고신뢰 자료다.

용어
해시체인 감사 로그 (tamper-evident audit log)
각 기록에 "이전 기록의 해시"를 포함시켜 사슬처럼 잇는 방식(buzz-audit). 중간 기록을 몰래 바꾸면 그 뒤 모든 해시가 어긋나 변조가 즉시 드러난다. 블록체인의 핵심 아이디어(해시 연결)만 빌려온 것이지, buzz는 "블록체인이 아니다"라고 README가 못 박는다 — 합의·채굴·분산원장 없이, 단일 서버 안에서 "위조 불가능한 순서 기록"만 취한 실용적 절충이다. 에이전트가 한 모든 행위를 사후에 신뢰성 있게 추적하는 근거가 된다.

6학습 포인트 — 여기서 훔쳐올 설계

팀 채팅에 관심 없어도 배울 값어치가 있는 것들
패턴 1 · 모든 것을 "하나의 이벤트 로그"로

이벤트 소싱(event sourcing)의 실전판

메시지·패치·CI·승인·워크플로를 각기 다른 테이블/시스템에 두는 대신, 전부 같은 종류의 append-only 이벤트로 한 로그에 쌓는다. 상태는 이 이벤트들을 재생(replay)해 얻는다. "현재 상태를 저장"하는 대신 "일어난 일을 순서대로 저장"하는 이벤트 소싱은 감사·시간여행 디버깅·재구성에 강하다. buzz는 이걸 채팅 도메인에 적용해 "대화와 코드와 자동화가 한 검색에 들어가는" 효과를 얻었다.

패턴 2 · 확장을 "정수 하나"로 흡수

kind 번호 = 파괴적 변경 없는 확장점

새 기능을 추가할 때 스키마를 바꾸거나 API를 깨지 않는다 — kind 정수를 하나 배정할 뿐이다(현재 81종). 모르는 kind는 클라이언트가 그냥 무시하면 되니 하위호환이 자연히 유지된다. 게다가 번호대(20000대=휘발성, 40000대=커스텀)로 "저장할 것/흘려보낼 것"까지 구분한다. "타입을 데이터(번호)로 표현해 디스패치한다"는 이 발상은 플러그인 시스템·메시지 버스·이벤트 스트림 설계에 두루 쓰인다.

패턴 3 · 권한을 "플래그"가 아니라 "신원"으로

봇에게도 사원증을 준다

에이전트를 특별 취급하지 않고 사람과 같은 키·멤버십·감사를 준 뒤, 접근 범위를 "이 봇은 이거 허용" 플래그가 아니라 "이 신원이 어느 채널의 멤버인가"로 정한다. 권한 로직이 단순해지고(멤버십 = 접근), 모든 행위가 행위자 신원으로 서명되어 추적된다. 서비스 계정·자동화 주체가 늘어나는 시스템에서 "주체마다 신원을 부여하고 신원으로 인가한다"는 원칙은 제로트러스트 설계와도 통한다.

패턴 4 · 기존 프로토콜을 "용도 변경"

SNS용 Nostr를 팀 워크스페이스로

검열저항 SNS를 위해 만든 Nostr(서명 이벤트 + 릴레이)를, 그 신원·포맷 모델만 취하고 운영은 "내가 소유한 릴레이 한 대"로 단순화해 팀 도구에 재활용했다. 새 프로토콜을 발명하는 대신 검증된 프로토콜의 좋은 부분을 빌리고, 안 맞는 부분(분산·가십)은 과감히 버린 선택. "바퀴를 다시 발명하지 말되, 필요한 바퀴만 떼어 쓴다"는 실용주의의 사례다.

패턴 5 · 표준으로 에이전트를 갈아끼운다

ACP + MCP — 벤더 중립 에이전트 연결

자사 goose에 묶지 않고 ACP(앱↔에이전트)와 MCP(에이전트↔도구)라는 표준 위에 얹어, 어떤 에이전트든 환경변수 하나로 연결한다. "우리 것만 쓰라"는 잠금 대신 표준을 깔아 생태계를 끌어들이는 전략은, 통합 지점을 표준 인터페이스로 두면 구현체를 자유롭게 교체할 수 있다는 소프트웨어 설계의 기본을 AI 에이전트 영역에 적용한 것이다.

패턴 6 · 채팅 앱에 형식 검증(TLA+)을 붙인다

"취향을 가진 이벤트 로그"의 진짜 의미

docs/formal/의 TLA+ 모델과 buzz-conformance(리플레이 검증기)는 이 프로젝트가 동시성·순서 보장을 형식적으로(수학적으로) 검증하려 한다는 신호다. 여러 클라이언트가 같은 릴레이에 동시에 이벤트를 밀어넣을 때의 경쟁 조건을, 테스트만이 아니라 모델 체킹으로 잡는다. "분산/동시 시스템의 미묘한 버그는 형식 명세로 잡는다"는 고급 기법을 실제 오픈소스에서 어떻게 쓰는지 관찰할 좋은 교보재다.

7하드웨어 / 시스템 요구사항

"채팅 앱" 치고 인프라가 묵직하다 — 릴레이 + DB + 캐시 + 오브젝트 스토리지

buzz는 단순 클라이언트가 아니라 서버 스택을 통째로 자가호스팅하는 시스템이다. 개발용 docker compose up 하나로 필요한 백엔드가 다 뜨지만, 그 안에 무엇이 도는지 알고 있어야 운영이 된다.

항목요구/권장
소스 빌드 툴체인Docker + Hermit(자동) 또는 수동으로 Rust 1.88+·Node 24+·pnpm 10+·just
빌드 절차. ./bin/activate-hermitjust setup && just buildjust dev(릴레이+데스크톱 동시)
릴레이Rust buzz-relay 바이너리. 포트 3000(WS+REST). ws://localhost:3000
데이터베이스Postgres 17(이벤트·검색·감사·워크플로). 포트 5432
캐시/실시간Redis 7(presence·typing·팬아웃). 포트 6379
오브젝트 스토리지S3 또는 MinIO(Blossom 미디어 + git 오브젝트). 9000/9001
선택 인프라Keycloak(8180 인증)·Prometheus(9090 메트릭)·Adminer(8082 DB UI)
프리빌트 앱GitHub 릴리스: macOS .dmg · Linux .AppImage/.deb · Windows .exe
기본 접속클라이언트는 ws://localhost:3000에 붙음. BUZZ_RELAY_URL로 변경
에이전트 실행BUZZ_PRIVATE_KEY(에이전트 키) + buzz-cli/buzz-acp. Windows는 shell 툴에 Git Bash 필요
프로덕션ghcr.io/block/buzz 이미지 + Helm 차트(deploy/charts/buzz) + Caddy compose
운영 주의
멀티테넌트·미디어·키 관리가 실전 난이도를 좌우한다

단일 릴레이는 "URL = 커뮤니티 하나"지만, 호스팅 운영자는 요청 호스트(도메인)로 여러 커뮤니티를 한 릴레이가 서빙하는 멀티테넌트 모드를 쓴다 — 알 수 없는 호스트는 "fail closed"(거부)로 처리된다. 또 미디어는 S3/MinIO에, git 오브젝트도 별도로 관리해야 하고, 무엇보다 모든 신원이 Nostr 키라 키 발급·보관·회수 절차(buzz-admin)를 팀 규칙으로 세워야 한다. "슬랙 대체"로 가볍게 접근하면 이 운영 부담에 놀랄 수 있으니, 인프라를 직접 굴릴 역량이 있는 팀에 적합하다.

8직접 해볼 수 있는 실습 과제

난이도별로, 손을 움직이며 배우는 순서

과제 1. 릴레이 띄우고 데스크톱으로 접속 난이도 ★☆☆

저장소를 클론하고 . ./bin/activate-hermitjust setup && just buildjust dev로 릴레이+데스크톱을 함께 띄운다. 채널을 만들고 메시지·이모지·스레드를 눌러보며, docker compose로 뜬 Adminer(8082)에서 Postgres의 이벤트 테이블에 내 메시지가 서명 이벤트로 쌓이는지 직접 확인한다.

과제 2. buzz-cli로 "사람 없이" 메시지 보내기 난이도 ★★☆

buzz-admin mint-token으로 키·스코프를 발급받아 BUZZ_PRIVATE_KEY로 설정하고, buzz-cli messages send(JSON in/out)로 채널에 메시지를 게시한다. messages search로 과거를 검색하고 messages send-diff로 NIP-34 패치를 올려본다 — "에이전트가 무엇을 손에 쥐는지"를 사람이 직접 대신 쳐보는 과제다.

과제 3. goose를 멤버로 초대하기 난이도 ★★★

goose(또는 buzz-agent)를 설치하고 buzz-acp 하네스를 BUZZ_ACP_AGENT_COMMAND=goose로 실행해, 에이전트에게 별도 키를 발급한 뒤 채널에 초대한다. 채널에서 @에이전트를 멘션하면 하네스가 프롬프트→응답을 게시하는 전 과정을 로그로 따라가며, 에이전트가 자기 신원으로 채널에 등장하는지 확인한다.

과제 4. YAML 워크플로 하나 짜기 난이도 ★★★

buzz-workflow의 트리거(message/reaction/schedule/webhook) 중 하나로 간단한 자동화를 만든다 — 예: 특정 채널에 :ship: 이모지가 달리면 에이전트가 릴리스 노트 초안을 게시. 워크플로 실행이 kind 46001~46012 이벤트로 로그에 남는지, 승인 반응(👍)이 다음 단계를 트리거하는지 관찰한다.

과제 5. 커스텀 kind로 새 기능 추가 난이도 ★★★★

buzz-core의 kind 레지스트리에 KIND_* 상수(40000대)를 하나 추가하고, 그 이벤트를 릴레이가 저장·팬아웃하도록 buzz-relay를 확장한 뒤, 데스크톱에 최소 렌더링을 붙여본다. "새 기능 = 새 kind 번호"라는 주장이 정말 파괴적 변경 없이 성립하는지, 기존 클라이언트가 모르는 kind를 잘 무시하는지 직접 검증하는 과제다.

9관련 기술 심화 학습 로드맵

이 저장소를 발판 삼아 넓혀갈 4주 코스

1주차 — Nostr 프로토콜과 NIP 규격

Nostr의 기본(키 쌍·서명 이벤트·릴레이·EVENT/REQ 와이어)을 NIP-01부터 읽고, buzz가 쓰는 NIP들 — NIP-42(인증)·NIP-44(암호화 DM)·NIP-34(git)·NIP-98(HTTP 인증) — 을 docs/nips/의 커스텀 스펙과 함께 정리한다. nostr-tools로 브라우저에서 이벤트를 직접 서명·전송해보면 감이 빨리 온다.

2주차 — 이벤트 소싱과 CQRS

"현재 상태 저장" 대신 "이벤트 순서 저장 → 재생으로 상태 도출"하는 이벤트 소싱 패턴, 그리고 읽기/쓰기 모델을 분리하는 CQRS를 학습한다. buzz의 buzz-core kind 디스패치와 Postgres 이벤트 테이블 + FTS 인덱스가 이 이론을 어떻게 실제 코드로 구현했는지 대조한다. append-only 로그 + 해시체인 감사(buzz-audit)도 함께.

3주차 — 에이전트 프로토콜(ACP·MCP)

MCP(에이전트↔도구)와 ACP(앱↔에이전트) 두 표준을 공식 문서로 익히고, buzz-dev-mcp(MCP 서버)와 buzz-acp(ACP 하네스) 소스를 교재로 "에이전트를 시스템에 안전하게 끼워 넣는" 통합 지점을 설계해본다. goose·codex-acp·claude-agent-acp가 같은 ACP 표면을 어떻게 공유하는지 비교.

4주차 — 실시간 분산 시스템과 형식 검증

axum WebSocket·Redis pub/sub 팬아웃·iroh QUIC 메시로 "다중 노드 실시간 시스템"을 이해하고, docs/formal/의 TLA+ 모델과 buzz-conformance동시성 버그를 모델 체킹으로 잡는 방법을 맛본다. Postgres/Redis/S3를 각각 어떤 책임에 배정했는지(내구성·속도·대용량) 정리하며 마무리.

10핵심 키워드 사전

이 문서에 나온 용어를 한 줄로
buzz / 하이브 마인드
Block이 만든 셀프호스트 팀 워크스페이스. "하이브(🐝 벌집)"는 사람과 AI 에이전트가 함께 속한 커뮤니티를, "마인드"는 하나의 이벤트 로그로 공유되는 집단 기억을 뜻한다.
Nostr
서명된 이벤트를 릴레이에 주고받는 단순 분산 프로토콜. buzz는 이 신원·포맷 모델을 팀 도구에 재활용했다(운영은 단일 릴레이로 단순화).
릴레이(relay)
Nostr 이벤트를 받고 나눠주는 서버. buzz에선 buzz-relay(Axum) 하나가 "단일 진실의 원천"이고, URL 하나가 커뮤니티 하나를 가리킨다.
kind
이벤트 종류를 가르는 정수. buzz는 81종을 정의하고, 새 기능은 새 kind 번호로 추가해 파괴적 변경을 피한다. 번호대로 저장/휘발도 구분(20000대=휘발).
이벤트 소싱(event sourcing)
현재 상태 대신 "일어난 일(이벤트)"을 순서대로 저장하고 재생해 상태를 얻는 방식. 감사·재구성·시간여행 디버깅에 강하다. buzz의 근간.
NIP-01 / 42 / 44 / 34 / 98
Nostr Improvement Possibilities. 01=기본 와이어, 42=릴레이 인증, 44=암호화 DM, 34=git 이벤트(패치·저장소), 98=HTTP 인증. buzz가 조합해 쓴다.
ACP(Agent Client Protocol)
"앱 ↔ 에이전트"를 잇는 JSON-RPC 표준. buzz가 에이전트에게 프롬프트를 넘기는 창구. goose·Codex·Claude Code가 이걸 말한다.
MCP(Model Context Protocol)
"에이전트 ↔ 도구"를 잇는 표준. buzz-dev-mcp가 shell·파일편집·todo 툴을 에이전트에 제공한다.
buzz-cli
에이전트용 명령줄 도구(JSON in/out). LLM 툴콜에 맞춰 설계됨 — messages send/search/send-diff, channels create/join 등. 에이전트의 "손".
buzz-acp
릴레이의 @멘션을 감지해 에이전트를 프롬프트하고 응답을 게시하는 하네스. 에이전트를 "멤버"로 만드는 다리. 최대 8세션·1~32 병렬.
goose
Block이 만든 오픈소스 코딩 에이전트. buzz의 ACP 기본 에이전트지만, ACP만 말하면 다른 에이전트로 교체 가능(벤더 중립).
해시체인 감사 로그
각 기록에 이전 기록의 해시를 넣어 변조를 드러내는 방식(buzz-audit). 블록체인의 해시 연결만 빌린 실용 절충(합의·채굴 없음).
Blossom
Nostr 생태계의 미디어(blob) 저장 규격. buzz는 이미지·파일을 S3/MinIO에 Blossom 방식으로 저장한다.
iroh
QUIC 기반 P2P 네트워킹 라이브러리. buzz의 buzz-relay-mesh가 릴레이끼리 연합(federation)하는 데 쓴다(선택 기능).
TLA+ / 형식 검증
시스템을 수학적으로 명세해 동시성·순서 버그를 모델 체킹으로 잡는 기법. buzz는 docs/formal/buzz-conformance로 이를 시도한다.

11참고 링크

원본부터 배경 지식까지

프로젝트

핵심 소스(먼저 읽을 파일)

기반 기술