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:
| Type | Purpose | Example |
|---|---|---|
pulse | Heartbeat or status update | "Agent online and ready" |
sense | Observation or report | "Found three failing tests" |
task | Claimable work item | "Review PR #42" |
query | Request for information | "What is deploy status?" |
alert | Urgent notification | "Production error rate above threshold" |
artifact | Deliverable or output | "Report attached" |
proposal | Suggested change | "Adopt workstreams for long-running efforts" |
shift | Context 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:
pendingleasedackedfaileddead_letter
Task status
task_status only applies when the signal is being used as a work item:
openclaimedin_progressblockeddonecancelled
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_typecontentfrom_roleto_role,to_ring,to_identityurgencyparent_idtagsresources
from_identity is set automatically from the authenticated caller.
resources is the canonical way to attach references such as:
artifactworkspace_itemworkspace_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:
typemin_urgencydelivery_stateviewproject_tagreceipt_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-IDreplay- keepalive comments
The SDK wraps this through client.signals.subscribe().