Skip to content

feat(core): replace @libsql/client with Kysely as unified DB layer#193

Merged
amondnet merged 16 commits intomainfrom
amondnet/northern-echium
Mar 24, 2026
Merged

feat(core): replace @libsql/client with Kysely as unified DB layer#193
amondnet merged 16 commits intomainfrom
amondnet/northern-echium

Conversation

@amondnet
Copy link
Copy Markdown
Contributor

@amondnet amondnet commented Mar 24, 2026

Summary

  • Replace raw @libsql/client SQL in packages/core/src/db.ts with Kysely typed query builder
  • Share a single Kysely<AppDatabase> instance between agent run history and Better Auth
  • Use @libsql/kysely-libsql LibsqlDialect for both local file and Turso cloud connections
  • Add Kysely Migrator with proper migration files (replacing inline CREATE TABLE)
  • Update Better Auth from bun:sqlite to shared Kysely instance via { db, type: 'sqlite' }

Supersedes tracks: libsql-turso-20260317, add-auth-20260321

Test plan

  • All 103 tests pass (bun run test)
  • Type check clean (bun run check)
  • Lint clean (bun run lint)
  • Manual: verify local libsql file DB works with agent-please run
  • Manual: verify Better Auth login works with shared Kysely instance
  • Manual: verify Turso cloud connection when configured

Summary by cubic

Replaced raw @libsql/client SQL with kysely as 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

    • New createKyselyDb returns Kysely<AppDatabase>; removed direct @libsql/client usage.
    • Added AppDatabase types and a migration for agent_runs; queries now use the typed builder.
    • Orchestrator uses Kysely and calls db.destroy() on shutdown; tests updated.
    • Better Auth now uses the shared Kysely instance (database: { db, type: 'sqlite' }); removed bun:sqlite. Auth plugin pulls the DB from the orchestrator and skips init if unavailable.
  • Migration

    • Kysely Migrator runs on startup; works with local files and Turso via db.turso_url and db.turso_auth_token.
    • Down migration drops indexes before the table; added a test for the migration failure path.
    • If the DB fails to init, auth is skipped and run history is disabled (service still starts).

Written for commit c38ecc2. Summary will update on new commits.

amondnet added 15 commits March 24, 2026 21:14
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.
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Warning

Gemini encountered an error creating the summary. You can try again by commenting /gemini summary.

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 24, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

- Add index drop before table drop in migration down()
- Add test for runMigrations failure path (destroyed connection)
@amondnet amondnet self-assigned this Mar 24, 2026
@sonarqubecloud
Copy link
Copy Markdown

@amondnet amondnet marked this pull request as ready for review March 24, 2026 14:20
@amondnet amondnet enabled auto-merge (squash) March 24, 2026 14:22
@amondnet amondnet merged commit 4502d38 into main Mar 24, 2026
6 checks passed
@amondnet amondnet deleted the amondnet/northern-echium branch March 24, 2026 14:22
@pleaeai-bot pleaeai-bot bot mentioned this pull request Mar 24, 2026
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.md and .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.md and .please/docs/research/md/003-prisma-orm-overview.md (id: 001 duplication), 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
Loading

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

@@ -0,0 +1,173 @@
---
id: 001
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
Suggested change
id: 001
id: 002
Fix with Cubic

@@ -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
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
Fix with Cubic


**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.
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
Fix with Cubic

@@ -0,0 +1,245 @@
---
id: 001
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
Suggested change
id: 001
id: 003
Fix with Cubic

@cubic-dev-ai cubic-dev-ai bot mentioned this pull request Mar 24, 2026
1 task
amondnet added a commit that referenced this pull request Mar 24, 2026
- 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
amondnet added a commit that referenced this pull request Mar 24, 2026
- 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
amondnet added a commit that referenced this pull request Mar 24, 2026
- 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant