Skill path forms: the lint moves first (#3822 step 1)
Branch fix/3822-skill-path-lint-prereq, 2026-09-02. pi 0.84.4 loads OrchestKit's SKILL.md files and delivers ${CLAUDE_PLUGIN_ROOT} as a literal string. This PR changes only the lint, the conformance grader, the delta anchor and the authoring guide, so the codebase (479 occurrences) can migrate in a separate step. No SKILL.md body is touched.
Pick a target and a consumer
Measured 2026-08-30 on CC 2.1.251 with a throwaway plugin asking for three nonces, run from /tmp and from the skill dir: rel=1 sdir=1 cpr=1 from both cwds. pi expands no ${CLAUDE_*} form. Cursor was not measured; its wrapper is a body copy outside the skill dir (build-plugins.sh generate_command_from_skill).
Three forms, one portable
| form | Claude Code | pi | Skills API | Cursor | use for |
|---|---|---|---|---|---|
references/x.md (bare relative) | resolves against the SKILL.md dir | resolves (Agent Skills spec) | skill dir ships whole (spec, not measured) | not measured | same-skill files. Preferred. |
${CLAUDE_SKILL_DIR}/scripts/x.py | expanded (documented) | literal | literal | literal | exec shapes in CC-only bodies |
${CLAUDE_PLUGIN_ROOT}/skills/other/..., /shared/..., hook command: | expanded | literal | literal | literal | cross-skill, shared, hooks: a plugin root is genuinely needed |
What the placeholder gate checks now
| check | before this PR | after | on this tree |
|---|---|---|---|
| documented placeholders | 3 (PLUGIN_ROOT, PLUGIN_DATA, PROJECT_DIR); SKILL_DIR blocked | 4; ${CLAUDE_SKILL_DIR} accepted | green |
target exists: ${CLAUDE_PLUGIN_ROOT}/skills/... | yes | yes (452 checked) | green |
target exists: ${CLAUDE_SKILL_DIR}/... against the containing skill dir | no | yes (0 in tree today) | green |
target exists: bare relative references/|rules/|scripts/|checklists/|assets/|workflows/|examples/ in Read("...") and ](...) form, SKILL.md only | no | yes (60 links checked, 0 missing) | green |
built plugins/ clean | grep for CLAUDE_SKILL_DIR | any undocumented ${CLAUDE_*} | green |
| same-skill refs on the plugin-root form | not counted | counted, advisory: 423 refs in 55 SKILL.md files | info only |
Paired probe run before commit: a throwaway skill with a missing Read("references/missing-read.md"), a missing [rules](rules/missing-link.md), a missing ${CLAUDE_SKILL_DIR}/scripts/missing.py and a ${CLAUDE_BOGUS_VAR} turned the gate red with all four named (rc=1); removing it turned the gate green (rc=0). A check that cannot disagree with you has measured nothing.
The other three files
| file | change | proof |
|---|---|---|
scripts/eval/conformance-check.mjs C3 | comment inverted (relative for same-skill, plugin-root for cross-skill and shared); C3b narrowed to ${CLAUDE_SKILL_DIR} in Read/link shape only; C3c same-skill check added behind CONFORMANCE_SAME_SKILL=1 | default run: 2 findings (C1, C2), identical to main, 0 new. Opt-in run: 409 C3 lines ready for step 2. |
scripts/check-skill-delta.mjs ORK_ANCHOR | bare CLAUDE_PLUGIN_ROOT and CLAUDE_SKILL_DIR entries replaced by ${CLAUDE_PLUGIN_ROOT}/(skills|shared|hooks)/ | report and --json output diffed before and after: byte-identical (11912 bytes). The one >150-line sub-file anchored only by that entry uses a cross-skill ref, which the new pattern still matches. |
tests/skills/test-skill-length.sh:7 | dead ${CLAUDE_SKILL_DIR} comment dropped | comment only |
src/skills/CONTRIBUTING-SKILLS.md | new "Referencing Supporting Files" section with the three-form table and the consumer matrix; agent-teams example switched to bare relative; checklist bullet | docs only |
Gate commands
bash tests/skills/structure/test-placeholder-validity.sh node scripts/eval/conformance-check.mjs CONFORMANCE_SAME_SKILL=1 node scripts/eval/conformance-check.mjs node scripts/check-skill-delta.mjs --check npm run test:skills npm run test:manifests
Still open after this PR: step 2, the codemod scripts/codemod/skill-paths-relative.mjs that rewrites the same-skill refs to bare relative in batches of 5 files and flips C3c on by default; step 3, the compatibility note near cross-skill and shared refs. This PR is Refs #3822, not Closes.