Skip to content

lifeos: stop a --local launch from the main checkout when worktrees are in use#1579

Closed
asdf8675309 wants to merge 1 commit into
danielmiessler:mainfrom
asdf8675309:fix/lifeos-worktree-launch-guard
Closed

lifeos: stop a --local launch from the main checkout when worktrees are in use#1579
asdf8675309 wants to merge 1 commit into
danielmiessler:mainfrom
asdf8675309:fix/lifeos-worktree-launch-guard

Conversation

@asdf8675309

Copy link
Copy Markdown
Contributor

What

'lifeos --local' starts a session wherever you are. If that's a repo's main checkout and the repo uses .claude/worktrees, the whole session runs on whatever branch the root is parked on — usually not what you meant. Easy footgun if you live in worktrees.

Change

One file. New inMainCheckoutWithWorktrees() (exported). It's plain git: when --git-dir and --git-common-dir match, you're in the main checkout, not a worktree; then it just checks for a .claude/worktrees dir. No version-specific flags, so it works on any git. When it's true, --local refuses with a clear message. Set LIFEOS_ALLOW_ROOT=1 to override.

Why it's safe

It only fires in one spot: --local, from a main checkout, in a repo that actually has .claude/worktrees, with the override off. Anything unexpected falls through to false and the launch proceeds — it never blocks you without an escape hatch, and it touches nothing outside --local. Not a git repo? Returns false, no-op.

Verification

Tested on macOS, Bun 1.3.14.

| context | inMainCheckoutWithWorktrees() | --local | |---------|-------------------------------|---------| | not a git repo | false | proceeds |
| main checkout, no .claude/worktrees | false | proceeds | | linked worktree (git-dir != git-common-dir) | false | proceeds | | main checkout WITH .claude/worktrees | true | refuses unless LIFEOS_ALLOW_ROOT=1 |

Scope

Just lifeos.ts, just the --local path. No new dependency. Nothing changes for non-worktree repos or for normal worktree launches.

…re in use

## What
'lifeos --local' starts a session wherever you are. If that's a repo's main
checkout and the repo uses .claude/worktrees, the whole session runs on whatever
branch the root is parked on — usually not what you meant. Easy footgun if you
live in worktrees.

## Change
One file. New inMainCheckoutWithWorktrees() (exported). It's plain git: when
--git-dir and --git-common-dir match, you're in the main checkout, not a
worktree; then it just checks for a .claude/worktrees dir. No version-specific
flags, so it works on any git. When it's true, --local refuses with a clear
message. Set LIFEOS_ALLOW_ROOT=1 to override.

## Why it's safe
It only fires in one spot: --local, from a main checkout, in a repo that actually
has .claude/worktrees, with the override off. Anything unexpected falls through
to false and the launch proceeds — it never blocks you without an escape hatch,
and it touches nothing outside --local. Not a git repo? Returns false, no-op.

## Verification
Tested on macOS, Bun 1.3.14.

| context | inMainCheckoutWithWorktrees() | --local |
|---------|-------------------------------|---------|
| not a git repo | false | proceeds |
| main checkout, no .claude/worktrees | false | proceeds |
| linked worktree (git-dir != git-common-dir) | false | proceeds |
| main checkout WITH .claude/worktrees | true | refuses unless LIFEOS_ALLOW_ROOT=1 |

## Scope
Just lifeos.ts, just the --local path. No new dependency. Nothing changes for
non-worktree repos or for normal worktree launches.

Co-authored-by: Claude <noreply@anthropic.com>
@danielmiessler

Copy link
Copy Markdown
Owner

Ported with credit — and porting it caught a real edge worth handing back: the harness creates an EMPTY .claude/worktrees dir as a side effect of one-off agent isolation (our own install has one), and the as-submitted check would have locked --local out of the main checkout there. The ported version requires the dir to be non-empty — "worktrees in use" literally. Verified across five contexts: non-git, main-without-worktrees, main-with-empty-dir, and inside-a-linked-worktree all proceed; main-with-populated-worktrees refuses. (Closing rather than merging — the public repo is generated from private source; the port ships next release.)

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