The open-source apply client for schema databases. Run it next to your own PostgreSQL, pair once, and it keeps that database converged with your enrichments — bootstrapping from a snapshot, then applying a live delta feed over a single outbound WebSocket. Your connection string never leaves your machine.
Every statement is revision-guarded, so a redelivered batch converges to the same rows. A SQL error rolls the batch back and halts — a poison delta is never silently skipped.
The client pulls state, not operations: each delta carries the full current row(s) for a changed entity as an idempotent INSERT … ON CONFLICT … DO UPDATE, so the target converges even if a batch was missed.
Schema databases can be consumed several ways — n8n, Make.com, MCP, raw webhooks, or the REST delta feed. The sync client is the fully-automated path: the least to build and the least to leak.
No n8n scenario, no cron, no glue code. Pair once and it bootstraps from the snapshot, then applies every delta as it arrives.
The connection string is passed on the command line or stored mode-600 locally — it is never sent to Entity Enricher. The client connects outward only.
Every delta is an idempotent, revision-guarded upsert. If the client dies mid-batch, the batch is redelivered after its lease expires and re-applying converges to the same rows.
A SQL error rolls the batch back, reports the failing delta to the Databases page, and exits non-zero — a poison delta can never be quietly skipped.
Register a database on a schema first, then pair a client and run it next to your database.
On the Databases page, register a database on the schema you want to mirror and review its database keys. See Databases for the full model. This step declares the target dialect the client will apply.
Download a signed binary from Releases, or build from source (Go ≥ 1.23).
go build -o ee-database .
Source and signed releases live at TOT-Concept/ee-database (MIT).
Run ee-database pair. A browser tab opens at /database/connect with a short code — confirm it, and pick which database this client should sync.
ee-database pair --server https://entityenricher.ai Open this URL in your browser to confirm pairing: https://entityenricher.ai/database/connect?code=7QX-KP2 Code: 7QX-KP2 Waiting for confirmation...
Prefer a token? Issue one on the Databases page (Sync client → Pair a client) and pass it directly: ee-database pair --server … <refresh-token>.
On first run the client fetches the .sql snapshot and applies it, then connects and streams deltas. --save-dsn stores the connection string locally so later runs need no arguments.
ee-database run --dsn "postgres://user:pass@localhost:5432/mydb" --save-dsn
“Next to” means network-adjacent, not on the database server: any machine or container that can reach the DSN works — including cloud-managed PostgreSQL (Azure, OVHcloud, AWS RDS…), which usually enforces TLS: …/mydb?sslmode=require.
Deltas leave Entity Enricher through a strict per-database FIFO outbox. The server leases the visible window for 120 seconds and pushes it as one batch; the client applies the whole batch in a single transaction and replies ack , which advances the cursor and triggers the next window immediately. A client that dies mid-batch is covered by lease expiry and a server-side re-push — nothing is lost or double-committed.
Bootstrap and steady-state share one code path. Skip the bootstrap with --skip-bootstrap if your database is already seeded.
Each statement carries a _sync_revision so an older row never overwrites a newer one, even out of order.
A SQL error stores the failing delta id on the Databases page → Sync client card, and the process exits non-zero for your supervisor to restart.
The target dialect is fixed by the schema-database registration in Entity Enricher — the client applies whatever SQL the server renders. PostgreSQL is the launch dialect; the MySQL and SQLite drivers are already bundled for when their SQL renderers ship. Multi-statement application is handled per driver (pgx simple protocol, MySQL multiStatements, and CGO-free SQLite).
The client initiates the WebSocket over :443/wss. Your database host never accepts inbound connections — no ports to open, no ingress to configure.
A credential is bound to a single schema database. Pairing again rotates it and instantly evicts the previous live connection.
The 365-day refresh token (stored mode-600) is exchanged for 15-minute access tokens that authenticate the WebSocket. Revoking in the UI disconnects a live client within ~1 second.
Run the client against a dedicated database role scoped to the synced schema, so a compromised token can touch nothing else.
| Command | What it does |
|---|---|
| ee-database pair --server URL | Browser-confirmed device-code pairing. Pick which database to sync. |
| ee-database pair --server URL <token> | Pair with a token issued on the Databases page (headless-friendly). |
| ee-database run --dsn DSN [--save-dsn] [--skip-bootstrap] | Bootstrap from the snapshot (unless skipped), then connect and apply deltas. |
| ee-database run … --create-missing | Create the target database first when it does not exist, using the DSN's own credentials (postgres needs CREATEDB, mysql the CREATE privilege; sqlite files are created automatically anyway). |
| ee-database run … --create-missing --admin-dsn DSN | Bootstrap everything the target DSN names via an admin connection: the missing role/user (with the DSN's password) and the database owned by it. The target DSN then needs no create rights; the admin DSN is never stored. |
| ee-database run --all | Sync every paired database concurrently from one process (each needs a saved DSN). |
| ee-database status | Show pairing state, server URL and the paired databases. |
| ee-database disconnect | Forget one pairing's local credentials. Revoke server-side from the UI. |
| ee-database version | Print version. |
Credentials are stored mode-600, one profile per paired database, under ~/.config/ee-database/profiles/ — pair once per database, and --database NAME selects one when several are paired. Prefer no automation at all? The same feed is plain REST: GET /api/databases//changes then POST /api/databases//ack — see Databases.
The client is MIT-licensed and lives in a public repository so anyone can audit exactly what runs against their database.
Source: github.com/TOT-Concept/ee-database
Releases: github.com/TOT-Concept/ee-database/releases — each binary is signed before publication.