From 5b130b25ef0825dca867e899753b36149801ef21 Mon Sep 17 00:00:00 2001 From: Ralf Heiringhoff Date: Wed, 22 Apr 2026 17:54:22 +0200 Subject: [PATCH] feat: add lockfile guard to /design and /plan MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /design and /plan commit directly to the base branch via `git add -A`, with no worktree isolation. If two sessions run these skills simultaneously, they race on the working tree. Both skills now acquire .beastmode/.worktree-lock (using shell noclobber for atomicity) before starting work, and release it after the checkpoint commit. If the lock exists, the session prints diagnostic info (PID, skill, timestamp) and stops. The lock file is transient and should be gitignored — see #559 for the skeleton .gitignore that will cover this. --- plugin/skills/design/SKILL.md | 30 ++++++++++++++++++++++++++++++ plugin/skills/plan/SKILL.md | 30 ++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/plugin/skills/design/SKILL.md b/plugin/skills/design/SKILL.md index 635bca75..e23dc804 100644 --- a/plugin/skills/design/SKILL.md +++ b/plugin/skills/design/SKILL.md @@ -18,6 +18,30 @@ Create PRDs through structured decision-tree interviews and collaborative dialog ## Phase 0: Pre-Execute +### 0. Acquire Worktree Lock + +Before any work, acquire the worktree lock to prevent parallel sessions from modifying the same branch. Design and plan commit directly to the base branch (no worktree), so concurrent sessions would race on `git add -A`. + +```bash +( set -C; echo "$$:design:$(date -Iseconds)" > .beastmode/.worktree-lock ) 2>/dev/null +``` + +If the lock file already exists (command fails), read it and STOP immediately: + +```bash +cat .beastmode/.worktree-lock +``` + +Print: + +``` +BLOCKED — another beastmode session is active on this branch. +Lock held by: +Wait for it to finish, or remove .beastmode/.worktree-lock if the session crashed. +``` + +STOP. Do not proceed. + ### 1. Problem-First Question Before exploring the codebase, ask the user what they are trying to solve. @@ -172,6 +196,12 @@ git add -A git commit -m "design(): checkpoint" ``` +Release the worktree lock: + +```bash +rm -f .beastmode/.worktree-lock +``` + Print: ``` diff --git a/plugin/skills/plan/SKILL.md b/plugin/skills/plan/SKILL.md index f91bcc21..267308a4 100644 --- a/plugin/skills/plan/SKILL.md +++ b/plugin/skills/plan/SKILL.md @@ -18,6 +18,30 @@ Decompose a PRD into independent feature plans. Each feature is a vertical slice ## Phase 1: Execute +### -1. Acquire Worktree Lock + +Before any work, acquire the worktree lock to prevent parallel sessions from modifying the same branch. Design and plan commit directly to the base branch (no worktree), so concurrent sessions would race on `git add -A`. + +```bash +( set -C; echo "$$:plan:$(date -Iseconds)" > .beastmode/.worktree-lock ) 2>/dev/null +``` + +If the lock file already exists (command fails), read it and STOP immediately: + +```bash +cat .beastmode/.worktree-lock +``` + +Print: + +``` +BLOCKED — another beastmode session is active on this branch. +Lock held by: +Wait for it to finish, or remove .beastmode/.worktree-lock if the session crashed. +``` + +STOP. Do not proceed. + ### 0. Check Research Trigger Research triggers if ANY: @@ -305,6 +329,12 @@ git add -A git commit -m "plan(): checkpoint" ``` +Release the worktree lock: + +```bash +rm -f .beastmode/.worktree-lock +``` + Print features and their implement commands: ```