feat(core): replace @libsql/client with Kysely as unified DB layer#193
feat(core): replace @libsql/client with Kysely as unified DB layer#193
Conversation
Add spec and plan for replacing @libsql/client with Kysely as the unified database layer. Shares a single Kysely instance between agent run history and Better Auth. Supersedes libsql-turso-20260317 and add-auth-20260321 tracks.
- T001: add kysely@0.28.14 and @libsql/kysely-libsql@0.4.1 to packages/core - Tests: passed [/please:implement]
- T002: add AgentRunsTable and AppDatabase interfaces in db-types.ts - Tests: passed [/please:implement]
- T003: create 001_create_agent_runs.ts with up/down using Kysely schema builder - Tests: passed [/please:implement]
- T004: replace @libsql/client with Kysely<AppDatabase> via LibsqlDialect
- createDbClient() → createKyselyDb() returning Kysely<AppDatabase> | null
- runMigrations() uses Kysely Migrator with MigrationProvider
- insertRun() uses db.insertInto('agent_runs').values(...).execute()
- queryRuns() uses db.selectFrom('agent_runs') with typed where/orderBy/limit/offset
- resolveDbPath(), InsertRunParams, QueryRunsOptions unchanged
- Tests: passed (orchestrator.ts/server.ts breakage resolved in T006/T007)
[/please:implement]
- T006: replace Client import with Kysely<AppDatabase>, use createKyselyDb(), and call db.destroy() instead of db.close() in stop() and migration failure path - Tests: passed [/please:implement]
- T007: server.ts already compatible with new queryRuns() Kysely signature - No Client import present; db passed directly without type annotation - Type check passes: bunx tsc --noEmit - Tests: passed [/please:implement]
- T005: replace createDbClient/Client with createKyselyDb/Kysely<AppDatabase> - replace client.close() with await db.destroy() - replace raw client.execute() SQL with Kysely query builder and sql tagged template - update seedRuns helper type to Kysely<AppDatabase> - Tests: passed [/please:implement]
- T010: replace dbPath construction with orchestrator.getDb() - Add null check for db before auth initialization - Remove unused 'node:path' resolve import - Tests: passed [/please:implement]
- T008: remove @libsql/client direct dependency (remains as transitive dep via @libsql/kysely-libsql) - T011: add AppDatabase, AgentRunsTable, createKyselyDb, runMigrations, insertRun, queryRuns, resolveDbPath to index.ts exports - Tests: passed [/please:implement]
- T009: change initAuth() to accept Kysely<any> instead of dbPath string
- Replace `import { Database } from 'bun:sqlite'` with `import type { Kysely } from 'kysely'`
- Use `database: { db, type: 'sqlite' as const }` for Better Auth Kysely adapter
- Add kysely and @libsql/kysely-libsql as dev deps for test helpers
- Update auth.test.ts to create in-memory Kysely instances via LibsqlDialect
- Tests: passed
[/please:implement]
Auto-fix import ordering and package.json key sorting.
|
Warning Gemini encountered an error creating the summary. You can try again by commenting |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
- Add index drop before table drop in migration down() - Add test for runMigrations failure path (destroyed connection)
|
There was a problem hiding this comment.
4 issues found across 24 files
Confidence score: 4/5
- This PR looks safe to merge overall, with low-risk issues limited to documentation/metadata rather than runtime behavior.
- The most impactful issue is stale architecture guidance in
.claude/agent-memory/please-please-code-explorer/project_db_layer_integration.mdand.claude/agent-memory/please-please-code-explorer/project_nitro_server_architecture.md, which could mislead future maintenance around the Kysely-based DB layer. - There are also frontmatter metadata collisions in
.please/docs/research/md/002-drizzle-orm-overview.mdand.please/docs/research/md/003-prisma-orm-overview.md(id: 001duplication), which should be corrected for doc consistency. - Pay close attention to
.claude/agent-memory/please-please-code-explorer/project_db_layer_integration.md,.claude/agent-memory/please-please-code-explorer/project_nitro_server_architecture.md,.please/docs/research/md/002-drizzle-orm-overview.md,.please/docs/research/md/003-prisma-orm-overview.md- update stale DB architecture references and make frontmatter IDs unique.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name=".please/docs/research/md/002-drizzle-orm-overview.md">
<violation number="1" location=".please/docs/research/md/002-drizzle-orm-overview.md:2">
P2: Use a unique frontmatter ID; this new file duplicates `id: 001` and should align with its `002-...` filename.</violation>
</file>
<file name=".claude/agent-memory/please-please-code-explorer/project_db_layer_integration.md">
<violation number="1" location=".claude/agent-memory/please-please-code-explorer/project_db_layer_integration.md:3">
P2: This new integration doc describes the old `@libsql/client` architecture instead of the Kysely-based DB layer introduced by this PR, so it is immediately stale and misleading.</violation>
</file>
<file name=".claude/agent-memory/please-please-code-explorer/project_nitro_server_architecture.md">
<violation number="1" location=".claude/agent-memory/please-please-code-explorer/project_nitro_server_architecture.md:19">
P2: The architecture note is outdated: auth no longer uses `bun:sqlite`; it now uses the shared Kysely DB. Update this line to avoid misleading future maintenance.</violation>
</file>
<file name=".please/docs/research/md/003-prisma-orm-overview.md">
<violation number="1" location=".please/docs/research/md/003-prisma-orm-overview.md:2">
P2: Use a unique frontmatter `id`; `id: 001` duplicates an existing research doc ID.</violation>
</file>
Architecture diagram
sequenceDiagram
participant Nitro as Nitro Server (App)
participant Orch as Orchestrator (Core)
participant DB as Kysely DB Layer
participant Mig as Kysely Migrator
participant Auth as Better Auth Service
participant Libsql as Libsql/Turso DB
Note over Nitro,Libsql: System Startup & Initialization
Nitro->>Orch: NEW: start()
Orch->>DB: NEW: createKyselyDb(config)
DB->>DB: Initialize LibsqlDialect
DB-->>Orch: Kysely<AppDatabase> instance
alt Migration Success
Orch->>Mig: NEW: runMigrations(db)
Mig->>Libsql: Apply 001_create_agent_runs
Libsql-->>Mig: Success
Mig-->>Orch: Migrated
else Migration Failure
Mig-->>Orch: Error
Orch->>Orch: Disable run history
end
Nitro->>Auth: NEW: initAuth(config, sharedKyselyDb)
Note right of Auth: Better Auth now uses shared<br/>Kysely instance (sqlite type)
Auth->>Libsql: Run Better Auth internal migrations
Auth-->>Nitro: Auth initialized
Note over Nitro,Libsql: Runtime: Agent Run History Flow
Orch->>Orch: onWorkerExit()
Orch->>DB: NEW: insertRun(db, runParams)
DB->>DB: Build typed insert query
DB->>Libsql: INSERT INTO agent_runs
Orch->>Orch: Track in pendingDbWrites
Note over Nitro,Libsql: Runtime: Data Access Flow
Nitro->>Orch: getDb()
Orch-->>Nitro: shared Kysely instance
Nitro->>DB: NEW: queryRuns(db, filters)
DB->>DB: Build typed select (where/limit/offset)
DB->>Libsql: SELECT FROM agent_runs
Libsql-->>DB: Rows
DB-->>Nitro: AgentRunRecord[]
Note over Nitro,Libsql: Shutdown
Nitro->>Orch: stop()
Orch->>Orch: await pendingDbWrites
Orch->>DB: NEW: db.destroy()
DB->>Libsql: Close connection
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| @@ -0,0 +1,173 @@ | |||
| --- | |||
| id: 001 | |||
There was a problem hiding this comment.
P2: Use a unique frontmatter ID; this new file duplicates id: 001 and should align with its 002-... filename.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .please/docs/research/md/002-drizzle-orm-overview.md, line 2:
<comment>Use a unique frontmatter ID; this new file duplicates `id: 001` and should align with its `002-...` filename.</comment>
<file context>
@@ -0,0 +1,173 @@
+---
+id: 001
+title: "Drizzle ORM — Supported Databases, Edge/Serverless, Bun, Migrations, Bundle Size"
+url: "https://orm.drizzle.team/docs/overview"
</file context>
| id: 001 | |
| id: 002 |
| @@ -0,0 +1,105 @@ | |||
| --- | |||
| name: db-layer-integration | |||
| description: Database layer architecture — DbConfig, createDbClient, insertRun, queryRuns integration points from config through orchestrator to HTTP API | |||
There was a problem hiding this comment.
P2: This new integration doc describes the old @libsql/client architecture instead of the Kysely-based DB layer introduced by this PR, so it is immediately stale and misleading.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .claude/agent-memory/please-please-code-explorer/project_db_layer_integration.md, line 3:
<comment>This new integration doc describes the old `@libsql/client` architecture instead of the Kysely-based DB layer introduced by this PR, so it is immediately stale and misleading.</comment>
<file context>
@@ -0,0 +1,105 @@
+---
+name: db-layer-integration
+description: Database layer architecture — DbConfig, createDbClient, insertRun, queryRuns integration points from config through orchestrator to HTTP API
+type: project
+---
</file context>
|
|
||
| **Server utils:** | ||
| - `server/utils/orchestrator.ts` — `useOrchestrator(event)` retrieves `nitroApp.orchestrator` via `useNitroApp()`, throws HTTP 503 if not initialized. | ||
| - `server/utils/auth.ts` — module-level singletons `_auth` and `_authEnabled`. Exports `initAuth()`, `useAuth()`, `isAuthEnabled()`, `resetAuth()`. Uses `better-auth` with `bun:sqlite`, supports GitHub OAuth + email/password + `admin` + `username` plugins. |
There was a problem hiding this comment.
P2: The architecture note is outdated: auth no longer uses bun:sqlite; it now uses the shared Kysely DB. Update this line to avoid misleading future maintenance.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .claude/agent-memory/please-please-code-explorer/project_nitro_server_architecture.md, line 19:
<comment>The architecture note is outdated: auth no longer uses `bun:sqlite`; it now uses the shared Kysely DB. Update this line to avoid misleading future maintenance.</comment>
<file context>
@@ -0,0 +1,36 @@
+
+**Server utils:**
+- `server/utils/orchestrator.ts` — `useOrchestrator(event)` retrieves `nitroApp.orchestrator` via `useNitroApp()`, throws HTTP 503 if not initialized.
+- `server/utils/auth.ts` — module-level singletons `_auth` and `_authEnabled`. Exports `initAuth()`, `useAuth()`, `isAuthEnabled()`, `resetAuth()`. Uses `better-auth` with `bun:sqlite`, supports GitHub OAuth + email/password + `admin` + `username` plugins.
+
+**API route structure:**
</file context>
| @@ -0,0 +1,245 @@ | |||
| --- | |||
| id: 001 | |||
There was a problem hiding this comment.
P2: Use a unique frontmatter id; id: 001 duplicates an existing research doc ID.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .please/docs/research/md/003-prisma-orm-overview.md, line 2:
<comment>Use a unique frontmatter `id`; `id: 001` duplicates an existing research doc ID.</comment>
<file context>
@@ -0,0 +1,245 @@
+---
+id: 001
+title: "Prisma ORM — Comprehensive Overview (Databases, Edge, Bun, Migrate, Performance)"
+url: "https://www.prisma.io/docs/orm/overview/introduction/what-is-prisma"
</file context>
| id: 001 | |
| id: 003 |
- Fix duplicate frontmatter IDs in research docs (002, 003 both had id: 001) - Update DB layer integration memory to reflect Kysely architecture - Update auth memory to reference shared Kysely DB instead of bun:sqlite Closes #195
- Fix duplicate frontmatter IDs in research docs (002, 003 both had id: 001) - Update DB layer integration memory to reflect Kysely architecture - Update auth memory to reference shared Kysely DB instead of bun:sqlite Closes #195
- Fix duplicate frontmatter IDs in research docs (002, 003 both had id: 001) - Update DB layer integration memory to reflect Kysely architecture - Update auth memory to reference shared Kysely DB instead of bun:sqlite Closes #195



