Writing Records in Depth
Every write option: JSON write, batch write, TTL, and the internal write path.
What you'll learn
- ✓Basic JSON write with POST /v1/agents/:id/write
- ✓Write with ttl_ms — automatic expiry via _expires_at_ms
- ✓Batch write with POST /v1/agents/:id/write/batch
- ✓GroupCommitter — one fsync per batch
- ✓Write path: JSON → MsgPack → AES-GCM → BLAKE3 → Ed25519 → WAL → segment
Write a 'user upgrade' event (user_id, from_plan, to_plan). Then batch-write 5 page_view events.
Interactive Walkthrough
What you'll learn
Every write option: JSON write, raw MessagePack write, batch write, TTL, and what the write path looks like internally.
Basic JSON write
curl -s -X POST http://localhost:7475/v1/agents/users/write \
-H "Content-Type: application/json" \
-H "Authorization: Bearer spx_root_YOUR_ROOT_KEY" \
-d '{
"payload": {
"type": "user_signup",
"user_id": "usr_001",
"email": "bob@example.com",
"plan": "starter",
"source": "landing_page"
}
}' | python3 -m json.toolWrite with a TTL
Records expire after ttl_ms milliseconds. An internal sweeper tombstones them automatically.
# This record expires in 1 hour (3,600,000 ms)
curl -s -X POST http://localhost:7475/v1/agents/sessions/write \
-H "Content-Type: application/json" \
-H "Authorization: Bearer spx_root_YOUR_ROOT_KEY" \
-d '{
"payload": {"session_token": "tok_xyz", "user_id": "usr_001"},
"ttl_ms": 3600000
}' | python3 -m json.toolThe engine injects _expires_at_ms into the payload before storing. The TTL sweeper runs every 60 seconds and tombstones expired records.
Batch write
curl -s -X POST http://localhost:7475/v1/agents/events/write/batch \
-H "Content-Type: application/json" \
-H "Authorization: Bearer spx_root_YOUR_ROOT_KEY" \
-d '{
"records": [
{"payload": {"event": "page_view", "page": "/pricing", "user": "usr_001"}},
{"payload": {"event": "button_click", "button": "start_trial", "user": "usr_001"}},
{"payload": {"event": "form_submit", "form": "trial_signup", "user": "usr_001"}}
]
}' | python3 -m json.toolBatch writes are coalesced by the GroupCommitter — all records in one batch share a single fsync, giving much higher throughput than individual writes.
Write response fields
| Field | Meaning |
|---|---|
content_hash | Permanent address of this record |
parent_hash | The record this chains from |
sequence | 1-based integer position in the strand |
ts_hlc | HLC timestamp of this record |
The write path (internals)
- JSON payload → MessagePack encode
- AES-256-GCM encrypt (key derived from
SAPIX_MASTER_SEED+ agent_id via HKDF) - Compute
content_hash = BLAKE3(parent_hash ‖ ts_hlc ‖ flags ‖ encrypted_payload) - Sign
content_hashwith agent's Ed25519 key - Append to WAL (plaintext for crash recovery)
- GroupCommitter fsync
- Move to encrypted segment file
Challenge
Write a "user upgrade" event with these fields: user_id, from_plan, to_plan, upgraded_at. Then write a batch of 5 page_view events for that user.
---