Skip to content

fix(integrations-claude-code): resolve deleted subagent worktree cwd to parent repo bank - #3098

Open
valda wants to merge 1 commit into
vectorize-io:mainfrom
valda:fix/claude-code-deleted-worktree-bank
Open

fix(integrations-claude-code): resolve deleted subagent worktree cwd to parent repo bank#3098
valda wants to merge 1 commit into
vectorize-io:mainfrom
valda:fix/claude-code-deleted-worktree-bank

Conversation

@valda

@valda valda commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Fixes #3096

Problem

With project-scoped dynamic banks (dynamicBankId: true, dynamicBankGranularity: ["project"], resolveWorktrees: true), the async Stop retain hook can fire after an isolated Claude Code subagent worktree under <repo>/.claude/worktrees/agent-* has already been cleaned up. git -C <cwd> rev-parse --git-common-dir fails for the deleted path and _resolve_project_name() falls back directly to os.path.basename(cwd), silently creating orphan banks named after the generated worktree directory (e.g. agent-a33c4d636c3472e69) and fragmenting project memory away from the intended bank. Observed in production: one parent session produced 5 orphan agent-* banks, one of which accumulated 598 memory units (details in #3096).

Fix

Two changes to scripts/lib/bank.py:

  1. Extract git resolution into _project_name_from_git() and fix the common-dir parse. The old basename(dirname(git_common_dir)) assumed the common dir always ends in .git. For a submodule the common dir is <super>/.git/modules/<name>, so the resolver returned the meaningless name modules even for a live submodule cwd. The parse now handles:

    • regular repo / linked worktree: <repo>/.gitrepo (unchanged)
    • bare repo gitdir: <path>/repo.gitrepo (was: parent directory name)
    • submodule: <super>/.git/modules/<name><name> (was: modules)
  2. Retry from the nearest existing ancestor when the cwd is deleted. If (and only if) the supplied cwd no longer exists on disk, git resolution is retried once from the nearest existing ancestor, so a removed ephemeral workspace still resolves to its containing repository. This is generic — no hard-coding of .claude/worktrees. Live directories (including live non-git directories) keep the existing behavior unchanged; the basename fallback remains for deleted paths with no repository ancestor.

The submodule parse fix also makes the ancestor retry consistent: a deleted path under a live submodule now resolves to the same name a live cwd would produce.

Behavior note

Users who work inside git submodules will see their bank resolve to the submodule name instead of the previous (buggy) modules. This is a bug fix but technically a bank-id change for that configuration.

Tests

  • Mocked regression tests for the common-dir parse: submodule, nested submodule, bare repo gitdir.
  • Real-git regression tests (git init against tmp_path, no mocks) for the deleted-cwd path: deleted worktree under an existing repo resolves to the repo basename (also asserted end-to-end through derive_bank_id()), deleted path outside any repo keeps the basename fallback, and a live non-git directory is unaffected.

All 204 tests in hindsight-integrations/claude-code pass; ruff format --check clean with the shared ruff.toml.

Async Stop retain hooks can fire after an isolated Claude Code
subagent worktree under <repo>/.claude/worktrees/ has been cleaned
up. `git -C <cwd>` then fails and _resolve_project_name() fell back
to the leaf basename, silently creating orphan `agent-*` banks and
fragmenting project memory (observed: 5 orphan banks from one
session, one holding 598 memory units).

Two changes:

- Extract git resolution into _project_name_from_git() and fix the
  common-dir parse: a submodule's common dir is
  <super>/.git/modules/<name>, so the old dirname+basename parse
  returned the meaningless "modules"; bare repo gitdirs
  (<path>/repo.git) now strip the suffix instead of returning the
  parent directory name.

- When the cwd no longer exists on disk, retry git resolution once
  from the nearest existing ancestor so a deleted ephemeral
  workspace still resolves to its containing repository. Live
  directories keep the existing behavior unchanged.

Fixes vectorize-io#3096

Claude-Session: https://claude.ai/code/session_01WJjWcQmo1g8ctHYs7AWKGr
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.

Claude Code: deleted subagent worktrees create orphan agent-* banks

1 participant