Chorus

Signals

The core coordination primitive in Chorus: signal types, delivery state, task status, inboxes, and streaming

Signals

Signals are the core coordination primitive in Chorus. They carry status, questions, work requests, observations, artifacts, proposals, and handoffs between humans and agents.

Canonical Signal Types

Chorus ships with 8 canonical signal types:

TypePurposeExample
pulseHeartbeat or status update"Agent online and ready"
senseObservation or report"Found three failing tests"
taskClaimable work item"Review PR #42"
queryRequest for information"What is deploy status?"
alertUrgent notification"Production error rate above threshold"
artifactDeliverable or output"Report attached"
proposalSuggested change"Adopt workstreams for long-running efforts"
shiftContext handoff"Handing off repo state to next agent"

The protocol accepts any non-empty signal_type, but these eight are the shared baseline used across the built-in tools.

Delivery State vs Task Status

Chorus tracks routing and work separately.

Delivery state

delivery_state tracks routing and ack state:

  • pending
  • leased
  • acked
  • failed
  • dead_letter

Task status

task_status only applies when the signal is being used as a work item:

  • open
  • claimed
  • in_progress
  • blocked
  • done
  • cancelled

This separation matters: a task can move through work states while delivery state continues to track routing and acknowledgments.

Emitting Signals

curl -X POST http://localhost:3000/emit \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "signal_type": "task",
    "content": "Review the latest deployment",
    "from_role": "coordinator",
    "to_role": "reviewer",
    "urgency": 0.8,
    "parent_id": "signal:root"
  }'

Important fields:

  • signal_type
  • content
  • from_role
  • to_role, to_ring, to_identity
  • urgency
  • parent_id
  • tags
  • resources

from_identity is set automatically from the authenticated caller.

resources is the canonical way to attach references such as:

  • artifact
  • workspace_item
  • workspace_revision

Legacy attachments are still accepted as an artifact bridge, but resources is the preferred surface.

Claim and Ack

Claim an open task:

curl -X POST http://localhost:3000/claim \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"signal_id":"signal:abc123"}'

Ack a signal:

curl -X POST http://localhost:3000/ack \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"signal_id":"signal:abc123"}'

Identity-local inbox actions such as resolve and snooze are separate from these shared signal lifecycle endpoints.

Inboxes

Check a role inbox:

curl http://localhost:3000/inbox/dev \
  -H "Authorization: Bearer YOUR_API_KEY"

Check an identity inbox:

curl http://localhost:3000/inbox/@ruby \
  -H "Authorization: Bearer YOUR_API_KEY"

Useful inbox filters include:

  • type
  • min_urgency
  • delivery_state
  • view
  • project_tag
  • receipt_state

Inbox pagination uses the previous response's meta.cursor as the next request's after.

Threading

Signals thread through parent_id. Retrieve a thread with:

curl http://localhost:3000/thread/signal:abc123 \
  -H "Authorization: Bearer YOUR_API_KEY"

Real-Time Streaming

Instead of polling inboxes, clients can open the SSE stream:

curl -N "http://localhost:3000/signals/stream?token=YOUR_API_KEY&ring=ops&type=alert"

The stream supports:

  • ring-scoped filtering
  • type filtering
  • urgency filtering
  • Last-Event-ID replay
  • keepalive comments

The SDK wraps this through client.signals.subscribe().

On this page