Summary
@libsql/clientSQL inpackages/core/src/db.tswith Kysely typed query builderKysely<AppDatabase>instance between agent run history and Better Auth@libsql/kysely-libsqlLibsqlDialectfor both local file and Turso cloud connectionsMigratorwith proper migration files (replacing inlineCREATE TABLE)bun:sqliteto shared Kysely instance via{ db, type: 'sqlite' }Supersedes tracks:
libsql-turso-20260317,add-auth-20260321Test plan
bun run test)bun run check)bun run lint)agent-please runSummary by cubic
Replaced raw
@libsql/clientSQL withkyselyas a unified DB layer and shared one Kysely instance between run history and Better Auth. Added Kysely migrations (local file and Turso via@libsql/kysely-libsql), improved migration safety, and added internal docs and research notes.Refactors
createKyselyDbreturnsKysely<AppDatabase>; removed direct@libsql/clientusage.AppDatabasetypes and a migration foragent_runs; queries now use the typed builder.db.destroy()on shutdown; tests updated.database: { db, type: 'sqlite' }); removedbun:sqlite. Auth plugin pulls the DB from the orchestrator and skips init if unavailable.Migration
Migratorruns on startup; works with local files and Turso viadb.turso_urlanddb.turso_auth_token.Written for commit c38ecc2. Summary will update on new commits.