Show HN: Open-source toolkit for AI memory that scales
Lithium is a hierarchical versioned storage engine built on PostgreSQL ltree, offering deterministic, scoped retrieval, built-in versioning, and zero runtime dependencies. It integrates with AI tools via MCP server, suitable for AI agent memory, decision tracking, and more.
Article intelligence
Key points
- Hierarchical versioned storage using PostgreSQL ltree, faster than graph databases
- TypeScript API with scoped retrieval and built-in versioning
- MCP server for connection to AI tools like Claude
- Zero runtime dependencies, leverages existing PostgreSQL infrastructure
Why it matters
This matters because hierarchical versioned storage using PostgreSQL ltree, faster than graph databases.
Technical impact
May affect model selection, inference cost, product capability, and evaluation benchmarks.
Notifications You must be signed in to change notification settings
Fork 0
Star 2
BranchesTags
Open more actions menu
Folders and files
NameName
Last commit message
Last commit date
Latest commit
History
81 Commits
81 Commits
.github/workflows
.github/workflows
packages
packages
.gitignore
.gitignore
LICENSE
LICENSE
README.md
README.md
package.json
package.json
pnpm-lock.yaml
pnpm-lock.yaml
pnpm-workspace.yaml
pnpm-workspace.yaml
vitest.integration.config.ts
vitest.integration.config.ts
vitest.unit.config.ts
vitest.unit.config.ts
Repository files navigation
Hierarchical versioned storage on PostgreSQL ltree. Scoped retrieval, built-in versioning, zero runtime deps.
const lithium = new Lithium(drizzleAdapter(db));
await lithium.clusters.create({ name: "infra" }); await lithium.clusters.create({ name: "database", parentPath: "infra" });
const context = await lithium.getContext({ path: "infra" });
Why?
Memory graphs don't scale for tree-structured data. Graph traversal becomes a bottleneck. Vector search gives you "similar to X" when you need "everything under X."
PostgreSQL's ltree handles tree queries significantly faster. Index-backed subtree lookups, not traversal. Lithium wraps it in a clean TypeScript API with built-in versioning.
Lithium Graph DBs Vector DBs
Structure Tree hierarchy Arbitrary graph Flat
Query speed ltree index-backed Graph traversal ANN search
Retrieval Deterministic, scoped Pattern matching Fuzzy, similarity
Versioning Built-in, immutable Manual Overwrite
Infrastructure Your existing Postgres Separate service Separate service
Packages
Package What Size
@lithium-ai/core Zero-dep storage engine
@lithium-ai/postgres PostgreSQL ltree adapter
@lithium-ai/drizzle Drizzle ORM adapter
@lithium-ai/mcp MCP server for AI tools
Quick Start
Prerequisites: PostgreSQL with ltree extension.
With Drizzle:
npm install @lithium-ai/core @lithium-ai/drizzle drizzle-orm
import { Lithium } from "@lithium-ai/core"; import { drizzleAdapter } from "@lithium-ai/drizzle";
const lithium = new Lithium(drizzleAdapter(db));
With raw postgres:
npm install @lithium-ai/core @lithium-ai/postgres postgres
import { Lithium } from "@lithium-ai/core"; import { postgresAdapter } from "@lithium-ai/postgres"; import postgres from "postgres";
const sql = postgres("postgres://..."); const lithium = new Lithium(postgresAdapter(sql));
Then:
// Create hierarchy const infra = await lithium.clusters.create({ name: "infra" }); await lithium.clusters.create({ name: "database", parentPath: "infra" });
// Create versioned entries const entry = await lithium.entries.create({ clusterId: infra.value.id }); await lithium.entries.update({ id: entry.value.entry.id });
// Scoped retrieval: everything under "infra" const context = await lithium.getContext({ path: "infra" });
Connect to Claude
npm install @lithium-ai/mcp
// server.ts import { Lithium } from "@lithium-ai/core"; import { postgresAdapter } from "@lithium-ai/postgres"; import { serveMcp } from "@lithium-ai/mcp"; import postgres from "postgres";
const sql = postgres(process.env.DATABASE_URL!);
const lithium = new Lithium(postgresAdapter(sql), async (versionIds) => { const rows = await sql` SELECT entry_version_id, title, content FROM your_content_table WHERE entry_version_id = ANY(${versionIds}) `; return new Map(rows.map((r) => [r.entry_version_id, r])); });
serveMcp(lithium);
Add to Claude Code:
{ "mcpServers": { "lithium": { "command": "npx", "args": ["tsx", "server.ts"] } } }
Data Model
Entries are pure structure. Your content lives in your own tables, referenced by entry version IDs.
Cluster id, parentId, path ("infra.database"), name, description, createdAt
Entry id, clusterId, createdAt
EntryVersion id, entryId, version (auto-incremented), createdAt
Your Content Table entryVersionId (FK), title, content, ...whatever you want
API
Clusters
Method What
create({ name, parentPath?, description? }) Create cluster, resolve parent
findByPath({ path }) Find by dot-path
list() All clusters ordered by path
listDescendantIds({ path }) ltree subtree query
Entries
Method What
create({ clusterId }) New entry + version 1
update({ id }) Auto-increment version
get({ id, version? }) Entry + version (latest or specific)
list({ clusterIds }) Entries by cluster IDs
listWithLatestVersion({ clusterIds }) Entries + latest versions (batch)
Context
Method What
getContext({ path }) Scoped retrieval with optional content resolver
Error Handling
Every method returns Result. No thrown exceptions.
const result = await lithium.clusters.create({ name: "infra" }); if (!result.success) { // result.error is ValidationError | NotFoundError | SystemError // Discriminate via error.kind or instanceof }
Migrations
Drizzle users: Import the schemas and use drizzle-kit push:
export { clusters, entries, entryVersions } from "@lithium-ai/drizzle";
npx drizzle-kit push
Raw SQL: Run the reference migrations from @lithium-ai/postgres:
psql -d your_db -f node_modules/@lithium-ai/postgres/src/migrations/001_clusters.sql psql -d your_db -f node_modules/@lithium-ai/postgres/src/migrations/002_entries.sql
Requires CREATE EXTENSION IF NOT EXISTS ltree; before running.
Roadmap
Core storage engine (@lithium-ai/core)
PostgreSQL ltree adapter (@lithium-ai/postgres)
MCP server (@lithium-ai/mcp)
Content resolver callback for getContext
Drizzle ORM adapter (@lithium-ai/drizzle)
GitHub Actions CI
Integration tests (testcontainers)
Transaction support (atomic createEntry)
MCP write tools (create_cluster, create_entry)
Example projects
Prisma adapter
Use Cases
AI agent memory (structured retrieval, scoped context)
Decision tracking across teams
Config versioning
Documentation hierarchies
Read more: Memory Graphs Don't Scale
Contributing
Issues and PRs welcome.
License
MIT
About
Hierarchical versioned storage on PostgreSQL ltree. Scoped retrieval, built-in versioning, zero runtime deps.
www.npmjs.com/package/@lithium-ai/core
Topics
open-source
typescript
mcp
postgresql
hierarchical
ltree
ai-memory
structured-context
versioned-storage
Resources
Readme
License
MIT license
Uh oh!
There was an error while loading. Please reload this page.
Activity
Stars
2 stars
Watchers
1 watching
Forks
0 forks
Report repository
Releases 2
v0.0.5 — Atomic entry creation with transaction support
Latest
May 29, 2026
+ 1 release
Packages 0
Uh oh!
There was an error while loading. Please reload this page.
Contributors
Uh oh!
There was an error while loading. Please reload this page.
Languages
TypeScript 100.0%