Repository navigation
Skills path parity: install_skills, skills_status and skill_usage join global paths as skills 1.7.0 does - #482
Merged
seathatflowsinourveins merged 6 commits intoSep 29, 2026
Conversation
…path.join does The pinned skills 1.7.0 CLI builds the global lock path and the canonical skill folder with Node's path.join, which collapses "..": getSkillLockPath (vercel-labs/skills@7407f389 src/skill-lock.ts:67-72, npm dist/cli.mjs L3746-3750) and getCanonicalSkillsDir (src/installer.ts:128-131, dist/cli.mjs L2208-2210). os.homedir() returns HOME verbatim, so only that join removes a ".." from --home. pathlib keeps it. With a ".." through a missing folder in --home or XDG_STATE_HOME, a canonical folder or lock entry that the rollback's remove kept read as removed ('rolled-back'), and a matching add read as unverified and was rolled back. - tools/adoption/install_skills.py: one node_path_join helper, the #467 claude_skills_dir rule (normpath of the non-empty parts joined with /, a leading // collapsed to /), now builds both lock_file_path branches, canonical_skill_dir's global branch and claude_skills_dir. Project paths are unchanged. Lines 1-481 keep the numbers the #467 addendum cites. - scripts/skills_status.py: resolve_lock_path applies the same join. Its copy of the helper sits after main(), so cited lines keep their numbers, and stays local because tree_drift_check.py executes this file from its own bytes and records their sha256. - tests: the fake CLI joins its global paths the same way. New tests cover ".." in --home and XDG_STATE_HOME (rollback read-back 'error', a 'rolled-back' control, a verified install), the unchanged project branches, and the helper against node's own path.join. Against f021926's scripts they fail: 6 failures and 1 error in test_install_skills, 1 failure in test_skills_status; the control and every earlier test pass there. - evidence/artifacts/skills-listing-restore-20260928/README.md: dated erratum naming resolve_lock_path and load_lock (tree_drift_check.py L284-285) and what a re-run now matches. The script and its outputs are unchanged. - catalogs/foundation/manifest.json: the sandbox gate cites docs/secret-storage.md line 30 and "Follow-ups not in this change" lines 1221-1225 (were line 29 and 1171-1175). Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Hot-file protocol (docs/lanes.md): re-registers the six files changed in the previous commit with scripts/host_receipts.py register_file. No new receipt. component_matrix.py --check and new_host_grand_list.py --check exit 0, so neither output is rewritten; scripts/validate.py exits 0. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
…uilds it (repair round) - install_skills.py: compare --project-dir with --home joined as the CLI joins HOME (path.join), then resolved; a '..' after a symlink no longer passes containment. - skills_status.py: the canonical and claude-code link folders are joined as the skills 1.7.0 CLI joins them. A set CLAUDE_CONFIG_DIR moves the link folder (JS trim, path.join) and settings.json (Claude Code 2.1.284's own rule: untrimmed, NFC, path.resolve). A set CODEX_HOME moves config.toml (Codex rust-v0.157.1 canonicalizes it; the default ~/.codex is normalized lexically). - skill_usage.py: any non-empty XDG_STATE_HOME, as the CLI takes it, joined with install_skills.py's node_path_join (one copy). - Tests: fail-first cases for each change; the paths skills_status builds from its copies of the join and trim agree with install_skills.py's. - skills-listing-restore README erratum: the lock read differs from the recorded code's only when a '..' follows a missing folder or a symlink. - Nits: fake-CLI fidelity helper, test-module docstring, "final part" wording. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Re-registers the eight changed files with host_receipts.register_file. component_matrix.py --check and new_host_grand_list.py --check passed without --write; scripts/validate.py passed. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
…back to HOME; cross-family re-check F4) Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
…rmalization-20260928
seathatflowsinourveins
deleted the
claude/skills-path-normalization-20260928
branch
September 29, 2026 02:47
5 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Scope
This finishes the path-resolution parity that #467 started. Every global path that
tools/adoption/install_skills.py,scripts/skills_status.pyandtools/skill-usage/skill_usage.pyread now matches the pinned skills 1.7.0 CLI. A rollback read-back or a status report can therefore no longer look somewhere other than where the CLI wrote.lane:foundation.manifests/evidence.jsonis only re-registered.install_skills.py:lock_file_pathand the globalcanonical_skill_dirnow follow Nodepath.joinsemantics through one sharednode_path_join.project_containment_problemcompares the CLI's lexical home, not the physically resolved--home.skills_status.py:CLAUDE_CONFIG_DIR, trimmed with the JS trim set.settings.jsonfollows Claude Code's own relocation rule.config.tomlfollowsCODEX_HOMEas Codex 0.157.1 resolves it.skill_usage.py: any non-emptyXDG_STATE_HOMEis used, as the CLI uses it, joined withnode_path_join.evidence/artifacts/skills-listing-restore-20260928/README.mdgets an appended dated erratum only.tree_drift_check.pyand its recorded outputs stay byte-identical.catalogs/foundation/manifest.json: the M6 gate's drifteddocs/secret-storage.mdcitations are repaired.blueprints/runtime-workers/*,docs/secret-storage.md, the PR-H: E2E preregistration for the token-save-practice stack (frozen tasks, metrics, gate, procedure) #381 artifacts and every dated receipt. The Runtime-worker skills program: project-scoped installs and a 137-skill manifest #429 program owner (token-save-practice-e2e-status) was told before this PR opened and confirmed there's no collision, because its resolver calls the installer only in project mode.SOTA sources
dist/cli.mjs, sha256fde68534…):codexHomeandclaudeHome, withCLAUDE_CONFIG_DIR?.trim();globalSkillsDir;getCanonicalSkillsDir;getSkillLockPath, which uses any truthyXDG_STATE_HOME, untrimmed, throughpath.join.src/skill-lock.tsL67-72 andsrc/installer.tsL128-131.CLAUDE_CONFIG_DIRbehaviour: the settings and env-vars pages at code.claude.com, read 2026-09-28, and a review of the installed 2.1.284 bundle for the untrimmed, empty-counts and NFC details.CODEX_HOME: openai/codex rust-v0.157.1 (@36650394)codex-rs/utils/home-dir/src/lib.rsL13-51, and the Codexconfig-advanceddocs page.claude_skills_dir, and the JS trim set thatnode --versionv24.21.0 measured.Evidence-class table
tests.test_install_skills tests.test_skills_status tests.test_skill_usage: 219 OK, 0 skipped.f0219263.path.joinwith Python for 6 adversarial inputs: 0 mismatches. Both copies ofJS_TRIM_CHARSequal node's trim set of 25 code points.validate.pypasses with 165 receipts;component_matrix.py --checkandnew_host_grand_list.py --checkboth pass; the three pre-push registry tests pass.Review loop
codex exec -s read-only -m gpt-6-astra, effort max). GPT-6 said MERGE-AFTER-FIXES with 3 majors and 1 minor, and the Claude reviewers independently agreed on the same items.4caf5611) closed all of them, plus the Claude nits and the same-contractskill_usage.pygap.17c5aee1.Residuals (recorded, not fixed here)
HOME: node'shomedir()returns"", so the CLI's canonical folder becomes relative to its working folder, while Python'sPath.home()gives/. The--homedefault in both scripts is affected. This is low severity and pathological.CLAUDE_CONFIG_DIRset only in a settings file'senvblock is invisible to the checker.CLAUDE_CODE_SUBPROCESS_ENV_SCRUBon, a checker run from inside Claude Code reads the default location.cowork_settings.jsonisn't read.--homein project mode is untested (this predates the PR).Local commands run
python3 -m unittest tests.test_install_skills tests.test_skills_status tests.test_skill_usage: exit 0,Ran 219 tests … OK.python3 scripts/validate.py: exit 0,"receipts": 165, "status": "passed".Decision record
No new decision; this closes the parity gap the #467 addendum names. The erratum records the behaviour change for the dated
tree_drift_check.pyre-runs.Host evidence
None. Tests and source review only.
Checklist
🤖 Generated with Claude Code