{"slug": "show-hn-open-source-toolkit-for-ai-memory-that-scales", "title": "Show HN: Open-source toolkit for AI memory that scales", "summary": "Lithium, an open-source toolkit for AI memory, launched with a PostgreSQL-based storage engine that uses hierarchical versioned storage to scale tree-structured data. The toolkit, which includes zero runtime dependencies and built-in versioning, claims to outperform graph and vector databases for tree queries by using PostgreSQL's ltree extension for index-backed subtree lookups instead of graph traversal.", "body_md": "Hierarchical versioned storage on PostgreSQL ltree. Scoped retrieval, built-in versioning, zero runtime deps.\n\n``` js\nconst lithium = new Lithium(drizzleAdapter(db));\n\nawait lithium.clusters.create({ name: \"infra\" });\nawait lithium.clusters.create({ name: \"database\", parentPath: \"infra\" });\n\nconst context = await lithium.getContext({ path: \"infra\" });\n```\n\nMemory 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.\"\n\nPostgreSQL's `ltree`\n\nhandles tree queries significantly faster. Index-backed subtree lookups, not traversal. Lithium wraps it in a clean TypeScript API with built-in versioning.\n\n| Lithium | Graph DBs | Vector DBs | |\n|---|---|---|---|\nStructure |\nTree hierarchy | Arbitrary graph | Flat |\nQuery speed |\nltree index-backed | Graph traversal | ANN search |\nRetrieval |\nDeterministic, scoped | Pattern matching | Fuzzy, similarity |\nVersioning |\nBuilt-in, immutable | Manual | Overwrite |\nInfrastructure |\nYour existing Postgres | Separate service | Separate service |\n\n| Package | What | Size |\n|---|---|---|\n`@lithium-ai/core` |\nZero-dep storage engine | |\n`@lithium-ai/postgres` |\nPostgreSQL ltree adapter | |\n`@lithium-ai/drizzle` |\nDrizzle ORM adapter | |\n`@lithium-ai/mcp` |\nMCP server for AI tools |\n\n**Prerequisites:** PostgreSQL with `ltree`\n\nextension.\n\n**With Drizzle:**\n\n```\nnpm install @lithium-ai/core @lithium-ai/drizzle drizzle-orm\njs\nimport { Lithium } from \"@lithium-ai/core\";\nimport { drizzleAdapter } from \"@lithium-ai/drizzle\";\n\nconst lithium = new Lithium(drizzleAdapter(db));\n```\n\n**With raw postgres:**\n\n```\nnpm install @lithium-ai/core @lithium-ai/postgres postgres\njs\nimport { Lithium } from \"@lithium-ai/core\";\nimport { postgresAdapter } from \"@lithium-ai/postgres\";\nimport postgres from \"postgres\";\n\nconst sql = postgres(\"postgres://...\");\nconst lithium = new Lithium(postgresAdapter(sql));\n```\n\n**Then:**\n\n``` js\n// Create hierarchy\nconst infra = await lithium.clusters.create({ name: \"infra\" });\nawait lithium.clusters.create({ name: \"database\", parentPath: \"infra\" });\n\n// Create versioned entries\nconst entry = await lithium.entries.create({ clusterId: infra.value.id });\nawait lithium.entries.update({ id: entry.value.entry.id });\n\n// Scoped retrieval: everything under \"infra\"\nconst context = await lithium.getContext({ path: \"infra\" });\nnpm install @lithium-ai/mcp\njs\n// server.ts\nimport { Lithium } from \"@lithium-ai/core\";\nimport { postgresAdapter } from \"@lithium-ai/postgres\";\nimport { serveMcp } from \"@lithium-ai/mcp\";\nimport postgres from \"postgres\";\n\nconst sql = postgres(process.env.DATABASE_URL!);\n\nconst lithium = new Lithium(postgresAdapter(sql), async (versionIds) => {\n  const rows = await sql`\n    SELECT entry_version_id, title, content\n    FROM your_content_table\n    WHERE entry_version_id = ANY(${versionIds})\n  `;\n  return new Map(rows.map((r) => [r.entry_version_id, r]));\n});\n\nserveMcp(lithium);\n```\n\nAdd to Claude Code:\n\n```\n{\n  \"mcpServers\": {\n    \"lithium\": {\n      \"command\": \"npx\",\n      \"args\": [\"tsx\", \"server.ts\"]\n    }\n  }\n}\n```\n\nEntries are pure structure. Your content lives in your own tables, referenced by entry version IDs.\n\n```\nCluster\n  id, parentId, path (\"infra.database\"), name, description, createdAt\n\nEntry\n  id, clusterId, createdAt\n\nEntryVersion\n  id, entryId, version (auto-incremented), createdAt\n\nYour Content Table\n  entryVersionId (FK), title, content, ...whatever you want\n```\n\n| Method | What |\n|---|---|\n`create({ name, parentPath?, description? })` |\nCreate cluster, resolve parent |\n`findByPath({ path })` |\nFind by dot-path |\n`list()` |\nAll clusters ordered by path |\n`listDescendantIds({ path })` |\nltree subtree query |\n\n| Method | What |\n|---|---|\n`create({ clusterId })` |\nNew entry + version 1 |\n`update({ id })` |\nAuto-increment version |\n`get({ id, version? })` |\nEntry + version (latest or specific) |\n`list({ clusterIds })` |\nEntries by cluster IDs |\n`listWithLatestVersion({ clusterIds })` |\nEntries + latest versions (batch) |\n\n| Method | What |\n|---|---|\n`getContext({ path })` |\nScoped retrieval with optional content resolver |\n\nEvery method returns `Result<T, E>`\n\n. No thrown exceptions.\n\n``` js\nconst result = await lithium.clusters.create({ name: \"infra\" });\nif (!result.success) {\n  // result.error is ValidationError | NotFoundError | SystemError\n  // Discriminate via error.kind or instanceof\n}\n```\n\n**Drizzle users:** Import the schemas and use `drizzle-kit push`\n\n:\n\n```\nexport { clusters, entries, entryVersions } from \"@lithium-ai/drizzle\";\nnpx drizzle-kit push\n```\n\n**Raw SQL:** Run the reference migrations from `@lithium-ai/postgres`\n\n:\n\n```\npsql -d your_db -f node_modules/@lithium-ai/postgres/src/migrations/001_clusters.sql\npsql -d your_db -f node_modules/@lithium-ai/postgres/src/migrations/002_entries.sql\n```\n\nRequires `CREATE EXTENSION IF NOT EXISTS ltree;`\n\nbefore running.\n\n- Core storage engine (\n`@lithium-ai/core`\n\n) - PostgreSQL ltree adapter (\n`@lithium-ai/postgres`\n\n) - MCP server (\n`@lithium-ai/mcp`\n\n) - Content resolver callback for\n`getContext`\n\n- Drizzle ORM adapter (\n`@lithium-ai/drizzle`\n\n) - GitHub Actions CI\n- Integration tests (testcontainers)\n- Transaction support (atomic createEntry)\n- MCP write tools (create_cluster, create_entry)\n- Example projects\n- Prisma adapter\n\n- AI agent memory (structured retrieval, scoped context)\n- Decision tracking across teams\n- Config versioning\n- Documentation hierarchies\n\nRead more: [Memory Graphs Don't Scale](https://dev.to/0xjaksun/memory-graphs-dont-scale-4p0i)\n\nIssues and PRs welcome.\n\nMIT", "url": "https://wpnews.pro/news/show-hn-open-source-toolkit-for-ai-memory-that-scales", "canonical_source": "https://github.com/0xJaksun/lithium-core", "published_at": "2026-05-29 04:44:16+00:00", "updated_at": "2026-05-29 05:16:57.062925+00:00", "lang": "en", "topics": ["ai-infrastructure", "ai-tools", "ai-products", "artificial-intelligence", "ai-agents"], "entities": ["Lithium", "PostgreSQL", "Drizzle", "MCP", "ltree"], "alternates": {"html": "https://wpnews.pro/news/show-hn-open-source-toolkit-for-ai-memory-that-scales", "markdown": "https://wpnews.pro/news/show-hn-open-source-toolkit-for-ai-memory-that-scales.md", "text": "https://wpnews.pro/news/show-hn-open-source-toolkit-for-ai-memory-that-scales.txt", "jsonld": "https://wpnews.pro/news/show-hn-open-source-toolkit-for-ai-memory-that-scales.jsonld"}}