Envelope specification
The envelope is the single shared contract of Cosmonapse. Every Signal crossing a Synapse is a valid envelope — regardless of which Neuron produced it, which Synapse carries it, or which Dendrite is on the other side.
{
"v": "1",
"id": "evt_01JVBCDEF1234567890ABCDEF",
"trace_id": "trc_01JVBCDEF0000000000000000",
"parent_id": "evt_01JVBCDEF0000000000000001",
"type": "THOUGHT_DELTA",
"neuron": "claude-debug",
"ts": "2026-05-16T14:22:01.391Z",
"payload": {
"delta": "reading the traceback...",
"seq": 1
},
"meta": {
"model": "claude-sonnet-4-6",
"tokens": { "out": 12 }
}
}Three layers. Non-overlapping responsibilities.
The envelope flows top to bottom; agent output flows bottom to top. Each layer has exactly one job.
role: "orchestrator" (full dispatch / emit surface) or "worker" (hosts Axons and bids in capability routing, but cannot emit TASK or any cognition signal). The role guard sits on emit() itself — every cognition emitter funnels through it. Every orchestrator-role Dendrite can drive workflows; there is no separate Cortex class.All identifiers are prefixed ULIDs: a short lowercase type prefix, an underscore, and a 26-character canonical ULID. Globally unique without coordination; lexicographically sortable by creation time.
| Prefix | Used for | Example |
|---|---|---|
| evt_ | Any envelope id | evt_01JVBCDEF1234567890ABCDEF |
| trc_ | Any trace_id | trc_01JVBCDEF0000000000000000 |
| call_ | TOOL_CALL / TOOL_RESULT pairs | call_01JVBCDEF0000000000000002 |
| prop_ | CONSENSUS proposal IDs | prop_01JVXAMPLE0000000000000001 |
Two TASK subjects. Two delivery modes.
The protocol exposes two transport-level routing modes for TASKs. The mode is chosen at dispatch time; both ride the same envelope.
| Mode | Subject | Delivery | Selected when |
|---|---|---|---|
| Addressed | cosmonapse.<ns>.TASK | Broadcast (every Dendrite subscribes, only the named host acts) | TASK carries a neuron field |
| Capability-routed | cosmonapse.<ns>.TASK.routed | Queue group caps:<sorted-aggregate> — broker delivers exactly once per matching cap profile | TASK omits neuron and sets payload.capabilities |
The split exists because a single queue group on a shared subject would break addressed routing (the broker could deliver an addressed TASK to a Dendrite that doesn’t host the target Axon, which would silently drop it). With two subjects, addressed broadcast and capability load-balancing coexist cleanly. Heterogeneous deployments — Dendrites with different but overlapping cap profiles — still get at-least-once across profiles; for atomic claim use TASK_OFFER / BID / TASK_AWARDED instead.
The mandatory types. Any compliant implementation must handle all of them.
{ intent, input, context_ref?, deadline?, budget_usd? }{ output }{ result }{ kind, message, retriable? }required_caps, bid_window_ms.{ offer_id, confidence, cost_estimate_usd?, eta_ms? }{ offer_id }Produced by the Dendrite, not the Axon or Neuron. Optional — a Dendrite that simply forwards TASK → FINAL with no intermediate events is fully compliant.
meta.seq must be monotonic per (trace_id, agent). Payload: { delta, final? }{ steps, revision }{ tool, args, call_id }{ call_id, ok, value?, error? }{ reason, hints? }{ proposal_id, outcome, votes, threshold? }{ target_event_id, severity, note }{ questions, context? }Emitted by the Dendrite on behalf of each attached Axon. The Axon owns the metadata (neuron_id, capabilities, version); the Dendrite publishes these Signals onto the Synapse.
{ capabilities, cost_hint?, max_concurrent?, max_latency_ms? }{ reason }{ status, load?, in_flight? }The Engram surface is request/reply: an Axon asks for context with RECALL or commits a write with IMPRINT, and the bound backend replies with RECALLED or IMPRINTED. Identifiers use the eng_ ULID prefix. The Neuron never writes to the memory fabric directly — EngramClient is the in-Neuron API.
{ engram_id, query, mode?, k?, deadline_ms? } where mode is first | merge | all.{ hits, partial? } where each Hit carries { id, content, score?, tags? }.{ engram_id, op, entry, deadline_ms? } where op is add | append | merge | upsert | delete.{ id, ok, error? }.Doppler is a non-competing, read-only consumer of the Synapse. It does not define its own Signal types — it taps every Signal emitted by Core and Engram. Pulse streams the raw telemetry; Prism renders it as dashboards and trace graphs. cosmo doppler in the CLI is the baseline implementation.
These signal types are reserved for future Cosmonapse products. They are not part of the current envelope spec but are documented here for planning purposes.
IDENTITY_ASSERT (Genome — neuron identity proof), KEY_ROTATE (Myelin — in-band key refresh), and THREAT_SIGNAL (Reflex/AntiBody — anomaly broadcast). These will extend the envelope spec in a future revision and remain backwards-compatible with v1 consumers.An envelope is valid if and only if…
- It is well-formed JSON.
vis present and equals"1".idis present and matches^evt_[0-9A-Z]{26}$.trace_idis present and matches^trc_[0-9A-Z]{26}$.parent_id, if present, matches the event pattern.typeis present and is one of the catalogued values.tsis a valid RFC 3339 UTC timestamp ending inZ.payloadandmeta, if present, are JSON objects.- Required payload fields for the given type are present and correctly typed.
cosmo validate checks these rules against a stream of envelopes. Validity is purely structural — Cosmonapse does not enforce sequencing or lifecycle rules. What constitutes a completed task, what happens after an error, and how envelopes flow over time are decisions you make in your Dendrite.