start-work.sh misreports a bare primary checkout as a dirty working tree
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 0
- Forks
- 1
- Avg merge
- 1d 3h
- Merged PRs (30d)
- 7
Description
Problem
plugins/start-work/scripts/start-work.sh refuses to run in any repository whose primary checkout is bare, with an error that names the wrong cause:
$ bash start-work.sh --slug "cloud-agent-standards-conformance" --id "525"
fatal: this operation must be run in a work tree
error: working tree is dirty. Commit, stash, or discard changes before starting new work.
fatal: this operation must be run in a work tree
The tree was clean. Nothing was dirty. The developer's only recourse is to work out that the message is false and fall back to git worktree add -b by hand — which is what happened in the session that found this.
Cause
In worktree mode the script deliberately resolves the primary checkout so the new worktree is not nested inside the current one:
REPO_ROOT="$(dirname "$(git rev-parse --path-format=absolute --git-common-dir)")"
cd "$REPO_ROOT"
It then runs the Git Hygiene clean-tree check there:
if ! git diff --quiet || ! git diff --cached --quiet; then
echo "error: working tree is dirty. ..." >&2
git status --short >&2
exit 1
fi
When the primary is bare (core.bare = true), git diff cannot run — it exits non-zero with fatal: this operation must be run in a work tree. The if ! reads that failure as "dirty" and aborts. The git status --short in the error path fails the same way, which is the second fatal: line and why the message has no file list under it.
This is not exotic: a bare primary with all work in linked worktrees under .claude/worktrees/ is a reasonable layout, and it is exactly the layout the worktree-first workflow encourages.
Why the check is misplaced
A bare repository has no working tree, so there is nothing for it to be dirty about. The tree that can actually be dirty in worktree mode is the one the developer is standing in — and that is not what gets checked today, even in the non-bare case.
Proposed fix
In worktree mode, run the clean-tree check against the current worktree (before the cd), not against the resolved primary — and skip it entirely if the current directory is not a working tree:
# Clean-tree check belongs to the tree the developer is in. The primary may be bare
# (no working tree at all), where `git diff` fails and would be misread as "dirty".
if git rev-parse --is-inside-work-tree >/dev/null 2>&1 &&
[ "$(git rev-parse --is-bare-repository)" != "true" ]; then
if ! git diff --quiet || ! git diff --cached --quiet; then
echo "error: working tree is dirty. Commit, stash, or discard changes before starting new work." >&2
git status --short >&2
exit 1
fi
fi
--no-worktree mode already cds to --show-toplevel, so it is unaffected either way.
Acceptance criteria
-
start-work.shsucceeds in a repo whose primary checkout is bare and whose current worktree is clean. - It still refuses, with the file list, when the current worktree has uncommitted or staged changes.
- It still refuses correctly in a conventional single-checkout repo (no behaviour change there).
-
--no-worktreemode is unchanged. - No error message ever claims "working tree is dirty" for a condition that is not a dirty tree — if the check cannot run, say that instead.
- A test covers the bare-primary case, since the failure is a wrong message rather than a crash and would otherwise regress silently.
Notes
Found while starting work in a repo laid out as a bare primary plus linked worktrees. The same topology causes two adjacent problems worth knowing about when testing this: core.hooksPath pinned to the primary's .githooks/ is frozen because nothing checks out into it, and the stale file set left at the primary root is still readable, so tooling that greps the primary path gets out-of-date content.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with plugins/start-work/scripts/start-work.sh and trace the worktree-mode path around REPO_ROOT and the Git Hygiene check. Reproduce the bare-primary case with the command shown, then add coverage for a clean current worktree, dirty current worktree, conventional checkout, and --no-worktree mode. Done means the checks target the current worktree, bare primaries do not produce a false dirty error, and the existing acceptance criteria hold.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- bash, git
- Domain
- cli, tooling
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100