Event
Smallest unit of history. Immutable JSON describing a turn, tool call, or observation with actors, payload, parents, and tags.
Spec / docs
This draft defines the event envelope, trail metadata, Merkle-head sync, and read APIs that make Tongbuku 同步库 the trusted trails engine for EarthCloud, Buoychong, ChatCard, and future Glyphd Labs products.
Tongbuku 同步库 keeps append-only trails of events that teams can replay, analyze, and reuse as process templates. Trails sit beneath ChatCard identity and EarthCloud meaning, and this document spells out how events, trails, and projections stay in step.
Core concepts
Smallest unit of history. Immutable JSON describing a turn, tool call, or observation with actors, payload, parents, and tags.
Append-only sequence of events for a document, room, or workflow. Trails can branch offline and reconcile via Merkle heads.
Derived representation of one or more trails—summaries, indexes, or templates that stay ready for models and operators.
Hash frontier representing what a client knows. Sync exchanges heads to request only missing events.
1 · Event envelope
Events are append-only objects with a stable identifier, parent references, actor metadata, payload, and tags. They are the atomic unit of sync, replay, and audit.
user_id, app_id, and optional card_id for ChatCard alignment.{
"event_id": "evt_01JK9WQ3",
"trail_id": "trail_conversation_abc",
"kind": "turn", // turn | tool | system | custom
"timestamp": "2025-11-08T20:00:00Z",
"parents": ["evt_01JK9WQ2"],
"actors": {
"user_id": "user_en",
"app_id": "chat_surface",
"card_id": "chatcard_room_alpha"
},
"payload": {
"role": "user",
"text": "Kickoff sync notes?",
"lang": ["en", "zh-CN"]
},
"tags": ["room:alpha", "plan:pro"],
"metadata": {
"glyphir_id": "gph_01HX...",
"approx_tokens": 128
}
}2 · Trail
Trails collect metadata about a conversation, workflow, session, or document. They reference one or more Merkle heads that describe how far a client has synced.
The heads array can hold multiple branches for offline edits. Many apps rely on a single head named head_main.
{
"trail_id": "trail_conversation_abc",
"kind": "conversation", // conversation | session | workflow | document | custom
"created_at": "2025-11-08T20:00:00Z",
"updated_at": "2025-11-08T20:15:00Z",
"tags": ["room:abc", "customer:1234", "plan:pro"],
"heads": [
{
"head_id": "head_main",
"merkle_hash": "mkh_def456...",
"last_event_id": "evt_01JK...",
"branch": "main"
}
],
"metadata": {
"title": "Project kickoff chat",
"summary": "Initial planning discussion about the new release."
}
}3 · View / projection
Snapshots are read-optimized documents derived from trails. They may be per-user, per-trail, or cross-trail indexes that your models consume directly.
scope defines the view type (e.g., conversation_summary or agent_turn_pairs).based_on_heads to indicate which frontier the view reflects.{
"snapshot_id": "snap_01SNAP...",
"trail_id": "trail_conversation_abc",
"scope": "conversation_summary", // type of view
"created_at": "2025-11-08T20:16:00Z",
"based_on_heads": ["mkh_def456..."],
"data": {
"summary": "The team agreed to meet tomorrow at 3pm Beijing time...",
"participants": ["user_en", "user_zh"],
"languages": ["en", "zh-CN"],
"turns": 14
},
"meta": {
"generated_by": "summary_agent_v1",
"model_id": "earthcloud_model_vX",
"approx_tokens": 256
}
}4 · Merkle head
A Merkle head captures the frontier a client has observed. Servers compare hashes to calculate missing events and return only what is new.
Implementations may compress known_event_ids. The contract is simply “given this head, return what I need.”
{
"trail_id": "trail_conversation_abc",
"merkle_hash": "mkh_def456...",
"known_event_ids": ["evt_01JH...", "evt_01JG...", "evt_01JK..."],
"client_id": "device_iphone_13",
"timestamp": "2025-11-08T20:15:30Z"
}Endpoints
REST-ish endpoints cover append, metadata, sync, and view reads. You can expose gRPC or GraphQL equivalents as long as the same envelopes are honored.
Append one or more events to a trail. Supports dedupe and optional return of the trail body.
POST /v1/events/append
Content-Type: application/json
Authorization: Bearer <token>
{
"events": [
{ ... tb_event ... },
{ ... }
],
"options": {
"dedupe_on": ["event_id"],
"return_trail": false
}
}{
"success": true,
"inserted": ["evt_01JK...", "evt_01JL..."],
"ignored": [],
"trail": { ... tb_trail ... } // optional, if return_trail = true
}Fetch metadata and, optionally, a window of events for a trail.
GET /v1/trails/trail_conversation_abc?limit=50&before=evt_01JK...
Sync events for one or more trails by sending Merkle heads and receiving the missing events.
POST /v1/sync
Content-Type: application/json
{
"heads": [
{
"trail_id": "trail_conversation_abc",
"merkle_hash": "mkh_client_local..."
}
],
"limit": 256
}{
"trails": [
{
"trail_id": "trail_conversation_abc",
"events": [
{ ... tb_event ... },
{ ... }
],
"server_head": {
"merkle_hash": "mkh_server_latest...",
"last_event_id": "evt_01JK..."
}
}
]
}Fetch or trigger a view over a trail.
GET /v1/views/trail_conversation_abc?scope=conversation_summary
{
"snapshot": { ... tb_snapshot ... },
"status": "ready" // ready | computing | stale
}Optional endpoint to trigger or update materialized views for one or more trails.
Error model
Use OAuth-style fields for errors. Keep error codes machine-readable and descriptive enough for operators.
{
"error": "invalid_request",
"error_description": "Missing 'events' field in body."
}Authentication & authz
user_id, app_id, and optionally card_id for ChatCard-aware permissions.trail_id prefixes and tags.Spec status & evolution
Future revisions will formalize merge semantics, ship reference implementations (Postgres, KV, embedded), and expand view types for training/eval workloads. Reach out via info@tongbuku to contribute or request clarifications.