Skip to content

fix: build skill allowlist from session worktree, not stale base clone#1337

Open
Junveloper wants to merge 1 commit into
cyrusagents:mainfrom
Junveloper:fix/skill-allowlist-uses-session-worktree
Open

fix: build skill allowlist from session worktree, not stale base clone#1337
Junveloper wants to merge 1 commit into
cyrusagents:mainfrom
Junveloper:fix/skill-allowlist-uses-session-worktree

Conversation

@Junveloper

Copy link
Copy Markdown

Fixes #1336.

Problem

For single-repo (and GitHub-mention) agent sessions, the per-session skill allowlist is built by globbing .claude/skills/ in the base clone's working tree (repository.repositoryPath). Cyrus never advances that working tree — GitService.createSingleRepoWorktree only runs git fetch origin and cuts each worktree from origin/<baseBranch>. So the allowlist reflects a frozen snapshot of the repo from whenever it was registered, while the SDK loads the actual skill definitions from the fresh worktree (the session cwd, with settingSources: ["user","project","local"]).

Result: any repo-committed skill added to the base branch after the repo was registered is loaded and offered to the model by the SDK, but is absent from the allowlist, so invoking it fails with:

<tool_use_error>Skill <name> is not in this session's skills allowlist</tool_use_error>

This degrades silently over time — the longer a repo has been registered, the more of its newer skills are unusable. (Observed in the wild: a base clone 584 commits behind origin/main, with shipped/expose rejected even though both load fine in the worktree.)

This is the same class of bug as the recently-fixed setup/teardown hook discovery (CYPACK-1337, #1332) — reading from the persistent base checkout instead of the issue worktree.

Fix

EdgeWorker.resolveSkillRepoPaths now prefers the session's worktree path (workspace.path) — the same path the SDK uses as cwd — over repository.repositoryPath:

const repoPaths = session?.workspace?.repoPaths;
if (repoPaths) { /* multi-repo: per-repo sub-worktrees (unchanged) */ }

const worktreePath = session?.workspace?.path;
if (typeof worktreePath === "string" && worktreePath.length > 0) {
    return [worktreePath];
}
return [repository.repositoryPath]; // fallback: no workspace yet

The multi-repo branch already used worktree sub-paths from workspace.repoPaths — only the single-repo fallback was wrong. The repository.repositoryPath fallback is retained for the case where no session workspace exists yet.

Test plan (TDD)

Added packages/edge-worker/test/EdgeWorker.skill-repo-paths.test.ts:

  • single-repo → returns workspace.path (the worktree), not repository.repositoryPath (this assertion failed before the fix — confirmed RED → GREEN)
  • multi-repo → returns every workspace.repoPaths sub-worktree
  • no workspace → falls back to repository.repositoryPath

Verification:

  • New test: RED before the one-line behaviour change, GREEN after.
  • vitest run for the full edge-worker package: 724 passed (64 files).
  • tsc --noEmit (repo-wide typecheck via pre-commit pnpm -r typecheck): clean.
  • biome check: changed files clean (pre-existing repo warnings untouched).
  • CHANGELOG.md updated under ## [Unreleased] → ### Fixed.

Notes / out of scope

  • Repos already registered need their base clone refreshed once to pick up skills committed before this fix ships (or just re-register). Going forward, no manual refresh is needed.
  • A related gap (not addressed here to keep the change focused): the allowlist unions plugin + repo-local skills but not user-level ~/.claude/skills/, even though the SDK loads those via settingSources: "user". Skills kept only in ~/.claude/skills/ would still hit the allowlist error. Happy to follow up separately if desired.

@Junveloper Junveloper force-pushed the fix/skill-allowlist-uses-session-worktree branch from 9983fda to 057e4b3 Compare June 19, 2026 12:23
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.

Skill allow-list built from stale base-clone working tree, not the session worktree (repo skills rejected as "not in this session's skills allowlist")

1 participant