Gate / documentation / event log

Event log

Commands, evidence, runs, and issue changes all land in one append-only event stream. The stream is the source of truth for the UI and the MCP interface alike.

Events are append-only and ordered by (project_id, sequence). Every command appends its event and updates the read model in the same transaction, so the stream is a complete, gap-free record of what happened.

Record structure

Each event records:

Field Meaning
id UUID identifying the event
project_id, sequence Per-project ordering; sequence increments by one per project
type Event type (see families below)
schema_version Payload schema version, defaults to 1
actor { type, id } Who caused it — human, agent, or mcp
correlation_id Groups events from one logical operation
causation_id The event that directly triggered this one, when any
payload_json Type-specific payload
created_at Timestamp

Replay and live delivery

The UI subscribes over WebSocket at /ws?projectId=<id>&after=<sequence>. On connect the server sends a hello (protocol version 1), then replays up to 1,000 missed durable events in sequence order, then streams new durable events as they commit, ephemeral provider activity messages, and a heartbeat every 15 seconds. A client that drops and reconnects with its last delivered sequence gets exactly the events it missed — already-delivered sequences are skipped, so there are no duplicates.

Event families

Family Current types
project.* project.created, project.policy.updated, project.provider.updated, project.stage.updated, project.instructions.updated
timeline.* timeline.draft.proposed, timeline.replaced, timeline.node.transitioned, timeline.node.locked, timeline.node.unlocked
agent.run.* agent.run.started, agent.run.interrupted, agent.run.review, agent.run.failed, agent.run.cancelled
gate.* gate.evidence.submitted, gate.approval.decided
feature.* feature.created, feature.status.updated
planning.* planning.proposed, planning.accepted, planning.regrounded
milestone.* milestone.expansion.proposed
plan.* plan.staleness.warned
inbox.* inbox.dismissed
memory.* memory.index.started, memory.index.completed, memory.index.failed
context.* context.compiled
remote.* remote.prs.observed, remote.issues.observed
issue.* issue.created, issue.status.updated
note.* note.created
git.* git.history.observed

Event payloads carry identifiers and counts rather than source excerpts — for example, a planning.proposed or context.compiled event names its capsule and request id instead of embedding content.

Consumer guidance

Consumers must ignore unknown event types and use schema_version when adding incompatible payloads — the stream grows without breaking older readers.