CCCC Collaboration Standard (CCCS) v1
Status: Draft (proposed for CCCC v0.4.x ecosystem)
This document defines CCCS v1, a small, transport-agnostic standard for multi-agent collaboration built around an append-only event ledger. It is designed to be stable, extensible, and implementable by:
- CCCC itself (daemon + web UI + MCP/IM bridges)
- Client SDKs (TypeScript/Python/Go/etc.)
- External tools and integrations (CI, IM bots, IDE plugins, automation)
CCCS v1 deliberately does not standardize workflows, model providers, or prompting. It standardizes the collaboration substrate: event envelopes, routing semantics, attention/ack, system notifications, and cross-group provenance.
0. Conformance Language
The key words MUST, MUST NOT, SHOULD, SHOULD NOT, and MAY in this document are to be interpreted as described in RFC 2119.
1. Goals and Non‑Goals
1.1 Goals
CCCS v1 MUST enable:
- Tool/code ⇄ agent collaboration: tools can send, observe, and act on the same collaboration stream as agents.
- Append‑only truth: collaboration history is represented as immutable events appended to a ledger.
- Provenance: relayed/forwarded messages can be traced back to an original event (cross-group).
- Attention loops: important messages have an explicit acknowledgement mechanism independent of “read”.
- Forward compatibility: unknown event kinds and unknown fields do not break clients.
1.2 Non‑Goals
CCCS v1 does NOT standardize:
- Any specific workflow engine, DAG, or no-code builder.
- Any model/provider API (OpenAI/Claude/etc.) or prompt format.
- Any single transport (Unix socket, HTTP, SSE, WS, gRPC). CCCS v1 is transport-agnostic.
- Multi-tenant auth schemes (but it reserves fields and rules for provenance/permissions).
2. Terminology
- Group: A collaboration namespace (working group).
- Scope: A project root URL attached to a group; each event is attributed to a
scope_key. - Actor: A named agent identity within a group (e.g.,
foreman,peer-1). - Principal: Any entity that can write events (
user, anactor_id,system, orsvc:<name>).- Service principals SHOULD use a stable namespace (RECOMMENDED:
svc:com.example.mybotwhen disambiguation is needed). - The
svc:cccc.prefix is RESERVED for CCCC ecosystem services.
- Service principals SHOULD use a stable namespace (RECOMMENDED:
- Ledger: An append-only sequence of events for a group.
- Client: Any process/UI/bot that reads or writes events via a daemon.
- Daemon: A single-writer authority that appends events and enforces permissions.
3. Core Object Model
3.1 Group
Each event belongs to exactly one group, identified by group_id (string).
3.2 Scope
Each group MAY have one or more scopes. Each event MUST include a scope_key:
scope_keyMAY be""(unknown / global / not tied to a scope).scope_keyis a stable identifier for a scope assigned by the daemon.- Clients MAY use
scope_keyfor equality and filtering, but MUST treat it as an opaque string and MUST NOT parse or interpret its value.
3.3 Actor
Actors are identities within a group. CCCS v1 standardizes only:
actor_id: stable string identifierrole:"foreman"or"peer"(optional; the collaboration semantics do not require a role)
4. Event Envelope (Normative)
All events MUST use the envelope below. Field semantics are fixed.
interface CCCSEventV1 {
v: 1
id: string // MUST be unique within the group ledger; SHOULD be globally unique (ULID/UUIDv7/UUID4)
ts: string // RFC3339 UTC timestamp assigned by the daemon at append time
seq?: number // OPTIONAL: monotonic sequence number assigned by the daemon (useful for streaming/cursors)
kind: string // e.g. "chat.message"
group_id: string
scope_key: string // "" allowed
by: string // principal id ("user", "system", actor_id, or "svc:<name>") set by the daemon
data: Record<string, unknown>
}4.1 Forward Compatibility Rules
- Clients MUST ignore unknown
kindvalues (but MAY display them as raw/unknown events). - Clients MUST ignore unknown fields inside
data. - Clients MUST preserve the event envelope when relaying/forwarding (see §9).
4.2 Versioning
vis the envelope version. CCCS v1 requiresv: 1.- Implementations MAY add a
data.vfield for kind-specific versioning, but MUST NOT change envelope semantics without bumpingv.
4.3 Ordering and Timestamps
- The authoritative ordering of events is the ledger append order.
tsMUST be assigned by the daemon at append time. Clients MUST NOT rely on client-local timestamps for ordering.- Implementations MAY record a client-provided timestamp (RECOMMENDED:
data.client_ts) for diagnostics or UI display, but it MUST NOT affect ordering.
4.4 Event Kind Namespaces
Standard kinds use the chat.*, system.*, group.*, actor.*, context.*, and assistant.* namespaces.
Extensions SHOULD use one of:
x.<vendor>.*(recommended for private/vendor-specific kinds)vendor.<name>.*(alternative vendor namespace)
Clients MUST treat unknown kinds as opaque and ignore them unless explicitly supported.
5. Recipient Routing Semantics
5.1 Recipient Tokens
Chat message routing uses to: string[] with these token types:
Actor IDs
- Example:
"peer-1","claude-1"
Selectors (MUST start with @)
@all: all actors in the group@peers: all peer actors@foreman: foreman actor(s)@user: the human user (UI recipient)
Compatibility
- Implementations MAY accept the literal token
"user"as equivalent to@user.
Multi-user note
- CCCS v1 assumes a single human principal per group, identified as
user. - Multi-user semantics (multiple distinct human principals) are out of scope for v1. Implementations MAY extend this outside of CCCS v1 (e.g.,
usr:<id>principals and selectors), but clients MUST remain forward-compatible.
5.2 Empty to
If to is absent or an empty list, the message is a broadcast. For compatibility with CCCC v0.4.x semantics, broadcast SHOULD be treated as equivalent to @all.
5.3 Permission and Visibility
CCCS does not mandate a single permission model, but a conforming daemon MUST ensure:
- The daemon MUST set
event.byto the principal identity it ascribes to the event.- If the transport provides authentication,
event.byMUST be derived from the authenticated principal and clients MUST NOT be able to chooseevent.byarbitrarily. - If the transport does not provide authentication (local-trust IPC), a daemon MAY accept a client-provided principal hint (e.g., an RPC arg like
by) as the effective principal. Such deployments MUST document thatbyis not a security boundary.
- If the transport provides authentication,
- A principal cannot acknowledge (
chat.ack) on behalf of another recipient.
6. Chat Events
6.1 chat.message
chat.message represents an IM-style message.
data: {
text: string
format?: "plain" | "markdown" // default "plain"
priority?: "normal" | "attention" // default "normal"
to?: string[] // recipient tokens (see §5)
reply_to?: string | null // replied-to event_id
quote_text?: string | null // display hint
// Cross-group provenance (relay/forward)
src_group_id?: string | null
src_event_id?: string | null
// Cross-group destination metadata (optional send record)
dst_group_id?: string | null
dst_to?: string[] | null
// Attachments and references (see §8)
attachments?: AttachmentRefV1[]
refs?: ReferenceV1[]
// Reserved for future threading
thread?: string
// Optional idempotency key (client-generated)
client_id?: string | null
}Rules
textMUST be present (it may be empty if and only if attachments convey the message).priority="attention"MUST trigger the attention/ack rules in §6.2.- If either
src_group_idorsrc_event_idis present, both MUST be present. - The
threadfield is RESERVED in v1; its semantics are undefined. Implementations MUST NOT rely onthreadfor v1 behavior. Clients MUST ignore it. - If
client_idis present, a daemon SHOULD provide best-effort idempotency for(group_id, by, client_id)within a bounded time window (RECOMMENDED: 5 minutes).- Duplicate submissions SHOULD return success with the original event reference, not a hard error.
6.2 chat.ack (Attention Acknowledgement)
chat.ack is the only completion signal for attention messages.
data: {
actor_id: string // the acknowledging recipient ("user" or an actor_id)
event_id: string // the acknowledged chat.message event_id
}Rules
- A daemon MUST enforce self-only ACK:
event.byMUST equaldata.actor_id. chat.ackMUST be idempotent per(group_id, actor_id, event_id); repeated ACK MUST NOT create repeated side effects.chat.ackMUST reference a validchat.messagewhosepriorityis"attention".- A daemon MUST reject ACK attempts for non-attention messages.
- The error
codeSHOULD beinvalid_request(or an implementation-specific equivalent such asnot_an_attention_message).
- The error
- A recipient MUST NOT be required to ACK a message that was not addressed to them.
chat.ackMUST be independent from read cursors. Marking read MUST NOT automatically clear the need for ACK.- Implementations MAY provide a convenience gesture where a recipient’s explicit “mark read” action on an attention message results in emitting
chat.ack, but thechat.ackevent MUST still exist as a distinct record.
- Implementations MAY provide a convenience gesture where a recipient’s explicit “mark read” action on an attention message results in emitting
6.3 chat.read (Read Cursor / Watermark)
chat.read records a recipient’s read watermark up to a given event.
data: {
actor_id: string // the reader/recipient ("user" or an actor_id)
event_id: string // the last read event_id (inclusive)
}Rules
- Read is a cursor, not an acknowledgement.
event_idMUST reference an event that exists in the group ledger.- For the Core Collaboration Profile,
event_idSHOULD reference an addressable event (RECOMMENDED:chat.messageorsystem.notify) and the daemon SHOULD reject watermarks for events that are not addressed toactor_id. - A daemon MUST enforce authorization: only the recipient (
event.by == data.actor_id) or an authorized privileged principal (e.g.,user) MAY emitchat.readfordata.actor_id. - “Inclusive” means the referenced
event_iditself is considered read. - If a client cannot efficiently determine ordering, it SHOULD treat
event_idas an opaque watermark maintained by the daemon.
6.4 chat.reaction (Optional)
data: {
event_id: string
actor_id: string
emoji: string
}7. System Notification Events
System notifications are separated from chat to avoid polluting conversations.
7.1 system.notify
data: {
kind: "nudge" | "keepalive" | "help_nudge" | "actor_idle" | "silence_check" | "automation" | "status_change" | "error" | "info" | string
priority?: "low" | "normal" | "high" | "urgent" // default "normal"
title?: string
message?: string
target_actor_id?: string | null // null = broadcast
context?: Record<string, unknown> // implementation-defined
requires_ack?: boolean // default false
related_event_id?: string | null // optional correlation
}Rules
- Clients MUST ignore unknown
data.kindvalues withinsystem.notify(open enum). - Implementations MAY enforce an allowlist of
data.kindvalues, but should not assume clients understand new kinds.
7.2 system.notify_ack
data: {
notify_event_id: string
actor_id: string
}Rules
system.notify_ackMUST be self-only:event.byMUST equaldata.actor_id.- A daemon MUST NOT allow a principal to ack on behalf of another recipient.
8. Attachments and References
8.1 AttachmentRefV1
type AttachmentRefV1 = {
kind?: "text" | "image" | "file" // default "file"
path: string // group-scoped path (implementation-defined)
title?: string
mime_type?: string
bytes?: number
sha256?: string
// extra fields MAY exist; clients MUST ignore unknown fields
}8.2 ReferenceV1
type ReferenceV1 =
| {
kind?: "file" | "url" | "commit" | "text" // default "url"
url?: string
path?: string
title?: string
sha?: string
bytes?: number
// extra fields MAY exist; clients MUST ignore unknown fields
}
| {
kind: "presentation_ref"
v?: 1
slot_id: string
label?: string
locator_label?: string
title?: string
card_type?: string
status?: "open" | "needs_user" | "resolved"
href?: string
excerpt?: string
locator?: Record<string, unknown>
snapshot?: {
path: string
mime_type?: string
bytes?: number
sha256?: string
width?: number
height?: number
captured_at?: string
source?: "browser_surface" | "pdf_viewer" | "viewer_dom" | string
}
// extra fields MAY exist; clients MUST ignore unknown fields
}
| {
kind: "task_ref"
task_id: string
title?: string
status?: "planned" | "active" | "done" | "archived" | string
// extra fields MAY exist; clients MUST ignore unknown fields
}Rules
- Attachments SHOULD include content hashes where possible (
sha256) to enable reproducibility/auditing. pathMUST be stable and retrievable within the group’s storage scope.kind="presentation_ref"is a structured evidence anchor into a group Presentation slot.slot_idMUST identify the target slot within the group presentation surface.locatorSHOULD carry best-effort position hints for the current view (for example page, heading, row, or scroll state).snapshot, when present, SHOULD be treated as a best-effort visual anchor for the quoted view.snapshot.pathMUST be a stable group-scoped blob path.- Implementations SHOULD use
locatorfor precise recovery when possible, andsnapshotas a visual fallback when precise recovery is unavailable.
status, when present, is advisory metadata for the referenced discussion state; ledger-derived obligation status remains authoritative.
kind="task_ref"links a chat message to a durable shared task.task_idMUST identify a task in the same working group unless explicitly documented otherwise by a relay/bridge.titleandstatus, when present, are UI hints; the task store remains authoritative.
8.3 Attachment Resolution (Non‑Normative Guidance)
CCCS v1 does not mandate a transport, but implementations SHOULD provide a way to resolve AttachmentRefV1.path to bytes, for example:
- An HTTP endpoint (e.g.,
GET /groups/{group_id}/blobs/{path}), or - An RPC/IPC operation that returns attachment metadata and streams bytes.
9. Cross‑Group Relay / Forward (Provenance)
CCCS v1 standardizes cross-group provenance via src_group_id/src_event_id on the destination message.
9.1 Relay Semantics
To relay a message from group A into group B:
- In group B, append a
chat.messagewhosedata.src_group_idanddata.src_event_idreference the original event in group A. - The relayed message MUST either:
- (a) include the original text verbatim, or
- (b) clearly indicate truncation/summarization in the message (e.g., prefix with
[Summarized]) and includesrc_group_id/src_event_idfor full content retrieval.
Rules
- If either
src_group_idorsrc_event_idis set, both MUST be set. - UIs SHOULD provide “Open source message” (jump-to) affordances.
- If the source is unavailable due to permissions or retention, clients MUST show a clear “source unavailable” state (not silent failure).
9.2 Optional Send Record
Implementations MAY also append an “outbound send record” in the source group (for auditability) by writing a local chat.message with:
dst_group_iddst_to
This record is OPTIONAL and MUST NOT be required for the destination’s provenance correctness.
10. Event Stream Subscription (Transport‑Agnostic)
CCCS v1 defines an abstract “event stream” interface:
- Input:
(group_id, since_cursor?, filters?, follow?) - Output: an ordered stream of
CCCSEventV1
10.1 Cursor
CCCS does not mandate a single cursor type. A daemon SHOULD support at least one:
since_ts(timestamp cursor), orsince_event_id(event-id cursor), orsince_seq(monotonic sequence number)
Clients MUST treat cursors as opaque and MUST NOT infer ordering from id. If since_seq is supported, it SHOULD correspond to the daemon-assigned event.seq field (when present).
10.2 Filters
Implementations SHOULD support filtering by:
kinds[](e.g., onlychat.message,system.notify)limit(for bounded replays)
10.3 Capability Discovery (Non‑Normative Guidance)
Different implementations may support different cursor types and stream filters. Implementations SHOULD expose capability discovery via their chosen transport (e.g., an info/capabilities endpoint or an IPC operation) so SDKs can adapt automatically.
11. Error Model (Recommended)
To make SDKs interoperable, daemons SHOULD expose errors as:
{
code: string
message: string
details?: Record<string, unknown>
}Recommended stable code values:
invalid_requestpermission_deniedgroup_not_foundactor_not_foundevent_not_foundunknown_opdaemon_unavailable
12. Security Considerations (Minimal v1)
A conforming daemon MUST:
- Enforce single-writer semantics for the ledger.
- Set
event.byto a principal identity consistent with the deployment’s trust model (authenticated vs. local-trust IPC) and document the security properties. - Enforce self-only ack rules for
chat.ackandsystem.notify_ack.
13. Minimal Profiles (Guidance)
To reduce implementation burden, CCCS v1 MAY be implemented in profiles:
13.1 Core Collaboration Profile (recommended minimum)
chat.message,chat.ack,chat.readsystem.notify,system.notify_ack(optional ack)- Recipient token semantics (§5)
13.2 Management Profile (optional)
group.*,actor.*
13.3 Context Profile (optional)
context.sync(implementation-defined ops)
14. Examples
The following examples use placeholder IDs for brevity. Conformance test vectors with complete values may be provided separately.
14.1 Attention Message + Ack
{
"v": 1,
"id": "01HZY2... (opaque)",
"ts": "2026-01-13T10:00:00Z",
"kind": "chat.message",
"group_id": "g_123",
"scope_key": "s_abc",
"by": "user",
"data": {
"text": "Please review the release checklist today.",
"format": "plain",
"priority": "attention",
"to": ["@foreman"]
}
}Ack:
{
"v": 1,
"id": "01HZY3... (opaque)",
"ts": "2026-01-13T10:01:00Z",
"kind": "chat.ack",
"group_id": "g_123",
"scope_key": "",
"by": "foreman",
"data": {
"actor_id": "foreman",
"event_id": "01HZY2... (opaque)"
}
}14.2 Cross‑Group Relay
Destination group message:
{
"v": 1,
"id": "01HZY4... (opaque)",
"ts": "2026-01-13T10:02:00Z",
"kind": "chat.message",
"group_id": "g_dst",
"scope_key": "",
"by": "svc:relay",
"data": {
"text": "Relayed: please review the release checklist today.",
"priority": "attention",
"to": ["@all"],
"src_group_id": "g_src",
"src_event_id": "01HZY2... (opaque)"
}
}