Repository navigation
fix(daemon): install a placed session's skills into its checkout - #2801
Conversation
A session placed on another daemon got its skills from reconcileClusterSkills without a cwd, so the executor's shim installed them at its own root: the session directory, one level above the checkout. Runtimes scan for project skills from their cwd up to the repository root only, so neither Codex nor Claude listed them, and agents told to use a skill guessed paths that do not exist. The executor plane's skill client now aims requests at the runtime's cwd, as the microsandbox path already does; installs there keep their own ledger key, and the bundles are recorded in the checkout's info/exclude through the executor's plane.
There was a problem hiding this comment.
Reviewed revision 21bb47c28e8bc8c9b30a88d715765ee4639a92e2. No new blocking issues found. The prepared cwd is carried through the skill requests, receipts use a separate cwd-specific key while retaining the launch fence, and Git exclusions are written through the executor’s filesystem. Pool behavior remains unchanged.
Validation: git diff --check passed. Focused tests were not executed locally: the fresh checkout required a full dependency installation, which I stopped after slow progress. CI was still running at review time.
sent by review-bot (Codex · gpt-6-astra) · open in session
…st path rules The workspace manager joins every placed path with node:path, so on Windows the exclude file path uses backslashes; the test now expects what the manager composes.
There was a problem hiding this comment.
Reviewed revision 49540a49c2b7f562effd22a27978d06ddd6c4fdc. No new blocking issues found. The only change since the previously approved revision uses path.join consistently in the Git-exclusion test fixture, making its expected filesystem paths match the host’s path rules.
Validation: git diff --check and focused Node assertions using both POSIX and Windows path semantics passed. The full test suite was not rerun locally; CI is still running.
sent by review-bot (Codex · gpt-6-astra) · open in session
…ectory (#2804) Since #2801 a placed session installs its skills into its checkout under a ledger of their own. Bundles an earlier daemon installed at the session directory stayed there under the old ledger, which nothing read again, so a skill revoked or removed later was never deleted from disk. After installing into the checkout, the placed path now reconciles that earlier ledger to nothing through the shim's own root. A failure is logged and retried at the next preparation; it does not fail the launch. Tests: a daemon-level test of the placed path (installs aimed at the cwd under the cwd ledger key, the exclude call, the retirement and its retry), and the exclude test now refuses an agent-wide filesystem. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Problem
A session placed on another daemon in its group never sees its installed skills. That covers both runtimes we
checked, Codex and Claude. An agent whose instructions name a skill then guesses a path:
It looks intermittent because it depends on placement. The same agent, runtime and release behave differently:
agents/<agent>/sessions/<leaf>/workspace/.agents/skills(inside the checkout)executor: session … runs on daemon …)sessions/<leaf>/.agents/skills(above the checkout)Measured on two Linux VM daemons in one group, 2.2.0-rc.43:
<leaf>/workspace, a git clone, and Codex scans.agents/skills"in every directory from your current workingdirectory up to the repository root", which here is
workspace/. In 3 sessions the model found the skills onlyby searching the disk after the guess failed.
installed in
<leaf>/.claude/skillsappear.Cause
runAgentWorkspacePreparationprepares a placed session's checkout (cwd = prepareExecutorWorkspace(…)), thencalls
reconcileClusterSkills(agent, placed.subject, plane)without that cwd.ExecutorPlane.skillClientForsendsbare
skillsrequests, so the executor's shim installs at its own workspace root, which is the session directory.The microsandbox path already aims the same shim at the runtime's cwd (
microsandboxSkillTargetsends{ cwd, request }), and the daemon-local path installs into the cwd too.Change
ExecutorPlane.skillClientFor(subject, cwd?)wraps requests as{ cwd, request }when given a cwd.cwdSkillRequesterinshim/skill-client.tsis shared withmicrosandboxSkillTarget, so the two stay oneshape. The shim side already supports this, including refusing a cwd that escapes its root
(
shim-exec-handler.test.ts).reconcileClusterSkillstakes an optional cwd and returns the ledger. The placed path passes the prepared cwd.cwdWorkspaceIncarnation(reported, cwd), so receipts recorded at the session directory are never read againstthe checkout. Missing prior bundles are already skipped, but a receipt whose path the repository tracks would
fail the safety check. The launch fence still compares the incarnation the executor reported.
.agentconnect/cluster-skill-statego into the checkout'sinfo/excludethrough the executor's plane (
excludePlacedSessionSkills), as the local and microsandbox paths do, so a placedcheckout does not report them in
git statusor pin the retention GC.withSkillskeeps its off-disk guardunchanged for pool pods, whose bundles stay outside the checkout.
session-executors.md: skills are published into the session's checkout.Pool pods (
K8sRuntimePlane) are unchanged: they pass no cwd.Tests
executor-plane.test.ts› "the skills a placed session installs":{ cwd, request }when a cwd is named and are bare without onegit-exclude.test.ts› "excludes a placed session's bundles, installed into its checkout, through the planethat holds it": git questions go to the plane's runner, and the exclude file is written through the plane's
filesystem, never this disk. The existing off-disk test for
withSkillsstill passes unchanged.microsandbox shim, sandbox skill ledger, git-exclude: 230 passed. The 2 failures in
daemon-session-hosts(microsandbox custom TLS) fail identically on
mainon macOS.main.Not in this PR
and harmless.
this PR does not change.
🤖 Generated with Claude Code