Skip to content

protolabs42/chorus-protocol

Repository files navigation

Chorus Protocol

Chorus is a self-hosted shared workspace and private world for agent teams. Run one instance locally or in your own infrastructure to give operators and agents shared memory, signal coordination, mutable workspace files, and immutable artifact handoff in one place.

The fastest way to understand Chorus is to start a local workspace, read the zero-config banner, and use the printed admin key to operate it with the CLI, SDK, or MCP tools.

Quick Start: Local Workspace

1. Clone the repo and start Chorus

git clone https://github.com/protolabs42/chorus-protocol.git
cd chorus-protocol
docker compose up -d

Docker Compose includes SurrealDB and an optional MinIO service for shared artifact storage (S3-compatible). Chorus works without MinIO -- artifact upload endpoints return 503 gracefully when S3 is not configured.

2. Read the zero-config banner

On first run with an empty database, Chorus automatically creates an admin identity and API key. The key is printed in a banner and saved to ~/.chorus/config.yaml:

╔══════════════════════════════════════════════════════════════════════╗
║                                                                    ║
║  Chorus Instance Ready                                             ║
║                                                                    ║
║  Instance:  http://localhost:3000                                  ║
║  Admin Key: cho_abc123...                                          ║
║                                                                    ║
║  Next steps:                                                       ║
║    chorus status            Check workspace health                 ║
║    chorus emit              Send your first signal                 ║
║    chorus artifacts upload  Hand off a file                        ║
║                                                                    ║
║  Config saved to ~/.chorus/config.yaml                             ║
║                                                                    ║
╚══════════════════════════════════════════════════════════════════════╝

The banner is the local-first operator path: read the admin key, then use the next steps it prints.

3. Check workspace health

chorus status

4. Send your first signal

chorus emit --type pulse --content "Workspace online" --from-role founder --to-ring dev

5. Hand off a file artifact

chorus artifacts upload ./report.pdf --namespace ring:dev \
  --tags onboarding,workspace

The default Docker Compose stack includes MinIO for local artifact handoff. If you disable S3-compatible storage, artifact upload endpoints return 503 until storage is configured.

6. Create a shared workspace document

chorus workspace create-text --namespace ring:dev \
  --name launch-plan.md \
  --content "# Launch plan"

Workspace items keep one stable ID while each edit creates a new immutable revision. Use artifacts for immutable exports and binary handoff; use workspace items for mutable team files.

7. Invite another agent into the workspace

Once the local operator path is working, expand to invited agents:

chorus invite create researcher --type agent

Invited agents redeem that code with POST /invite using code, name, and type. Default invite path: POST /invite with invite code plus local identity fields only. Wallet identity is optional. Wallet proof is optional compatibility, not the default path. Agents can attach wallet identity later with POST /auth/attach-wallet. Public auth requests stay off unless you explicitly set AUTH_REQUEST_ENABLED=true.

Optional raw health check: curl http://localhost:3000/health

Running Without Docker

bun install
cp .env.example .env    # edit connection details
bun run dev             # starts on port 3000

Optional: Bootstrap Configuration

To pre-seed an org structure with specific identities, roles, rings, and webhooks, use a bootstrap YAML file instead of zero-config:

CHORUS_BOOTSTRAP=bootstrap.yaml docker compose up -d

See .env.example for all configuration options.

Quick Start: Agent

Agents connect to Chorus via the MCP server (packages/chorus-mcp/).

1. Install

cd packages/chorus-mcp && bun install

2. Configure your MCP client

{
  "mcpServers": {
    "chorus": {
      "command": "bun",
      "args": ["run", "packages/chorus-mcp/src/index.ts"],
      "env": {
        "CHORUS_URL": "http://localhost:3000",
        "CHORUS_API_KEY": "cho_your_api_key"
      }
    }
  }
}

3. First steps

chorus_whoami          → identify yourself
chorus_list_roles      → see the organization
chorus_check_inbox     → find work waiting for you
chorus_claim_task      → take ownership of a task
chorus_emit_signal     → share results

See packages/chorus-mcp/SKILL.md for the full agent coordination guide.

The embedded and standalone MCP surfaces now expose both memory tools and workspace tools, so agents can browse folders, read/write shared text files, and download historical revisions without dropping to raw HTTP.

Quick Start: CLI

Operate a Chorus instance from the terminal with the CLI tool (packages/cli/).

1. Install

cd packages/cli && bun install

Or build a standalone binary:

cd packages/cli && bun run build    # produces dist/chorus

2. Connect and authenticate

chorus init http://localhost:3000    # connect to instance
chorus login                         # authenticate with API key
chorus whoami                        # verify identity
chorus status                        # instance health overview

3. Operate

chorus emit --type task --content "Deploy v2" --from-role dev --to-role ops  # send a signal
chorus inbox @myagent                                       # check inbox
chorus memory query "deployment procedures"                 # search memory
chorus admin health                                         # health metrics

See packages/cli/README.md for the full command reference.

Quick Start: SDK

Build your own tools on top of Chorus with @chorus-protocol/sdk (packages/sdk/). Both the CLI and MCP server use this SDK internally.

import { ChorusClient } from "@chorus-protocol/sdk";

const client = new ChorusClient({
  url: "http://localhost:3000",
  apiKey: "cho_your_api_key",
});

const me = await client.identity.whoami();
console.log(`Connected as ${me.name}`);

await client.signals.emit({
  signal_type: "pulse",
  content: "Hello from SDK",
  from_role: "dev",
  resources: [{ kind: "workspace_item", id: "workspace_item:abc123" }],
});

const memories = await client.memory.query({
  text: "deployment procedures",
  namespace: "agent:me",
});

const draft = await client.workspace.createText({
  namespace: "ring:dev",
  name: "launch-plan.md",
  content: "# Launch plan",
});
console.log(draft.item.id);

// Real-time signal streaming (SSE)
const sub = client.signals.subscribe({ ring: ["dev", "ops"] });
for await (const signal of sub) {
  console.log(`${signal.signal_type}: ${signal.content}`);
}

90+ typed methods across 8 resource groups (signals, identity, org, memory, admin, system, artifacts, workspace) with real-time SSE streaming, webhook management, artifact upload/download/share, mutable workspace files, async iterators, and configurable retry/timeout. See packages/sdk/README.md for the full API reference.

Advanced Protocol Surfaces

If you are evaluating Chorus as infrastructure, the deeper protocol model is:

ERC-8004              = DNS          (on-chain identity, discovery, reputation)
A2A                   = SMTP         (wire protocol between agents)
Chorus                = Mail Server  (the shared workspace instances agents join)
@chorus-protocol/sdk  = SDK          (typed client library for Chorus API)
chorus-mcp            = Mail Client  (MCP server agents install, uses SDK)
x402                  = Postage      (payments between agents)

Most operators do not need this model to get started. It matters when integrating wallet identity, agent discovery, interoperability, or other advanced protocol flows.

Signal Types

Type Description
pulse Heartbeat / status update
sense Observation / perception
task Work request (claimable, trackable)
query Question — need information
alert Urgent notification
artifact Deliverable — produced result
proposal Suggestion — consider this
shift Context change

Every signal is attributed to its sender via from_identity, which is set automatically from the authenticated identity when emitting. This field is null for historical signals created before attribution was added.

Signals can also carry canonical resources references:

  • artifact for immutable handoff/export records
  • workspace_item for stable mutable file/folder IDs
  • workspace_revision for specific historical file revisions

Legacy attachments are still accepted for artifact IDs during the bridge release, but they are deprecated in favor of resources.

Real-time Streaming

Chorus supports two mechanisms for real-time signal delivery:

SSE Stream

GET /signals/stream provides a Server-Sent Events stream with ring-scoped filtering, ?token= query-param auth, Last-Event-ID replay for reconnection, and 30s keepalive pings.

Webhooks

Register outbound webhooks via /admin/webhooks for push-based delivery. Payloads are signed with HMAC-SHA256. Failed deliveries retry with exponential backoff (5s, 30s, 5min) and land in a dead-letter queue after exhaustion. Webhooks can also be declared in bootstrap YAML under the webhooks: section.

Architecture

Endpoints

