Skip to content

feat: pluggable storage backends (SQLite + remote control plane) - #32

Merged
tishachawla-jg merged 1 commit into
mainfrom
feat/storage-backends
Jul 29, 2026
Merged

feat: pluggable storage backends (SQLite + remote control plane)#32
tishachawla-jg merged 1 commit into
mainfrom
feat/storage-backends

Conversation

@tishachawla-jg

Copy link
Copy Markdown
Contributor

Recording wrote only to a local JSONL file. Deployed agents need durable and shared storage. This adds a Store protocol with three backends, keeping local JSONL as the zero-config default. Nothing downstream changes.

Backends

Backend Use Dependency
JsonlStore (the default EnvelopeStore) local dev, CI fixtures none
SqliteStore a single deployed instance (durable, queryable) stdlib sqlite3
RemoteStore many deployed agents to one shared control plane stdlib urllib

All satisfy the Store protocol, so chronicle.record(store=...) and session.store accept any of them.

Dev-simple selection

with chronicle.record("run-1", store="runs.jsonl"): ...              # local file (default)
with chronicle.record("run-1", store="sqlite:///runs.db"): ...       # deployed instance
with chronicle.record("run-1", store="https://chronicle.internal"): ...  # control plane

open_store(target) routes by the string; or pass a SqliteStore / RemoteStore instance.

Safety

RemoteStore never raises into the agent: a failed append is warned and dropped, reads return [] on failure. Recording can't take down production. SqliteStore serializes concurrent appends with a lock and allows cross-thread use (async requests share one store).

Control plane

examples/control_plane/server.py is a minimal reference service (stdlib http.server + SQLite) that RemoteStore talks to. TokenOps can point at the same host to co-locate its cost ledger with trace storage, which is the "Chronicle provides control-plane support to TokenOps" direction.

Tests

tests/test_stores.py: SQLite round-trip, open_store dispatch, recording into SQLite and via a sqlite:// URL, RemoteStore end-to-end against the reference server, and that a dead control plane never crashes the agent. Full suite green; ruff 0.15.22 clean. No em/en dashes.

Follow-up (not in this PR): Phase C, first-class OpenTelemetry spans per boundary.

Recording wrote only to a local JSONL file. Deployed agents need durable and
shared storage, so introduce a Store protocol with three backends. The default
stays local JSONL (zero config); nothing downstream changes.

- Store protocol in chronicle/envelope/backends.py. EnvelopeStore (JSONL) already
  satisfies it; exposed as JsonlStore too.
- SqliteStore: durable, queryable, zero dependency (stdlib sqlite3). Thread-safe
  appends for concurrent async requests. Good for a single deployed instance.
- RemoteStore: ships envelopes to a Chronicle control plane over HTTP (stdlib
  urllib). Never raises into the agent (a failed append is warned and dropped);
  reads return [] on failure.
- open_store(target) picks a backend from a string: a path -> JsonlStore,
  sqlite:/// or *.db/*.sqlite -> SqliteStore, http(s):// -> RemoteStore.
- chronicle.record(store=...) now accepts any Store, or a path/URL string routed
  through open_store, so store="sqlite:///runs.db" and control-plane URLs work.
- examples/control_plane/server.py: a minimal reference control plane (stdlib
  http.server + SQLite) that RemoteStore talks to and TokenOps can share.

Exports: Store, JsonlStore, SqliteStore, RemoteStore, open_store, EnvelopeStore.
Tests: tests/test_stores.py (SQLite round-trip, open_store dispatch, record into
SQLite and via a sqlite:// URL, RemoteStore end-to-end against the reference
server, and that a dead control plane never crashes the agent). ruff 0.15.22 clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Tisha Chawla <tisha.chawla2020@vitalum.ac.in>
@tishachawla-jg
tishachawla-jg merged commit 6c49e11 into main Jul 29, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant