entireio / entireio/cli

`entire disable` does not reach linked worktrees: settings.local.json is per worktree, so a new `git worktree add` comes back enabled

Open
#2,274 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Go
Stars
5.1k
Forks
475
Avg merge
1d 11h
Merged PRs (30d)
178

Description

Problem or use case

We roll Entire out per repository with a committed .entire/settings.json ("enabled": true) and let individual developers opt out with entire disable. That writes "enabled": false to .entire/settings.local.json, which is gitignored — so it exists only in the worktree it was written in.

Anyone who works with linked worktrees (git worktree add, or agents such as Claude Code that create worktrees on their own) gets re-enabled every time a worktree is created: the new checkout carries only the committed settings.json, settings.Load finds no local override, and every agent hook and git hook starts recording again. The developer has to notice and run entire disable in each worktree.

Reproduced on 0.10.2 and current main:

tmp=$(mktemp -d)
git init -q -b main "$tmp/main" && cd "$tmp/main"
mkdir .entire && printf '{"enabled": true}\n' > .entire/settings.json
printf 'settings.local.json\n' > .entire/.gitignore
git add -A && git commit -qm init

entire disable            # -> Entire is now disabled (.entire/settings.local.json).
git worktree add -q "$tmp/wt" -b feature
cd "$tmp/wt" && entire status --json
# {"enabled":true, ...}   <- expected "enabled":false

What we checked before filing:

  • Clone preferences (.git/entire/preferences.json) already live in the git common dir so that "multiple worktrees of the same clone see the same preferences", but they carry only review/trails keys, not enabled.
  • The docs mention a global ~/.config/entire/settings.json; settings.Load has no such layer, and an "enabled": false there (also via ENTIRE_CONFIG_DIR) has no effect.
  • There is no environment variable that disables Entire.
  • A settings.local.json symlinked to a file outside .entire is refused (path escapes from parent), so a per-developer shared file is not a workaround either.
  • No existing issue covers this; #2020 is the closest (Codex hooks installed per worktree) and #645 (stealth mode) is adjacent but a different ask.
Desired behavior
$ entire disable
Entire is now disabled (.entire/settings.local.json).
$ git worktree add ../wt -b feature && cd ../wt
$ entire status
○ Disabled · branch feature

A personal opt-out made in one worktree applies to every worktree of that clone, without touching the committed settings.json and without a per-worktree step.

Proposed solution

Mirror the local-scope enabled flag into clone preferences, which is the layer designed to span worktrees:

  • ClonePreferences gains enabled *bool; applyClonePreferences applies it, so the merge order becomes settings.json → clone preferences → settings.local.json (the local file still wins, as documented).
  • entire disable / entire enable (local scope) write the flag to both settings.local.json (unchanged, keeps IsSetUpAny and older binaries working) and .git/entire/preferences.json.
  • entire enable --project re-syncs the mirror only when it was set — the same rule the project → local sync already follows — so a clone that never made a personal choice keeps the committed file as its only source of truth.
  • The "already enabled" short-circuit in runEnableOnConfiguredRepo treats a clone-wide false as an explicit local disable, so entire enable can recover a worktree whose own local file says true.
  • entire status --detailed shows a Clone · enabled|disabled line between Project and Local.

Known edge: a worktree that carries its own settings.local.json with "enabled": false keeps that answer until entire enable runs there, because the local file is the most specific layer. That matches today's layering and only affects worktrees that were disabled individually before this change.

I have this implemented with unit tests (including a linked-worktree test) and can open a PR once the direction is agreed.

Alternatives or workarounds

We currently ship a post-checkout git hook in the repository (core.hooksPath=.githooks) that copies the main worktree's .entire/settings.local.json into a freshly created worktree (git worktree add runs post-checkout with a zero previous HEAD from inside the new worktree). It works, but it is repo-specific plumbing every team would have to rediscover, and it only helps repositories that already manage hooks this way.

Other options considered: a user-level enabled (would need a new global settings layer and would still lose to a committed "enabled": true under "more specific wins"), an ENTIRE_DISABLED environment variable (per shell, not per clone), and removing entire from PATH (the SessionStart hook then prints an install warning on every session).

CLI version: 0.10.2 (macOS, arm64); reproduced against main at 61dac01. Go 1.26.6.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with settings.Load, ClonePreferences, and applyClonePreferences to trace the settings merge order and shared worktree preferences. Then inspect entire enable/disable, enable --project, status --detailed, and runEnableOnConfiguredRepo, and run the existing unit tests including the linked-worktree case. Done means a local disable applies to new worktrees while local settings still take precedence.

Written by the indexing model from the issue text.

Assessment

Tech stack
git, go
Domain
cli, developer-experience
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.