Skip to content

Worktree default: shared agent instructions contradict this fork's intended workflow #36

Description

@asktt1770

Gated on #34. Re-check once the upstream sync merges. Verified against the #34 tree
(origin/chore/upstream-sync-2026-08-14): both files below are still byte-identical to
upstream/main there, and our fork-only CLAUDE.md section still survives — so the merge
does not resolve this.

Related: #35 (follow-ups from the same sync).

What happened

Observed in asktt1770/nix-hermes-agent, session of 2026-09-08 (darwin, Claude Code / Opus 5).

An assistant session produced 8 commits, one merge, and two pull requests while working
directly in the main worktree, and edited main in place before being asked to move to a
topic branch. The stated expectation, once it surfaced, was that implementation work happens in
a linked worktree by default.

Why the assistant did not create one

This is a conflict between the documented default and the intended default — not a lapse in
following instructions. Two fragments load into every session and both say the main worktree is
a valid place to work:

agents/shared/git-worktrees.md:9-10

- Use the `git-wt` skill only when a worktree lifecycle operation is actually
  needed

agents/skills/git-wt/SKILL.md:21-27

Different paths mean the current directory is already inside a linked
worktree. Continue in that worktree unless the user explicitly requests a
different one. Do not create or select another worktree merely to satisfy an
isolation convention.

Equal paths mean the current directory is the main worktree. Create or select
a linked worktree only when the task or user actually requires isolation.

The detection step ran correctly and returned "this is the main worktree"; the rule then said
that was acceptable. Any remedy consisting of restating the expectation in prose will be read
alongside these two fragments, which contradict it.

Upstream context — this shapes the remedy

Both files are byte-identical to upstream/main; there is currently zero fork divergence in
either:

$ git diff upstream/main -- agents/shared/git-worktrees.md agents/skills/git-wt/SKILL.md
$   # no output

The wording is deliberate upstream, not an accident:

830d019c fix(agents): avoid redundant worktree setup   (2026-06-20)

  Compare the Git directory and common directory before invoking git-wt.
  This identifies an existing linked worktree before isolation begins.
  Keep agents there unless the user explicitly requests a lifecycle
  operation. This prevents redundant selection in Codex Desktop and
  similar environments.

Upstream is solving the mirror image of our problem. Their agents start inside a linked
worktree (Codex Desktop and similar), so an instruction to create one for isolation produced
redundant nesting. Our sessions start in the main worktree. The same text, through the same
detection logic, reaches the opposite conclusion. The text is correct for upstream and wrong for
us, so it cannot be fixed by reporting it upstream.

Two further facts:

  • Upstream has no worktree enforcement at all. No hooks in nix/; upstream's repo-level
    .claude/settings.json contains only a nix run .#fmt PostToolUse hook. The rule is
    instruction-only everywhere.
  • Upstream's root CLAUDE.md has no "Worktree Workflow" section. Ours (CLAUDE.md:103) is a
    fork-only addition and is the single place the intended default is written down. It wins here
    and loses in every repository that does not repeat it — which is how nix-hermes-agent
    behaved as it did.

Open decisions

Left open deliberately; to be settled with the post-merge files in front of us.

  • Channel. Editing agents/shared/ or agents/skills/git-wt/ reintroduces divergence in
    files that are currently clean, against the "keep the upstream diff minimal" policy in
    CLAUDE.md, and upstream will keep touching them. Alternatives: a fork-only file under
    claude/rules/ (loaded globally via ~/.config/claude/rules/, zero upstream conflict
    surface), or leaving it per-repository in .claude/.
  • Precedence. A fork-only rules file loads alongside the shared fragments, not after them
    in any guaranteed order, so it has to override them explicitly in its wording rather than
    relying on position.
  • Reach. claude/rules/ is Claude Code only. ~/.codex/AGENTS.md is generated from
    agents/shared/ alone, so anything meant to reach Codex needs codex/AGENTS.md too.
  • Mechanism. EnterWorktree (Claude Code harness tool, used by our CLAUDE.md) vs git wt
    (used by the shared fragment). EnterWorktree cannot live in agents/shared/ because Codex
    has no such tool.
  • Instruction vs enforcement. If a hook is added, where it blocks matters: at edit time
    (Edit/Write) it catches everything but fires on legitimate main-worktree work; at commit/PR
    time it guards only the irreversible step. Note this repo explicitly permits committing
    directly to main, so any mechanical block needs a per-repository opt-out.
  • Escape hatch strength. Somewhere the assistant can write (shows up in a diff, reviewable)
    vs somewhere it cannot (an env var set when launching claude). A marker file would repeat the
    weakness tracked separately in the codex-review gate issue.
  • Rebuild boundary. agents/shared/ and claude/rules/ are out-of-store symlinks and can be
    iterated on live; hooks in nix/modules/home/programs/claude-code/default.nix need a rebuild.

Secondary observation

git-wt itself worked without incident once invoked. git wt --nocd <branch> created
.wt/<branch>/ inside the repo, and that directory does not appear in git status in the main
tree, so no .gitignore entry was needed. wt.remover is set to trash-cli; wt.basedir is
unset, so worktrees land under the repository.

Reproducing

# the two fragments that set the default
$ bat agents/shared/git-worktrees.md
$ sed -n '20,30p' agents/skills/git-wt/SKILL.md

# what the detection step returns in a main worktree
$ git rev-parse --path-format=absolute --git-dir
$ git rev-parse --path-format=absolute --git-common-dir   # equal => main worktree

# confirm the files are still pristine upstream
$ git diff upstream/main -- agents/shared/git-worktrees.md agents/skills/git-wt/SKILL.md

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentation

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions