Skip to content

RFC/draft: opt-in libSQL/Turso storage backend for concurrent multi-writer memory#262

Draft
Donach wants to merge 2 commits into
rtk-ai:mainfrom
Donach:turso-backend-minimal
Draft

RFC/draft: opt-in libSQL/Turso storage backend for concurrent multi-writer memory#262
Donach wants to merge 2 commits into
rtk-ai:mainfrom
Donach:turso-backend-minimal

Conversation

@Donach
Copy link
Copy Markdown

@Donach Donach commented Jun 4, 2026

Summary — opt-in libSQL/Turso storage backend (draft / RFC)

ICM keeps memory in a single local SQLite file, so it can't be shared or written
concurrently from more than one machine/process. This adds an opt-in backend
that runs the existing icm-store SQL over the async libsql client, so the
store can live in a libSQL/Turso database — local file, a remote sqld/Turso
server, or an embedded replica. A remote server is the multi-writer path (it
serialises writes from every ICM process).

The default build is completely unchangedrusqlite, exactly as today. The
two backends are mutually-exclusive Cargo features. Still a draft: I'd like
your read on whether you want this at all and how you'd shape it before polishing.

What changed

  • icm-store gains a small sync-over-async facade (crates/icm-store/src/dbcompat.rs)
    mirroring the slice of the rusqlite API the store uses. Under --features turso
    it's aliased as rusqlite, so store.rs/schema.rs are byte-identical to the
    default build
    apart from cfg-gated imports and the connection-open path.
  • Backends are mutually exclusive:
    • default = backend-rusqlite → upstream rusqlite, untouched.
    • cargo build -p icm-cli --no-default-features --features turso,embeddings,tui
      → libSQL. With rusqlite absent there's no extern/alias clash; compile_error!
      guards reject enabling both/neither.
  • Feature plumbed through icm-mcp + icm-cli. Runtime backend chosen by env
    (TURSO_DATABASE_URL/LIBSQL_URL + TURSO_AUTH_TOKEN; ICM_TURSO_REPLICA=1).

Verified

  • Default backend: 162/162 icm-store tests pass (unchanged behaviour).
  • Turso backend: 161/162 — only perf_fts_search_100 regresses (see gaps).
  • Against a self-hosted sqld (sqlite-vec loaded via --extensions-path):
    store/recall, and 16 concurrent icm processes wrote with zero lost rows.

Honest remaining gaps

  1. Perf: the sync-over-async bridge does a block_on per call, so
    perf_fts_search_100 regresses on the turso build (worse over the network).
    Wants connection reuse or an async store path — I'd value your steer here.
  2. No new libSQL-specific tests yet; the existing suite runs under both
    backends, but CI for the turso feature would need a spun-up sqld (or the
    in-memory path).
  3. The use crate::dbcompat as rusqlite; alias keeps the diff tiny but is
    unusual — happy to refactor toward a Storage trait if you'd prefer.
  4. sqlite-vec must be loaded server-side for the vector schema; embedded
    replicas can't forward the vec0 DDL (so remote is the vector path).

Questions

  1. Would you accept a self-hosted libSQL/Turso backend, given icm cloud is
    already Turso-backed — or is hosted-only intentional?
  2. Is this feature-flag shape what you'd want? Should I target develop?
  3. Preference on the perf path — make the store async, or keep a sync bridge with
    connection pooling?

Branched off main@804dac2 for a clean diff; glad to rebase onto develop.
Setup + verified results in docs/turso-backend.md.

Disclosure: implemented with AI assistance and human-reviewed; commits carry a
Co-Authored-By trailer. Flagging it up front.

Donach and others added 2 commits June 4, 2026 07:45
…ite)

Re-architect the Turso backend as a thin overlay to minimise the diff against
upstream (store.rs is upstream's most-churned file → fewer rebase conflicts).

dbcompat is now a faithful rusqlite-0.34-shaped drop-in (exact Params model:
empty [], [T;1..32], &[&dyn ToSql]; params! -> &[&dyn ToSql]; phantom-lifetime
Row<'_>; types::ToSql). store.rs/schema.rs are byte-identical to upstream except
'use crate::dbcompat as rusqlite;' plus the connection-open path (open_backend +
remote PRAGMA guard) — store.rs touched lines: 206 -> ~15 + one isolated fn;
schema.rs: 34 -> 3. Tests: 161 pass / 1 perf-test fail (same as before).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Turn the Turso support into a mutually-exclusive Cargo feature so it's purely
additive for existing users:

- default (`backend-rusqlite`) = upstream rusqlite, untouched — store.rs/schema.rs
  are byte-identical apart from cfg-gated imports and the connection-open path.
- `--no-default-features --features turso` routes the same SQL through the
  libSQL-backed dbcompat shim (aliased as `rusqlite`). rusqlite is then absent,
  so there's no extern/alias clash. Backends are mutually exclusive (compile_error
  guards if both/neither).
- Feature plumbed through icm-mcp + icm-cli; flake builds the turso binary.

Tests: default 162/162; turso 161/162 (only perf_fts_search_100, documented).
Docs: docs/turso-backend.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Donach Donach changed the title RFC/draft: optional libSQL/Turso storage backend for concurrent multi-writer memory RFC/draft: opt-in libSQL/Turso storage backend for concurrent multi-writer memory Jun 4, 2026
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