Skip to content

Expose workspace env vars to project hooks; run cleanup on every worktree destruction#705

Merged
h0x91b merged 1 commit into
mainfrom
feat/workspace-lifecycle-hooks
Jun 27, 2026
Merged

Expose workspace env vars to project hooks; run cleanup on every worktree destruction#705
h0x91b merged 1 commit into
mainfrom
feat/workspace-lifecycle-hooks

Conversation

@ittaiz

@ittaiz ittaiz commented Jun 20, 2026

Copy link
Copy Markdown
Collaborator

Why

dev3's per-task git worktrees are a natural fit for per-worktree dev environments (each worktree gets its own backend/app container, ports, etc.). Tooling like Base44's b44 CLI already does this for Superset via a gitignored .superset/ hook folder (config.json + setup.sh + teardown.sh) that resolves its scripts from $SUPERSET_ROOT_PATH. dev3 already has the equivalent plumbing — setupScript / cleanupScript and root-first config resolution (.dev3/config.local.json at the repo root drives every worktree) — but two gaps stopped the same hooks from working here.

What

1. Workspace env vars for hook scripts. setupScript, devScript, and cleanupScript (and the agent session) now receive:

Var Value
DEV3_PROJECT_PATH Project root (the original repo checkout)
DEV3_PROJECT_NAME Project name
DEV3_TASK_ID Task UUID
DEV3_TASK_TITLE Task title
DEV3_WORKTREE_PATH This task's worktree dir
DEV3_BRANCH_NAME The task's git branch

DEV3_PROJECT_PATH is the load-bearing one (the analog of $SUPERSET_ROOT_PATH): a gitignored .dev3/config.local.json and any scripts it references live only at the project root, so a fresh worktree has no copy. Referencing a hook as bash "$DEV3_PROJECT_PATH/.dev3/setup.sh" lets every worktree find it while cwd stays the worktree. (The cleanup hook already had most of these; this centralizes them via a buildTaskLifecycleEnv helper and adds DEV3_BRANCH_NAME.)

2. Cleanup hook now fires on every worktree-destruction path. Previously cleanupScript ran only on completed / cancelled column moves. It now also runs when:

  • an active task is deletedDEV3_TASK_STATUS=deleted
  • task preparation is cancelled (reverts to To Do) → DEV3_TASK_STATUS=todo

Without this, deleting a task or cancelling its preparation tore down the worktree silently, leaking any per-worktree resources the setup hook had created (e.g. dev containers). Task deletion now also releases allocated ports and stops the dev-server session, both of which previously leaked on that path.

Docs updated: the embedded dev3-project-config skill gains a step documenting the hook env vars + the gitignored-hooks pattern, and the cleanup-script description is updated in all three locales.

Test instructions

bun install
bun run test          # full suite — 2,986 tests pass (1505 mainview + 1481 bun)
bun scripts/lint.ts   # TypeScript: no errors in src/

New unit tests cover: the deleted transition env, cleanup-runs-before-removeWorktree ordering on delete, cleanup-failure tolerance, port release on delete, and DEV3_BRANCH_NAME in the cleanup env.

…orktree destruction

Project hook scripts (setupScript / devScript / cleanupScript) now receive
DEV3_PROJECT_PATH, DEV3_PROJECT_NAME, DEV3_TASK_ID, DEV3_TASK_TITLE,
DEV3_WORKTREE_PATH and DEV3_BRANCH_NAME. DEV3_PROJECT_PATH is the
load-bearing one: a git-ignored .dev3/config.local.json exists only at the
project root, so hooks it references must be resolvable as
"$DEV3_PROJECT_PATH/.dev3/<hook>.sh" from inside a fresh worktree. This
mirrors the Superset workspace-hook contract (SUPERSET_ROOT_PATH /
SUPERSET_WORKSPACE_NAME / SUPERSET_WORKSPACE_PATH) so tooling like the b44
CLI can drive per-worktree environments on both runners with the same
scripts.

The cleanup hook now fires on every worktree-destruction path, not just
completed/cancelled column moves: deleting an active task runs it with
DEV3_TASK_STATUS=deleted, and cancelling task preparation runs it with
DEV3_TASK_STATUS=todo. Task deletion also releases allocated ports and
stops the task dev server (both previously leaked).

Docs updated: dev3-project-config skill (new step 3b documenting hook env
vars and the git-ignored-hooks pattern) and the cleanup script description
in all three locales.
@h0x91b h0x91b force-pushed the feat/workspace-lifecycle-hooks branch from 88eb28f to d45d078 Compare June 27, 2026 16:01

@h0x91b h0x91b left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Hey, Claude here — the AI assistant working on this branch with Arseny. Rebased onto latest main (was 27 commits behind, with conflicts in task-lifecycle.ts from the new virtual/Operations work). Resolved the conflicts to follow the same canonical teardown order main already uses in moveTask: runCleanupScript runs unconditionally (git + virtual), and only the dir removal is branched (git.removeWorktree vs managed rm). Backend suite is green (1616 passed) and lint is clean. Leaving the mainview test gate to CI. LGTM.

@h0x91b h0x91b enabled auto-merge (squash) June 27, 2026 16:01
@h0x91b h0x91b merged commit d63c10e into main Jun 27, 2026
4 checks passed
@h0x91b h0x91b deleted the feat/workspace-lifecycle-hooks branch June 27, 2026 16:02
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.

2 participants