From 3e2f7a7ddb82f48ae9c5416127c1dbca6252c67a Mon Sep 17 00:00:00 2001 From: Kevin Veen-Birkenbach Date: Tue, 3 Nov 2026 17:40:17 +0100 Subject: [PATCH] fix(transcend): skip repository copies in scratchpads A scan on the real host offered 4276 candidates, 4253 of them files of two repository copies in one peer's scratchpad. scratch_candidates now walks with os.walk, skips any directory holding .git, roles, plugins, pyproject.toml, package.json or a Makefile, and descends at most one level below a scratchpad; the real scan drops to 59 candidates. test_transcend adds a nested helper that stays, a deeper one and a repository copy that drop out (negative control against the unfiltered scan fails). Co-Authored-By: Claude Opus 5.5 --- skills/kvb-transcend/SKILL.md | 4 +++- skills/kvb-transcend/scripts/transcend.py | 22 +++++++++++++++++----- tests/test_transcend.py | 5 +++++ 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/skills/kvb-transcend/SKILL.md b/skills/kvb-transcend/SKILL.md index f3a0515..af585c0 100644 --- a/skills/kvb-transcend/SKILL.md +++ b/skills/kvb-transcend/SKILL.md @@ -19,7 +19,9 @@ transcend.py mark --state carried|dropped|later scratchpad, every peer session's scratchpad, and the agent homes (`~/.claude`, `~/.agents`, `~/.codex`) for skills, commands, agents, hooks and rules the skills repository does not ship. It keeps scripts, tests and -skills, and skips files named like secrets and files over 1 MB. Carried or +skills at most one directory below a scratchpad, and skips files named like +secrets, files over 1 MB, and repository copies (a directory holding `.git`, +`roles`, `plugins`, `pyproject.toml`, `package.json` or a `Makefile`). Carried or dropped candidates return only when their content changes; `later` returns every time. diff --git a/skills/kvb-transcend/scripts/transcend.py b/skills/kvb-transcend/scripts/transcend.py index 90e186d..6a35cf8 100755 --- a/skills/kvb-transcend/scripts/transcend.py +++ b/skills/kvb-transcend/scripts/transcend.py @@ -22,6 +22,8 @@ SECRET_NAME = re.compile( r"(secret|token|credential|passw|auth|\.env$|id_[a-z0-9]+$|\.pem$|\.key$)", re.IGNORECASE ) MAX_BYTES = 1_000_000 +MAX_DEPTH = 1 +REPO_MARKERS = {".git", "roles", "plugins", "pyproject.toml", "package.json", "Makefile"} HOME_SOURCES = { ".claude/skills": "skill", ".agents/skills": "skill", @@ -74,11 +76,21 @@ def session_names(home: Path) -> dict[str, str]: def scratch_candidates(root: Path, source: str, owner: str) -> list[dict]: found = [] - for path in sorted(p for p in root.rglob("*") if p.is_file()): - kind = file_kind(path) - if kind: - found.append({"source": source, "owner": owner, "kind": kind, "path": str(path)}) - return found + for current, dirs, files in os.walk(root): + here = Path(current) + depth = len(here.relative_to(root).parts) + if depth and REPO_MARKERS & {*dirs, *files}: + dirs.clear() + continue + if depth >= MAX_DEPTH: + dirs.clear() + for name in files: + kind = file_kind(here / name) + if kind: + found.append( + {"source": source, "owner": owner, "kind": kind, "path": str(here / name)} + ) + return sorted(found, key=lambda item: item["path"]) def shipped(skills_repo: Path) -> set[str]: diff --git a/tests/test_transcend.py b/tests/test_transcend.py index 55e6ee1..045f61c 100644 --- a/tests/test_transcend.py +++ b/tests/test_transcend.py @@ -40,6 +40,10 @@ class TestTranscend(unittest.TestCase): self._write(self.own / "auth_token.py", "secret") self._write(self.own / "big.py", "x" * 1_000_001) self._write(self.peer / "helper.sh", "echo hi") + self._write(self.peer / "probe" / "nested.py", "print(2)") + self._write(self.peer / "probe" / "deep" / "too_deep.py", "print(3)") + self._write(self.peer / "copy" / "pyproject.toml", "[project]") + self._write(self.peer / "copy" / "copied.py", "print(4)") for name in ("kvb-x", "caveman", "custom"): self._write(self.home / ".claude" / "skills" / name / "SKILL.md", name) self._write(self.home / ".codex" / "rules" / "default.rules", "allow") @@ -78,6 +82,7 @@ class TestTranscend(unittest.TestCase): "probe.py": ("own", "self", "script"), "test_probe.py": ("own", "self", "test"), "helper.sh": ("peer", "Peer", "script"), + "nested.py": ("peer", "Peer", "script"), "custom": ("home", "operator", "skill"), "default.rules": ("home", "operator", "rule"), },