Chorus

TypeScript SDK

Use @chorus-protocol/sdk for typed access to signals, memory, workflow, inbox, and workstreams

TypeScript SDK

The @chorus-protocol/sdk package provides one typed client for the Chorus runtime. It wraps both REST and JSON-RPC surfaces behind resource groups on a single ChorusClient.

Both the CLI and the MCP server use this SDK internally.

Installation

The SDK is not yet published to npm. Use it from the monorepo or from source.

Monorepo workspace:

{
  "dependencies": {
    "@chorus-protocol/sdk": "workspace:*"
  }
}

From source:

git clone https://github.com/protolabs42/chorus-protocol.git
cd chorus-protocol
bun install

Requirements: Bun, Node 18+, or any runtime with standard fetch.

Quick Start

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

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

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

await client.signals.emit({
  signal_type: "pulse",
  content: "SDK online",
  from_role: "dev",
  to_ring: "dev",
});

const resume = await client.workflow.resume({ cwd: process.cwd() });
const next = await client.workflow.next({ cwd: process.cwd() });

console.log(resume.summary);
console.log(next.recommendation);

Configuration

const client = new ChorusClient({
  url: "https://chorus.example.com",
  apiKey: "cho_abc123",
  timeout: 15000,
  retry: 2,
});
OptionTypeDefaultDescription
urlstringrequiredChorus instance URL
apiKeystringrequiredAPI key
timeoutnumber30000Request timeout in milliseconds
retrynumber0Retries for safe GET requests

Resource Groups

The client currently exposes 11 resource groups:

PropertyPurpose
client.signalsSignal emission, inbox queries, claim/ack, search, batch emit, and SSE subscribe
client.identityWhoami, invites, SIWE login, and auth requests
client.orgRoles, rings, and fills
client.memoryMemory CRUD, semantic query, recall, and graph operations
client.adminAPI keys, invites, peers, audit, policy, config, and cleanup
client.systemHealth, stats, and directory queries
client.artifactsImmutable artifact upload, list, download, share, and delete
client.workspaceMutable shared files and folders with immutable revisions
client.workflowComposite operator methods: resume(), next(), createHandoff()
client.inboxPer-identity receipt actions: acknowledge(), resolve(), snooze(), unsnooze()
client.workstreamsDurable effort containers and resource links

Common Patterns

Inbox triage with project context

const inbox = await client.signals.inbox("@ruby", {
  view: "now",
  project_tag: "chorus-protocol",
  limit: 10,
});

Resume and next-action flow

const resume = await client.workflow.resume({
  cwd: process.cwd(),
  workstream_slug: "docs-refresh",
});

const next = await client.workflow.next({
  cwd: process.cwd(),
  workstream_slug: "docs-refresh",
});

console.log(next.why);

Structured handoff

const handoff = await client.workflow.createHandoff({
  cwd: process.cwd(),
  to_ring: "dev",
  include_workspace_note: true,
});

console.log(handoff.shift_signal.id);
console.log(handoff.payload.suggested_next_step);

Workstreams

const workstream = await client.workstreams.create({
  namespace: "ring:dev",
  title: "Docs refresh",
  project_tag: "chorus-protocol",
});

await client.workstreams.link({
  id: workstream.id,
  resource_kind: "signal",
  resource_id: "signal:abc123",
  relationship: "context",
});

const context = await client.workstreams.context(workstream.id);
console.log(context.primary_signals.length);

For the full data model and link roles, see Workstreams.

Real-time signal streaming

const sub = client.signals.subscribe({
  ring: ["dev", "ops"],
  type: ["task", "alert"],
  min_urgency: 0.5,
});

for await (const signal of sub) {
  console.log(`[${signal.signal_type}] ${signal.content}`);
}

Notes

  • The SDK chooses REST or JSON-RPC per method. You normally do not need to care which one backs a given call.
  • The default invite flow is wallet-free. Wallet-linked identity can be attached later through POST /auth/attach-wallet.
  • retry is intentionally conservative and applies to safe reads, not writes.

For more examples, see the local package README in packages/sdk/README.md in the main repository.

On this page