Skip to content

6.4: Keep worktrees, clones and working folders out of the shared cache - #81

Merged
NSchatz merged 1 commit into
mainfrom
6.4-private-working-copies
Oct 8, 2026
Merged

NSchatz merged 1 commit into
mainfrom
6.4-private-working-copies

Conversation

@NSchatz

@NSchatz NSchatz commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

What changed

#79 gave every container its own /state volume and moved databases and keys out of the shared /cache. A survey of one host's /cache afterwards found the same leak in other forms: worktrees and clones of private repositories, planning folders, keys a test generated, and a private term list kept out of git, all readable from every container because a tool or a repository's notes told sessions to work under /cache.

This PR documents that class and where it belongs, so new containers and tools stop recreating it:

  • claude-config/CLAUDE.md (the baked global notes): a worktree or clone of a repo, a planning folder or a test key is private too: /state/wt/<repo>/<branch> or /state/tmp if it must last, /scratch ($TMPDIR, cleared at boot) if not.
  • docs/volume-reference.md: the /cache row says never a worktree, a clone or a working folder; a new section "Worktrees, clones and working folders" with the move recipe. git worktree move cannot cross volumes (rename fails with "Invalid cross-device link"), so the recipe copies the worktree and runs git worktree repair from the main repository. When the main repository moves too, the repair must run where the old copies cannot be seen: while the old main repository exists, repair mends the old links instead of the new ones (both reproduced in a scratch repository, see below).
  • README.md: the private-state paragraph names worktrees and working folders.
  • test/state-unit.sh: pins the new CLAUDE.md line and the docs recipe.

No code path changes. The entrypoint's boot scan from #79 stays as it is: these folders are not named after a container, so a boot banner could not say whose they are, and a scan for git checkouts under /cache would also flag public tool clones.

Scope note: the moves and deletions on the owner's host, and the changes to the owner's own tools that wrote there, are the owner's steps, outside this repository.

How it was checked

  • bash test/state-unit.sh: state-unit: 51 passed, 0 failed (2 new checks).
  • npm run -s lint: check-no-emdash: OK, lint rc 0.
  • The unit suites one by one: compose-gen 39/0 (with PyYAML on PATH, as CI has), launch 43/0, gpu 65/0, egress-packages 93/0, mise 14/0, cache 36/0, manifest-hardening 44/0, pkg-install-guide OK, sessions 180/0, kit 57/0, state 51/0, keys 55/0, unit 260/0, workspace 29/0 (run with GIT_REPO_URL and GIT_REPOS unset; the session container sets them, and main fails the same 8 checks with them set).
  • The git behavior the docs rest on, in a scratch repository (git 2.x in the image):
    • git worktree move <wt> /scratch/... across mounts: fatal: failed to move ... Invalid cross-device link.
    • cp -a the worktree, git worktree repair <new> from the main repository: git worktree list shows the new path, an untracked file came along, and after rm -rf <old> plus git worktree prune the new one stays.
    • Main repository and worktree both copied, repair run while the old main still existed: it repaired the OLD links, and after the old copies were removed the new worktree was broken and pruned. With the old copies out of sight first, the repair linked both new copies and the uncommitted file survived.

https://claude.ai/code/session_01U97ssbeo9C37pqPiWMQ1BU

…ared cache

The shared /cache is readable from every container. Besides databases and keys, a
worktree or clone of a private repository, a planning folder, a generated test key or a
term list kept out of git is just as private. The baked CLAUDE.md, the README and
docs/volume-reference.md now say so and name the places: /state/wt/<repo>/<branch> and
/state/tmp for what must last, /scratch for throwaway work.

volume-reference.md also shows how to move a git worktree to /state: `git worktree move`
cannot cross volumes (rename fails with EXDEV), so copy it and run `git worktree repair`
from the main repository; when the main repository moves too, repair where the old copies
cannot be seen. state-unit.sh pins both.

Claude-Session: https://claude.ai/code/session_01U97ssbeo9C37pqPiWMQ1BU
@NSchatz
NSchatz merged commit 697f015 into main Oct 8, 2026
4 checks passed
@NSchatz
NSchatz deleted the 6.4-private-working-copies branch October 8, 2026 21:47
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.

1 participant