Skip to content

Comments

feat(worktree): add per-task DB target env#941

Open
naaa760 wants to merge 1 commit intogeneralaction:mainfrom
naaa760:feat/per-wrk-app-datb-trg-isol-test
Open

feat(worktree): add per-task DB target env#941
naaa760 wants to merge 1 commit intogeneralaction:mainfrom
naaa760:feat/per-wrk-app-datb-trg-isol-test

Conversation

@naaa760
Copy link
Contributor

@naaa760 naaa760 commented Feb 18, 2026

add per-worktree database target configuration

  • Enables configuring a database target per worktree/task for isolated testing.

Problem

  • Multiple worktrees share the same DATABASE_URL, causing cross-worktree data interference during parallel testing.

Solution

  • Added db_target column to tasks table
  • Added "DB target" field in task creation (Advanced options)
  • Injects DATABASE_URL, DB_NAME, DB_PROFILE into terminals/agents
  • Shows active DB target badge in task header
  • Fixed DB env vars not being passed to direct-spawn agents

Usage

  • Create task → Advanced options → Enter DB target → Injected automatically

Backward compatibility

  • Existing tasks work without changes
  • dbTarget is optional
  • No breaking changes

fix : #935

Co-authored-by: Cursor <cursoragent@cursor.com>
@vercel
Copy link

vercel bot commented Feb 18, 2026

@naaa760 is attempting to deploy a commit to the General Action Team on Vercel.

A member of the Team first needs to authorize it.

@greptile-apps
Copy link

greptile-apps bot commented Feb 18, 2026

Greptile Summary

This PR adds per-task database target configuration to worktrees, allowing each task to have its own DATABASE_URL, DB_NAME, and DB_PROFILE environment variables injected into terminals and agents. The feature is optional and backward-compatible.

  • Adds db_target column to the tasks table schema and a "DB target" textarea in the task creation modal's advanced settings
  • Parses dbTarget as either a JSON object ({url, name, profile}) or a plain connection string, then injects the appropriate env vars (DATABASE_URL/DB_URL, DB_NAME/DATABASE_NAME, DB_PROFILE/DATABASE_PROFILE)
  • Updates the PTY manager's env var forwarding allowlist to pass DB-related vars through SSH and direct-spawn paths
  • Shows a "DB: ..." badge in the task header when a target is configured
  • Critical issue: The migration file drizzle/0010_add_db_target_to_tasks.sql was manually created without drizzle-kit generate — it has no corresponding entry in _journal.json or snapshot in drizzle/meta/, which means Drizzle's migration runner will not execute it and the column will never be added to existing databases

Confidence Score: 2/5

  • The migration is broken — do not merge without regenerating it via drizzle-kit generate.
  • The core feature logic is well-implemented and backward-compatible, but the manually created migration file without journal/snapshot metadata means the database column will never be applied to existing installations. This is a blocking issue that would cause runtime failures when tasks with dbTarget are saved.
  • drizzle/0010_add_db_target_to_tasks.sql — missing journal entry and snapshot; src/main/services/worktreeIpc.ts — ad-hoc dbTarget on untyped worktree response

Important Files Changed

Filename Overview
drizzle/0010_add_db_target_to_tasks.sql Manually created migration file with no corresponding journal entry or snapshot in drizzle/meta/. This violates the project's critical rule to always use drizzle-kit generate for migrations.
src/main/db/schema.ts Adds dbTarget text column to tasks table. Schema change is correct and the column is properly nullable for backward compatibility.
src/main/services/DatabaseService.ts Adds dbTarget to saveTask with careful backward-compatible handling using hasOwnProperty check, and maps it in task row retrieval.
src/main/services/TaskLifecycleService.ts Adds DB lookup in buildLifecycleEnv to pass dbTarget into getTaskEnvVars. Introduces an extra async DB call on every lifecycle env build.
src/main/services/ptyManager.ts Adds DB-related env vars to the PTY forwarding allowlist for SSH and direct spawn paths. Clean implementation using a Set-based check.
src/main/services/worktreeIpc.ts Passes dbTarget through worktree creation by spreading it onto the worktree response object. Ad-hoc approach since WorktreeInfo doesn't have a dbTarget field.
src/renderer/components/ChatInterface.tsx Adds dbTarget to env vars computation and displays a DB target badge in the task header. Uses React's auto-escaping for user input safely.
src/renderer/components/TaskAdvancedSettings.tsx Adds "DB target" textarea field in advanced settings with clear placeholder and description. Follows existing UI patterns.
src/renderer/lib/taskCreationService.ts Threads dbTarget through both single-agent and multi-agent task creation flows, persisting it to DB and worktree creation.
src/shared/task/envVars.ts Core logic for parsing dbTarget (JSON or plain string) and injecting DATABASE_URL, DB_URL, DB_NAME, DATABASE_NAME, DB_PROFILE, DATABASE_PROFILE env vars.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["TaskModal\n(user enters dbTarget)"] --> B["taskCreationService\n(passes dbTarget to IPC)"]
    B --> C{"Use worktree?"}
    C -- Yes --> D["worktreeIpc\n(worktree:create)"]
    D --> E["WorktreeService\ncreateWorktree"]
    E --> F["Return worktree + dbTarget"]
    C -- No --> F2["Use project path directly"]
    F --> G["DatabaseService.saveTask\n(persist dbTarget to DB)"]
    F2 --> G
    G --> H["Task activated in UI"]
    H --> I["getTaskEnvVars\n(parseDbTarget)"]
    I --> J{"JSON or\nplain string?"}
    J -- JSON --> K["Extract url, name, profile"]
    J -- Plain string --> L["Treat as url"]
    K --> M["Set DATABASE_URL, DB_URL,\nDB_NAME, DATABASE_NAME,\nDB_PROFILE, DATABASE_PROFILE"]
    L --> M
    M --> N["PTY Manager\n(shouldForwardTaskEnvVar)"]
    N --> O["Terminal / Agent Process"]
Loading

Last reviewed commit: 2c51390

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

18 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +1 to +2
ALTER TABLE `tasks` ADD COLUMN `db_target` text;
--> statement-breakpoint
Copy link

Choose a reason for hiding this comment

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

Manually created migration file

This migration file was created manually without running drizzle-kit generate. The drizzle/meta/_journal.json has no entry for 0010_add_db_target_to_tasks (it stops at idx 9 / 0009_add_ssh_support), and there is no corresponding snapshot file in drizzle/meta/.

Per the project's critical rules in CLAUDE.md: "NEVER modify drizzle/meta/ or numbered migration files — always use drizzle-kit generate". While this rule focuses on modifying existing files, the intended workflow is to always generate migrations via drizzle-kit generate after modifying schema.ts. A hand-written migration without the journal/snapshot metadata will cause Drizzle's migration runner to skip this file, meaning the db_target column will never be added to existing databases.

Please run pnpm exec drizzle-kit generate after the schema change to produce a properly tracked migration.

Context Used: Context from dashboard - CLAUDE.md (source)

Comment on lines +17 to 30
function parseDbTarget(dbTarget: string | null | undefined): DbTargetConfig | null {
if (!dbTarget) return null;

try {
const parsed = JSON.parse(dbTarget);
if (typeof parsed === 'object' && parsed !== null) {
return parsed as DbTargetConfig;
}
} catch {
return { url: dbTarget };
}

return null;
}
Copy link

Choose a reason for hiding this comment

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

Valid JSON object parsed as string falls through silently

When the input is a valid JSON value that is not an object (e.g., a JSON array ["a","b"] or a JSON number 42), JSON.parse succeeds but the typeof parsed === 'object' check passes for arrays (since typeof [] === 'object'). An array input would be cast to DbTargetConfig and then properties like .url would be undefined, causing silent no-op behavior. Consider adding an !Array.isArray(parsed) check:

Suggested change
function parseDbTarget(dbTarget: string | null | undefined): DbTargetConfig | null {
if (!dbTarget) return null;
try {
const parsed = JSON.parse(dbTarget);
if (typeof parsed === 'object' && parsed !== null) {
return parsed as DbTargetConfig;
}
} catch {
return { url: dbTarget };
}
return null;
}
function parseDbTarget(dbTarget: string | null | undefined): DbTargetConfig | null {
if (!dbTarget) return null;
try {
const parsed = JSON.parse(dbTarget);
if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) {
return parsed as DbTargetConfig;
}
} catch {
return { url: dbTarget };
}
return null;
}

args.baseRef
);
return { success: true, worktree };
return { success: true, worktree: { ...worktree, dbTarget: args.dbTarget ?? null } };
Copy link

Choose a reason for hiding this comment

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

dbTarget not persisted to task in worktreeIpc

For the local (non-remote) worktree creation path, dbTarget is spread onto the returned worktree object as an ad-hoc property ({ ...worktree, dbTarget: args.dbTarget ?? null }). The WorktreeInfo interface returned by worktreeService.createWorktree() does not include dbTarget, so this relies on the untyped worktree?: any return type in the IPC definition.

This works at runtime because taskCreationService.ts reads worktree.dbTarget from the response, but it's fragile — if WorktreeInfo is ever typed more strictly at the IPC boundary, this will silently break. Consider either adding dbTarget to WorktreeInfo or documenting that this field is only passed through via the IPC response (not a worktree property).

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

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.

[feat]: per-worktree app database target for isolated testing

1 participant