Local-first

On-device inference and vector search behind a default-deny privacy gate, two-way offline sync, and per-tenant field encryption. Your data stays on-device by default.

The Local-first family keeps inference and retrieval on the machine that holds the data. A default-deny egress gate is the contract: nothing crosses the network boundary unless a typed allowlist names it, so "on-device" is enforced in code, not promised in a README.

What's in the family

  • local-inference: the InferenceBackend seam over a MiniLM-class ONNX model via transformers.js, SHA-256 hash-verified before use. On-device by default; a remote target is an explicit opt-in.
  • local-privacy: the EgressGuard runtime wrapper over a strict zero-egress PrivacyPolicy: every payload crosses it before it can leave the process, and an empty allowlist blocks every host.
  • local-store: hybrid vector + full-text retrieval on disk, one SQLite file per tenant, sqlite-vec KNN fused with FTS5 by Reciprocal Rank Fusion, no vector cloud involved.
  • local-sync: two-way offline sync for those per-tenant SQLite files: a changeset log, a hybrid-logical-clock last-writer-wins merge, and tombstone-aware convergence.
  • field-crypto: per-tenant field encryption for anything stored in the local database, shared with the Compliance, AI-Production, and Provenance families.

Install

bunx --package @caisson-sh/cli@latest create-caisson --name caisson-app --module <id@version>
cd caisson-app
bun install

Repeat --module <id@version> once per module you want. Every module installs from public npm, no token needed; see Getting started for the full flag reference.

How it composes

local-inference runs embeddings on-device; local-store persists and searches the vectors it produces; local-sync reconciles that same per-tenant SQLite file across devices without a server round-trip. local-privacy's EgressGuard sits in front of all three, any path that would send a payload off the device passes through it first, and an empty allowlist blocks every host by default. field-crypto seals sensitive columns in the local store the same way it seals a Postgres column: a per-tenant derived key, never a shared one.

Composing with the base

The tenant boundary is the same one @caisson-sh/tenancy-rls enforces server-side: each local SQLite file is scoped to one tenant, so a sync merge or a vector search never crosses into another tenant's data even without a network round-trip to check.

License

Every module here is Apache-2.0 and installs from public npm.

Next steps