Skip to content

Types

All of these are exported from cynapse as types (import type { Channel, Entry } from 'cynapse') and are what Store methods accept and return. Timestamps are ISO 8601 strings.

Anything that reads or writes: an agent, a person, a service. See Participants.

type ParticipantKind = 'agent' | 'human' | 'service'
type ParticipantStatus = 'live' | 'retired'
interface Participant {
id: string // UUIDv5 of `key` when registered
kind: ParticipantKind
name: string // not unique; resolveAddress matches it among live participants
status: ParticipantStatus // asserted by the registering runtime, never measured
key?: string // the registration key, such as cyberlegion:role/reviewer
registeredBy?: string // the service participant that registered it; itself, for a unit
}

A participant from before the registry has no key, no registeredBy and no address channel. It is live, and still resolves by name.

A named, ordered log of entries. See Channels.

interface Channel {
id: string // UUID: v7 when minted, v5 when derived from an anchor or key
handle: string // the current human-readable name
aliases: string[] // handles it used to have; they still resolve
type: string // namespaced, defined by the consumer, e.g. 'sdd.mission'
title: string
purpose?: string
parent?: Anchor // set on a child channel
members: Member[]
context: string[] // reference shorthands, e.g. 'gh:cyberuni/cynapse#12'
traits: ChannelTraits
state: string // the lifecycle state: 'active', 'paused', 'reconciled', ...
pinned: number[] // seqs of the pinned entries
conventions: string[] // names of the conventions that apply, plugin-prefixed
stats: ChannelStats
createdAt: string
}

Behaviour switches stored on the channel. See Types, tags and traits.

interface ChannelTraits {
membership: 'open' | 'fixed'
retention?: string
wake: boolean // advice to the runtime; cynapse never wakes anyone
defaultView?: string
}

A new channel gets { membership: 'open', wake: false } unless createChannel says otherwise.

interface Member {
participant: string
role: string
cursor: number // the last seq this member has read; 0 when nothing
}

The entry in a parent channel that a child channel branches from.

interface Anchor {
channelId: string
entryId: string
seq: number
}
interface ChannelStats {
entries: number
lastSeq: number
lastAt?: string
unread?: number // present only when read on behalf of a participant
}
interface ChannelTree {
channel: Channel
children: ChannelTree[]
}

An immutable record in a channel. See Entries.

interface Entry {
id: string // UUIDv7 minted by the writer; also the idempotency key
channelId: string
channel: string // the channel's current handle: `${channel}#${seq}` is the short reference
seq: number // arrival order within the channel
author: string
type: string
tags: string[] // the current set: write-time tags adjusted by cynapse.label entries
parent?: string
parentSeq?: number
root?: string
rootSeq?: number
refs: string[]
body: string // Markdown; '' when empty or read metadata-only
data?: Record<string, unknown> // typed payload; absent when read metadata-only
createdAt: string // when the writer minted it, from the UUIDv7
recordedAt: string // when it arrived in the channel
}

What is true on a channel right now: a pending answer, a needs-input, a lease. See State and lifecycle.

type StateStatus = 'open' | 'resolved'
interface StateRecord {
channelId: string
key: string // unique within the channel
kind: string
status: StateStatus
subject?: string // the participant it waits on or is held by
entryId?: string
value?: unknown
seq: number // the entry that logged the latest transition
updatedAt: string
}

A saved filter over a channel’s entries. See Views.

interface ViewFilter {
types?: string[] // exact types, or a prefix ending in '.*' ('sdd.*')
excludeTypes?: string[]
tags?: string[] // an entry matches when it carries any of these
excludeTags?: string[] // excluded when it carries any of these now
authors?: string[]
excludeAuthors?: string[]
}
interface View {
channelId: string
name: string
filter: ViewFilter
}

The result of brief: everything needed to start work on a channel in one call.

interface Briefing {
channel: Channel
states: StateRecord[] // open state records only
pinned: Entry[]
views: View[]
children: Pick<Channel, 'id' | 'handle' | 'type' | 'title' | 'state'>[]
}

What changes returns. Pass token to the next call.

interface Changes {
token: string // opaque, local to one store; not an order of entries
channels: ChannelChange[] // ordered by handle
}
interface ChannelChange {
channelId: string
handle: string
lastSeq: number
}
interface UnreadCount {
channelId: string
handle: string
count: number
}

CreateChannelInput, AppendInput, EntryMatch, ConditionalAppend, SetStateInput, ListChannelsQuery, EntryQuery, SearchQuery and StateQuery are documented with the methods that take them on the Store page.