@skein-js/storage-postgres
v0.5.0
Published
Postgres SkeinStore driver with pgvector semantic search, reusing PostgresSaver for checkpoints.
Maintainers
Readme
@skein-js/storage-postgres
Production Postgres
SkeinStoredriver with pgvector semantic search.
Part of skein-js — a TypeScript Agent Protocol server for LangGraph.js, and a drop-in replacement for the LangGraph CLI.
Status: 🚧 Pre-alpha — implemented; passes the shared SkeinStore conformance suite (integration tests need Docker).
What it does
A production SkeinStore over pg: it owns the assistants / threads /
runs / store-item tables and their migrations, and is held to the same shared conformance suite
as the memory driver, so the two are provably interchangeable.
- Migrations are applied by
store.migrate()vianode-pg-migrate(SQL files undermigrations/, tracked in askein_migrationstable). Idempotent — safe to call on every boot. - Semantic store search uses pgvector when a
store.index(with an embedder) is configured onconnect; each item's value is embedded andsearch({ query })ranks by cosine distance. Without an index,searchfalls back to naive text matching — identical to the memory driver.
Graph checkpoints are not here — those stay LangGraph-native via PostgresSaver (wired
separately by @skein-js/runtime). This store owns only the protocol resource rows.
Install
pnpm add @skein-js/storage-postgres @langchain/langgraph-checkpoint-postgrespgandnode-pg-migrateare bundled — you do not install them separately.@langchain/langgraph-checkpoint-postgresis a peer dependency: thePostgresSaverthis store pairs with for graph checkpoints (used by@skein-js/runtime, not by this package's own code).- Set
POSTGRES_URIto a Postgres instance with the pgvector extension available for semantic search (skein dev --store postgres/skein upread this env var for you).
Usage
The connection URL is passed explicitly (this package never reads POSTGRES_URI itself):
import { PostgresSkeinStore } from "@skein-js/storage-postgres";
const store = await PostgresSkeinStore.connect(process.env.POSTGRES_URI!);
await store.migrate(); // idempotent; applies pending migrations
// …later, on shutdown:
await store.close();With pgvector semantic search — pass a store.index with an embedder (dims must match the
embedder's output length, or the store throws):
const store = await PostgresSkeinStore.connect(process.env.POSTGRES_URI!, {
index: { dims: 1536, fields: ["content"], embed: async (texts) => embedBatch(texts) },
});
await store.migrate();In practice you rarely call this yourself — skein dev --store postgres / skein up and
@skein-js/runtime resolve POSTGRES_URI and the store.index.embed from your
langgraph.json and construct the store for you.
API
PostgresSkeinStore.connect(url, options?): Promise<PostgresSkeinStore>— the static factory (the constructor is private). Creates apg.Pool; does not migrate.store.migrate(): Promise<void>— apply pending migrations (idempotent).store.close(): Promise<void>— end the pool.store.truncateAll()— test helper.- Repos
assistants/threads/runs/store— theSkeinStoreinterface, with Postgres FKON DELETE CASCADEfor thread→runs and pgvector cosine ranking onstore.search. interface PostgresSkeinStoreOptions—{ index?: StoreIndexConfig }.interface StoreIndexConfig—{ dims: number; fields?: string[]; embed: EmbedFunction }(fieldsdefault["$"]= embed the whole value as JSON).type EmbedFunction—(texts: string[]) => Promise<number[][]>.
Reuse
Pairs with @langchain/langgraph-checkpoint-postgres (PostgresSaver) for graph checkpoints —
skein-js only adds tables for protocol resources and a pgvector column for semantic store search.
(The PostgresSaver wiring lives in @skein-js/runtime; the peer dep here documents
the pairing.)
