- Update architecture docs to reflect pivot from @libsql/client to Honker - Fold @alkdev/drizzlebox Phase 0 into src/sqlite/utils/ (ADR-046) - Add HonkerEventTarget adapter for pubsub TypedEventTarget (ADR-047) - Replace hand-written CRUD with OperationSpec generation (ADR-048) - Resolved OQ-26: Honker replaces Redis for single-node pub/sub (POC validated) - Updated OQ-17, OQ-18, OQ-19 for OperationSpec repository surface - Added OQ-30 (composite event target), OQ-31 (consumer naming), OQ-32 (Drizzle Kit) - POC results: adapter buildable, same-process pub/sub works, transactional outbox semantics confirmed, concurrent listeners/streams work - Research doc at docs/research/pivot-honker-sqlite-adapter.md
8.0 KiB
AGENTS.md — @alkdev/storage
Project-specific guidance for agents working on this package.
Project Overview
@alkdev/storage is a deno-first TypeScript package providing typed graph
storage with SQLite via Honker. It uses the metagraph pattern (graphTypes →
nodeTypes → edgeTypes → typed graph instances) and includes identity tables
for multi-tenant auth. The system/tenant DB model separates identity
infrastructure from org-scoped graph data.
Architecture Snapshot
@alkdev/storage/
├── mod.ts # Re-exports graphs/ only (zero db deps)
├── deno.json # JSR config, imports, tasks, lint rules
├── src/
│ ├── graphs/ # Metagraph Module + bridge functions (no db deps)
│ │ ├── modules/ # TypeBox Module definitions
│ │ │ ├── metagraph.ts # Base Metagraph Module (Config, BaseNode, BaseEdge)
│ │ │ ├── call-graph.ts # CallGraph reference Module
│ │ │ ├── secret-graph.ts # SecretGraph reference Module
│ │ │ └── index.ts # Barrel re-export
│ │ ├── bridge.ts # moduleToDbSchema, validateNode, validateEdge
│ │ ├── crypto.ts # encrypt, decrypt, generateEncryptionKey, EncryptedDataSchema
│ │ └── mod.ts # Re-exports all graphs exports
│ └── sqlite/ # SQLite host (drizzle-orm + honker-node)
│ ├── tables/
│ │ ├── common.ts # shared column definitions
│ │ ├── identity/ # accounts, organizations, org_members, api_keys, audit_logs
│ │ └── metagraph/ # graph_types, node_types, edge_types, graphs, nodes, edges
│ ├── utils/ # createSelectSchema, createInsertSchema, column mappings (ADR-046)
│ ├── relations.ts # Drizzle relations
│ ├── adapter.ts # Drizzle-Honker session adapter
│ ├── event-target.ts # HonkerEventTarget (pubsub TypedEventTarget on Honker)
│ ├── schema.ts # Re-exports
│ └── client.ts # createSystemDatabase(), createTenantDatabase()
└── test/
└── reference-modules.test.ts # Metagraph, bridge, crypto tests
Subpath Exports (JSR/npm)
@alkdev/storage→ Metagraph Module, graph type definitions (zero deps)@alkdev/storage/sqlite→ SQLite tables (metagraph + identity), relations, client, adapter, event-target, utils (drizzle-orm + honker-node, peer: @alkdev/pubsub)
PostgreSQL has been removed (ADR-038). SQLite via Honker is the sole database host.
Key Decisions
- Deno-first, npm-second via JSR: Package is published to JSR
(
deno publish). npm compatibility is automatic via JSR's npm layer (@jsr/alkdev__storage). No separate dnt build step. - No comments in code: Per project convention across @alkdev packages.
- JSR slow types excluded from lint: Drizzle's deeply inferred generics
(
sqliteTable,createInsertSchema,relations) make explicit type annotations impractical. We use--allow-slow-typeson publish and"exclude": ["no-slow-types"]in lint config. This is known technical debt — can be tightened iteratively. - Injectable clients:
createSystemDatabase(client)andcreateTenantDatabase(client)take pre-created Honker clients, not env vars. Module-level side effects are forbidden. - Dependencies:
@alkdev/typeboxis an npm dep (not yet on JSR).@alkdev/pubsubis a peer dep (forTypedEventTargettype). The@alkdev/drizzleboxexternal dep has been folded intosrc/sqlite/utils/(ADR-046). - SQLite-only via Honker: No PostgreSQL. Honker provides DB + pub/sub + queues in a single SQLite file (ADR-038, ADR-039).
- System/tenant DB split: Identity tables in
system.db, graph data intenant-{orgId}.db(ADR-040). - OperationSpecs as repository surface: Storage outputs
OperationSpec[]from table definitions. No hand-written CRUD. The consumer (hub/spoke) registers handlers (ADR-048). - HonkerEventTarget: Bridges pubsub
TypedEventTargetto Honkernotify/listenandstream/subscribe. Enables single-node pub/sub without Redis. Transactional outbox semantics confirmed via POC (ADR-047).
Commands
deno check mod.ts src/graphs/mod.ts src/sqlite/mod.ts # Type check
deno lint # Lint (slow-types, verbatim-module-syntax excluded)
deno task lint:analyze # Analyze lint issues by code/file grouping
deno fmt # Format
deno test --allow-all test/ # Run tests
deno publish --allow-slow-types --dry-run # Dry-run publish
Source Heritage
The graphs/ and sqlite/ modules were adapted from
@ade/ade-v0/packages/core/graphs and @ade/ade-v0/packages/storage_sqlite.
The codebase has diverged significantly from the originals:
- All schemas use
Type.Module()construction (notSchemaBuilder) Metagraph,CallGraph,SecretGraphare TypeBox Modules composing viaImport()andType.Composite()- Bridge functions (
moduleToDbSchema,validateNode,validateEdge) project Modules to DB row values - Crypto utility ported from
@alkdev/hub/src/crypto/mod.tswithEncryptedDataSchemaas a TypeBox schema @sinclair/typebox→@alkdev/typebox,drizzle-typebox→@alkdev/drizzlebox→ folded intosrc/sqlite/utils/(ADR-046)- TypeScript enums replaced with
as constobjects (GRAPH_STATUS,ACTOR_TYPE) Type.Unknown()used for unvalidated fields (notType.Any())- Injectable client pattern (
createSqliteDatabase(client)takes a pre-created client) - No module-level side effects or state
File Conventions
- All source files use
.tsextension with explicit extensions in imports (Deno convention) - Entry points are
mod.tsfiles that re-export from subdirectories - TypeBox schemas are named with PascalCase (
NodeType,GraphConfig) - Drizzle table objects are named with camelCase (
graphTypes,nodeTypes) - Schema objects from utils are named with PascalCase (
InsertGraph,SelectGraph) - Enum constants use
SCREAMING_SNAKE_CASEobjects (GRAPH_STATUS,ACTOR_TYPE)
Architecture Docs
See docs/architecture/ for detailed specifications:
overview.md— Package purpose, exports, database model, ecosystem integrationmetagraph-module.md— Graph type definitions as TypeBox Modules, data model, naming conventions, implementation pathhonker-integration.md— Drizzle-Honker adapter, event patterns, DB coordinationschema-evolution.md— How graph type schemas evolve, TypeBox Value.Diff/Patch/Cast for schema change detection and data migrationsqlite-host.md— SQLite tables (metagraph + identity), client factoriesencrypted-data.md— Encrypted data design, crypto utility, node type modelingforward-look.md— Connections to dbtype, graph pointers, ujsx universal IRacl.md— Access control graph, principal-agent framework, scoping
These docs describe what the package is AND what it's becoming. Items marked ⚠️ are not yet implemented.
What's Not Done Yet
- Fold dbtype Phase 0 →
src/sqlite/utils/(ADR-046, import path changes) - Drizzle-Honker session adapter (
src/sqlite/adapter.ts, POC validated) - HonkerEventTarget (
src/sqlite/event-target.ts, POC validated, ADR-047) - Identity tables in
src/sqlite/tables/identity/(accounts, organizations, etc.) - Scoping columns on
graphstable (ownerId,projectId) - Graph type
scopecolumn ongraph_typestable - Remove
actorstable andsrc/pg/directory - Update client factory to
createSystemDatabase()/createTenantDatabase()(accept Honker client) - Table restructure into subdirectories (metagraph/, identity/)
- OperationSpec generation from tables (ADR-048)
- ACL graph type (ADR-034)
- JSR publication setup (need to create scope/package on jsr.io first)