Shared memory.
Your Postgres. No middleman.
Multi-user Lattice databases on a Postgres you own. Email-bound invitations, machine-local identity, encrypted secrets, content-addressed files. Self-hosted by design — no central account, no vendor lock-in.
One command to bootstrap a team.
lattice teams register is atomic: it creates the bootstrap user, the team, the creator membership, and the bearer token in a single HTTP call. No two-step dance, no half-created state.
# One atomic command. Creates the user, the team,
# the creator membership, and the bearer token.
lattice teams register \
--cloud http://localhost:4317 \
--email alice@example.com \
--name "Alice" \
--team-name "Atlas"
# → Registered alice@example.com and created team "Atlas".
# user-id: 9f3a...
# team-id: 4d12...
# Bootstrap API token (shown ONCE — save it now):
# lat_8f4c2b...Invite by email. The token is bound.
Every invitation carries an invitee_email. The cloud refuses to redeem a token if the caller's claimed email doesn't match (case-insensitive). Share invite tokens over unauthenticated channels without worrying — only the addressee can use them.
# Alice (creator) invites Bob by email. The invite
# token is BOUND to bob@example.com — Eve can't redeem it.
lattice teams invite --team Atlas --invitee-email bob@example.com
# → Invitation generated for bob@example.com (expires …).
# Share this token with the invitee (one-time use):
# latinv_a2c8e5...
# Bob redeems from his own machine
lattice teams join \
--cloud http://localhost:4317 \
--token latinv_a2c8e5... \
--email bob@example.com \
--name "Bob"
# → Joined team "Atlas". Local connection saved.Operating principles.
Your Postgres
Lattice does not host your database. Bring any Postgres — Supabase, Neon, RDS, a VM, your laptop. We provide the schema, the auth, and the sync engine.
No central account
There is no latticedesktop.com login required to create a team. Bearer tokens live on your machine. Identity is local-first.
One team per DB
No multi-tenant juggling. Each cloud Postgres is one team. Need multiple teams? Spin up multiple databases. Each gets its own URL + member list.
Email-bound invites
Invitations carry a recipient email. An invite token is useless without the bound address — case-insensitive, checked before the token-already-used check.
Encrypted at rest
secrets.value, connection strings, and per-team tokens are AES-encrypted on every operator’s machine. The master key auto-generates as ~/.lattice/master.key (chmod 0600 on POSIX).
No SDK lock-in
The cloud speaks HTTP. The CLI, the GUI, and the TeamsClient TypeScript API all hit the same routes. Build your own client if you want — it is a JSON API.
Realtime out of the box (v1.13.8+)
Cloud Postgres-backed lattices stream changes to every connected GUI in realtime via LISTEN/NOTIFY + Server-Sent Events. A topbar dot reports cloud connection health; the entity cache invalidates on every change. No additional service to deploy.
Identity once, switch projects freely.
Display name, email, encrypted connection strings, and per-team bearer tokens live in ~/.lattice/ — outside any single Lattice DB. Switch between projects without retyping who you are.
| ~/.lattice/master.key | 32-byte AES key, auto-generated, chmod 0600. LATTICE_ENCRYPTION_KEY env wins. |
| ~/.lattice/identity.json | {display_name, email} — mirrored into the active Lattice as __lattice_user_identity (singleton) on every open. |
| ~/.lattice/keys/<label>.token | Per-joined-team bearer token. One file per team you have joined. |
| ~/.lattice/db-credentials.enc | AES-GCM-encrypted Postgres URLs by label. YAML references them as ${LATTICE_DB:<label>} so passwords never live in your config files. |
Share tables. Link rows. Sync.
Any member can share a local table with the team; other members auto-register the schema on their next sync. Row-level link / unlink chooses which rows are team-visible; only the owner can push updates.
# Alice shares the tasks table with the team
lattice teams share --team Atlas --table tasks
# Alice links a row to the team
lattice teams link --team Atlas --table tasks --pk task-001
# Bob (on a different machine) pulls
lattice teams sync --team Atlas
lattice teams pull --team Atlas
# task-001 now lives in Bob's local tasks table
# Bob updates a row he owns; the change propagates
db.update('tasks', 'task-002', { status: 'done' });
lattice teams push --team AtlasMonotonic change log
Every share / link / row update / unlink lands in a single ordered feed. Pullers track a per-team last_change_seq cursor.
Replay guard
Your local writes never re-push during a pull. The outbox capture hook is gated by an _isReplaying flag.
Auto-unlink on kick
Removing a member tears down every row they owned in this team. Receivers drop the rows on their next pull.
secrets and files come for free.
Every Lattice opened by the GUI auto-registers two framework-shipped tables. secrets.value is encrypted at rest; files writes into a content-addressed blob store at data/blobs/<sha256>. Use them from the GUI or the API.
import { Lattice } from 'latticesql';
import { registerNativeEntities } from 'latticesql/framework/native-entities';
const db = new Lattice(
{ config: './lattice.config.yml' },
{ encryptionKey: process.env.LATTICE_ENCRYPTION_KEY },
);
registerNativeEntities(db);
await db.init();
// secrets.value is encrypted at rest (AES-256-GCM)
await db.insert('secrets', {
name: 'OPENAI_API_KEY',
kind: 'api-key',
value: 'sk-...', // stored as 'enc:<base64>' on disk
});
// files lands in content-addressed storage at data/blobs/<sha256>
import { attachBlob } from 'latticesql/framework/blob-store';
const meta = await attachBlob('./contract.pdf', process.cwd());
await db.insert('files', meta);CLI
Scriptable end-to-end.
lattice teams covers register, join, invite, share, sync, link, push, pull, members, leave, destroy, and status. CI-friendly — every action is one HTTP call away.
Local browser GUI
Same flows, no terminal required.
lattice gui drives the whole lifecycle: configure the cloud DB, register, invite by email, share tables, watch sync status. Identity is prefilled from ~/.lattice/identity.json.
Start local. Migrate to cloud. Invite your team.
Each step is a single wizard in the local GUI and a single public function in the npm package. Migrate or connect to Postgres and the database is a shareable cloud workspace — with you as the owner, ready to invite your team.
Step 1
Local SQLite
Your project starts on a local .db file. Native secrets + files entities work out of the box.
Step 2
Migrate to cloud
The Migrate to cloud → wizard runs migrateLatticeData to copy every row into your BYO Postgres, renames the SQLite to .db.local-bak, and rewrites your YAML.
Step 3
Invite your team
Your cloud database is a shareable workspace and you're the owner. Invite teammates by email — choose which tables to share (all checked by default) — and they redeem with Join a team → invite token and land in the shared tables instantly.
Public API: migrateLatticeData, probeCloud, TeamsClient.connectToExistingCloud, TeamsClient.ensureCloudWorkspaceIdentity. Full API reference →
Spin up a team in five minutes.
Install latticesql. Point it at your Postgres. Run lattice teams register. Invite your team by email.
Need volume, SSO, or compliance?
The OSS Teams release is self-serve. If you're standing up Lattice across an organisation and need audit trails, SSO, or a managed cloud, tell us what you're building.