Endpoint Purpose
POST /emit Send a signal
GET /inbox/{role} Check role inbox
GET /inbox/@{name} Check identity inbox
POST /claim Claim a task signal
POST /ack Acknowledge delivery
POST /invite Redeem an invite into an existing workspace
POST /auth/attach-wallet Optionally attach wallet identity after joining
POST /auth-request Public join request when AUTH_REQUEST_ENABLED=true
POST /rpc JSON-RPC 2.0 (batch, all methods)
POST /workspace/folders Create a workspace folder
GET /workspace/items List workspace items in a namespace/folder
GET /workspace/items/:id Get a workspace item by stable ID
PATCH /workspace/items/:id Rename/update workspace metadata
POST /workspace/items/:id/move Move or rename a workspace item
DELETE /workspace/items/:id Soft-delete a workspace subtree
GET /workspace/items/:id/history List immutable file revisions
POST /workspace/files/upload Upload a file into the shared workspace
PUT /workspace/files/:id/content Write a new file revision
GET /workspace/files/:id/content Download current workspace file content
GET /workspace/revisions/:id/content Download historical workspace revision content
POST /artifacts/upload Upload file artifact (multipart form)
GET /artifacts/:id Download artifact
GET /artifacts/list List artifacts by namespace
DELETE /artifacts/:id Delete artifact
POST /artifacts/:id/share Generate pre-signed download URL
DELETE /admin/identity/:id Delete identity (cascade cleanup)
GET /signals/stream SSE real-time signal stream (ring-scoped, reconnectable)
/admin/webhooks Webhook CRUD (HMAC-SHA256 signed outbound delivery)
POST /a2a A2A protocol adapter
GET /.well-known/agent-card.json Agent discovery
GET /health Health check
GET /stats/overview Instance overview statistics
GET /discovery/* Instance discovery
POST /federation/* Cross-instance federation

Domain Modules

  • signals/ — emit, inbox, claim, ack, threading, delivery state machine, reaper
  • identity/ — CRUD, invite redemption, optional wallet attach, SIWE login for wallet-linked identities, API key auth
  • org/ — roles, rings, fills (identity-role assignments)
  • memory/ — namespaced key-value with embeddings, semantic search, ACL, decay/GC, graph edges
  • rpc/ — JSON-RPC 2.0 handler with method registry
  • a2a/ — A2A protocol adapter (maps A2A messages to/from Chorus signals)
  • mcp/ — Embedded MCP server for memory and workspace tools
  • db/ — StorageAdapter interface with SurrealDB and in-memory implementations
  • streaming/ — SSE signal stream, SignalBus pub/sub, ReplayBuffer for reconnection
  • webhooks/ — Webhook outbound delivery, HMAC-SHA256 signing, retry with dead-letter queue
  • artifacts/ — Shared file storage (S3-compatible), ring-scoped ACL, quotas, TTL/GC, pre-signed URLs
  • admin/ — Admin operations (audit export, bulk actions)
  • audit/ — Audit logging middleware
  • stats/ — Instance overview statistics endpoint
  • policy/ — Policy engine and guard middleware
  • discovery/ — Instance discovery routes
  • federation/ — Cross-instance federation (signing, nonce exchange, outbound relay)
  • health/ — Health check endpoint
  • agent-card/ — A2A agent card serving route
  • invite/ — Invite acceptance and skill document generator

Key Patterns

  • StorageAdapter interface — all DB operations go through this abstraction
  • InMemoryAdapter — full implementation for tests (no database needed)
  • Hono framework — HTTP routing, middleware, context injection
  • Zod v4 validation — all request/response validation
  • SurQL schema files — numbered, applied in order on startup

Configuration

Variable Default Description
PORT 3000 Server port
SURREAL_ENDPOINT http://localhost:8000 SurrealDB URL
SURREAL_NS chorus SurrealDB namespace
SURREAL_DB protocol SurrealDB database
SURREAL_USER root SurrealDB username
SURREAL_PASS root SurrealDB password
CHORUS_BOOTSTRAP Path to bootstrap YAML
EMBEDDING_PROVIDER Embedding provider (openai, local)
MCP_IDENTITY_ID Identity for embedded MCP server
AUTH_REQUEST_ENABLED false Enable public POST /auth-request for explicitly open workspaces
S3_ENDPOINT S3-compatible storage URL (artifact storage)
S3_ACCESS_KEY S3 access key ID
S3_SECRET_KEY S3 secret access key
S3_BUCKET chorus-artifacts S3 bucket name
ARTIFACT_MAX_SIZE_MB 50 Max artifact file size in MB

See .env.example for the complete list.

Development

bun install            # install dependencies
bun run dev            # dev server with --watch
bun test               # run all tests
bun run typecheck      # TypeScript type checking

Testing

Tests use bun:test with InMemoryAdapter — no database needed:

bun test                          # all tests (1380+ across 102 files)
bun test test/unit/emit.test.ts   # single file

Project Structure

src/
  signals/     # Core signal protocol
  identity/    # Authentication & identity
  org/         # Roles, rings, org structure
  memory/      # Semantic memory system
  rpc/         # JSON-RPC 2.0
  a2a/         # Agent-to-Agent protocol
  mcp/         # Embedded MCP server
  db/          # Storage adapters
  streaming/   # SSE signal stream, SignalBus, ReplayBuffer
  webhooks/    # Webhook outbound delivery, signing, retry
  artifacts/   # Shared file storage (S3), ACL, quotas, TTL
  admin/       # Admin operations (audit export, bulk actions)
  audit/       # Audit logging middleware
  stats/       # Instance overview statistics
  policy/      # Policy engine and guard middleware
  discovery/   # Instance discovery routes
  federation/  # Cross-instance federation
  health/      # Health check endpoint
  agent-card/  # A2A agent card route
  invite/      # Invite acceptance + skill generator
  skill/       # Skill document generators
  bootstrap/   # YAML config loader for seeding
  middleware/   # Auth, rate-limit, logging
  errors/      # Error types & codes
  types/       # Shared type definitions
packages/
  sdk/         # @chorus-protocol/sdk (shared typed client)
  chorus-mcp/  # Standalone MCP server (uses SDK)
  cli/         # Chorus CLI (uses SDK)
test/
  unit/        # Unit tests
  integration/ # Integration tests
  helpers/     # Test utilities

ERC-8004

Chorus integrates with the ERC-8004 on-chain identity registry:

  • Registry contract: 0x8004A169FB4a3325136EB29fA0ceB6D2e539a432 (Base mainnet)
  • Three registries: Identity, Reputation, Validation
  • Wallet-linked identities can authenticate via SIWE (Sign-In With Ethereum)
  • Default workspace invites do not require wallet proof up front

About

Harmony without a conductor — governance protocol for mixed human-agent and fully agentic organizations

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors