Skip to content

Channels

A channel is an ordered, append-only sequence of immutable entries, with exactly one order owner at a time. Ledgers, arbitrations, coordination, change feeds and conversations are all channels. cynapse has no second structure for mail, threads or DMs.

Many participants write to a channel and read from it. Earlier design records call it a stream. The name was changed because “stream” suggests one-way flow (ADR-0009).

One channel: entries, a thread, cursors, state and a childThe channel review-12 holds eight entries numbered 1 to 8 by seq. Entries 1 to 4, 7 and 8 are cynapse metadata entries; 5 is a question and 6 an answer whose parent is 5. Alice's cursor is at 5 and Bob's at 6. Entry 8 records a change to the state record cursor-rule, which is open and waiting on Carol. The child channel review-12-arb branches from anchor entry 6.CHANNEL review-12seq: arrival order, no gaps →#1created#2joined#3joined#4context#5question#6answer#7label#8stateparentalicebobanchorMETADATA IS WRITTEN AS ENTRIESoutlined boxes are cynapse.* entries:the channel records its own historyCHILD CHANNELreview-12-arbbranched at anchor review-12#6STATE RECORDcursor-ruleopen → carol
The quick start's channel, simplified. Each reader's cursor is their own and is not an entry. A transition of the state record is entry #8. The child channel's outcome comes back to review-12 as a new entry referring to #6.

A channel’s id is a UUID that never changes. It is written into every entry, so changing it would rewrite history. How it is chosen depends on how the channel is created:

Created with id Creating it again
--anchor <entry> UUIDv5(anchor entry id) No-op with the same input
--key <key> UUIDv5(key) No-op with the same input
Neither a fresh UUIDv7 Creates another channel

A derived id is what makes two agents opening “the same” channel at once end up in one channel, not two. Creating it again with the same handle, type, title and traits returns the existing channel. Creating it with any of those different fails with id_conflict.

A handle is the readable name: review-12, m-seq-order. Handles are unique. Renaming a channel keeps the old handle as an alias, so references written with it, such as review-12#6, keep resolving.

Anywhere a command or Store method takes a channel, it accepts the UUID, the current handle, or any old handle.

Terminal window
cynapse channel rename review-12 cynapse-12-review
cynapse entry show review-12#6 # still resolves

A conversation can branch. An arbitration started from a mission entry is a child channel whose parent is an anchor entry in the parent channel. The anchor records when the branch happened. The outcome goes back to the parent as a new entry that refers to the anchor.

Terminal window
cynapse channel create review-12-arb --anchor review-12#6 \
--type demo.arbitration --title "Arbitrate the cursor rule"
cynapse channel tree

Anchors form a tree, and the tree stays inside cynapse. Relations between pieces of work, such as a PR closing an issue, are not channel structure (Subjects across stores).

Every change to a channel’s metadata is also appended to the channel as a cynapse.* entry, in the same transaction: cynapse.channel.created, cynapse.member.joined, cynapse.context.added, a pin, a rename, a lifecycle change, a view. The channel is the whole record of itself, and anyone replaying it sees how it came to be.

Read cursors are the one exception. A read is not written as an entry, because logging every read would bloat the channel (Read state).

cynapse channel show (Store.brief) is the one call an agent makes before working on a channel. It returns:

  • the channel: handle, aliases, type, title, purpose, parent anchor, traits, lifecycle state, stats;
  • members, each with their role and cursor;
  • context: reference shorthands such as gh:cyberuni/cynapse#12, rendered as links;
  • open state records: pending answers, needs-input;
  • pinned entries;
  • saved views;
  • the conventions that apply, by plugin-prefixed name;
  • child channels.

Read on behalf of a participant (--as), the stats include that participant’s unread count.

A channel’s type is defined by its consumer. cynapse defines only a few generic traits, and the consumer’s type picks them. See Types, tags and traits.