Repository navigation
Description
Bug Description
When an extension command is installed as an agent skill, rewrite_extension_paths (src/specify_cli/agents.py, introduced in #2101) rewrites references so they point to .specify/extensions/<id>/…. This has two problems:
- Root-relative output. The result is always
.specify/extensions/<id>/…, relative to the project root. In agents that resolve skill-relative paths from the directory ofSKILL.md(for example.github/skills/<name>/SKILL.md), the path resolves to.github/skills/<name>/.specify/…and the file is not found.../../../.specify/extensions/<id>/…works. - Only top-level directories are matched. Only directories directly in the extension root are rewritten. A reference such as
references/template.mdis left unchanged when the file lives inskills/<name>/references/, because no top-levelreferences/directory exists.
Only SKILL.md is written to the skill directory. All other extension files stay in .specify/extensions/<id>/.
Steps to Reproduce
- Create an extension with
skills/example/references/template.mdand a command that saysRead `references/template.md`. - Install it in a project with a skills-based agent where skills are in
.github/skills/. - Inspect
.github/skills/<ext>-<cmd>/SKILL.md. The reference is unchanged. - Change the command to
Read `skills/example/references/template.md`and reinstall. The reference becomes.specify/extensions/example/skills/example/references/template.md, which the agent cannot resolve from theSKILL.mddirectory.
Expected Behavior
References resolve from the skill, either via a path relative to the skill directory (for example ../../../.specify/extensions/<id>/…) or because referenced files are available next to SKILL.md. References into nested extension directories are handled too.
Actual Behavior
Nested references are not rewritten, and rewritten references are root-relative and not found when the agent resolves from the SKILL.md directory.
Specify CLI Version
0.8.2.dev0 (main checkout)
AI Agent
GitHub Copilot
Operating System
Not relevant (platform-independent path handling)
Python Version
Not relevant (platform-independent path handling)
Error Logs
N/A
Additional Context
Workaround for extension authors: use paths from the extension root (skills/example/references/template.md), preceded by whitespace, backtick, quote or (, and tell the agent in AGENTS.md to resolve .specify/… references from the project root.
Behavior was confirmed in the code and with the rewrite function in isolation, not with a full specify extension add. Resolution behavior in other agents is not verified.
Alternatives to consider
- Relative path from the skill directory. Generate the reference with
os.path.relpathfrom the skill directory to.specify/extensions/<id>/…, for example../../../.specify/extensions/<id>/…for.github/skills/<name>/. This keeps a single copy of the files, but the path depends on the agent's skills directory and its depth. - Symlinks in the agent-native skill directory. Create symlinks next to
SKILL.mdthat point to the referenced files or directories in.specify/extensions/<id>/. References likereferences/template.mdthen work as written, with no rewrite. Caveats: symlinks are unreliable on Windows without developer mode or admin rights, and some agents or tools may not follow them. The dev-mode install already uses symlinks forSKILL.md, so there is precedent. - Copy the files into the skill directory. Copy the referenced files next to
SKILL.md. This matches the usual Agent Skills layout and works everywhere, with no path rewriting. The cost is duplicated files that can drift from.specify/extensions/<id>/. Update, removal and rollback (_command_update_transaction.py,_find_extension_skill_dirs) would also need to track and clean up these files.
AI Disclosure
Drafted with GitHub Copilot CLI (Claude Sonnet 5.5). The code analysis was AI-assisted and reviewed by the filer.
Activity
github-actions commentedon Nov 10, 2026
Bug assessment — extension-skill-path-rewrite: Valid · severity medium
Bug Assessment: Extension skill path rewriting breaks nested refs and skill-relative resolution
Report (summarized)
Issue #5363 (by @markuswondrak) reports that extension command references are rewritten to
.specify/extensions/<id>/..., but this can fail for skills installed under.github/skills/.../SKILL.mdwhen the agent resolves paths relative toSKILL.mdrather than repository root. The report also states that nested references (for examplereferences/template.mdwhen the file is underskills/<name>/references/) are not rewritten.Symptom
Extension command content in generated
SKILL.mdcan contain rewritten paths that do not resolve from the skill directory, and some nested file references are left unchanged. Expected behavior is that referenced files are resolvable from the installed skill context, including nested extension directories.Reproduction
skills/example/references/template.md) and a command body that referencesreferences/template.md..github/skills/.../SKILL.md).SKILL.mdand observe whether nested reference text is rewritten and whether rewritten.specify/extensions/...path resolves from the skill file location.[NEEDS CLARIFICATION: full end-to-end runtime confirmation of path resolution behavior was not provided for every agent, but code evidence and isolated function behavior support the report.]
Suspected Code Paths
src/specify_cli/agents.py:237(rewrite_extension_paths) — primary rewrite routine used during extension command/skill rendering.src/specify_cli/agents.py:258— collects only top-level subdirectories fromextension_dir.iterdir(), which excludes nested directory names not present at root.src/specify_cli/agents.py:274-275— replacement is hard-coded to.specify/extensions/{extension_id}/{subdir}/via regex substitution, producing repository-root-style paths.src/specify_cli/extensions/__init__.py:1676— skills registration path invokesregistrar.rewrite_extension_paths(...)before writingSKILL.md.tests/test_extension_skills.py:1099-1156— existing tests assert.specify/extensions/...rewriting for top-level subdirs but do not cover nested-reference rewriting or skill-directory-relative resolution.src/specify_cli/integrations/copilot/__init__.py:123,126— Copilot skills are written under.github/skillswith/SKILL.md, matching the reported context.Root Cause Hypothesis
rewrite_extension_pathsis intentionally conservative but currently keyed to top-level folder names only, so it cannot detect/reference nested paths that do not start with a root-level folder name present in the extension root. It also emits a fixed.specify/extensions/...prefix without considering the final skill file directory depth. That combination explains both reported symptoms. Confidence: high.Proposed Remediation
Preferred: make rewrite context-aware and path-accurate in two parts:
/SKILL.mdtargets), compute reference strings relative to the generated skill directory (for example viaos.path.relpathfrom<agent skills dir>/<skill>/to.specify/extensions/<id>/...), while preserving existing behavior for non-skill command layouts if needed.This keeps single-source extension assets under
.specify/extensions/while producing references that remain resolvable in skills directories at varying depths.Alternatives (optional):
SKILL.mdduring install (portable, but introduces duplication/drift and lifecycle cleanup complexity).Files likely to change:
src/specify_cli/agents.pysrc/specify_cli/extensions/__init__.pytests/test_extension_skills.pyTests to add or update:
references/template.mdbacked byskills/example/references/template.md) is rewritten correctly..github/skills/<skill>/SKILL.md(relative path expectation).Risks & Considerations
Open Questions
Fix extension-skill-path-rewrite: rewrite skill refs relative to SKIL…
github-actions commentedon Nov 10, 2026
Pull request created: #5364
github-actions commentedon Nov 10, 2026
Implemented extension-skill-path-rewrite and opened a draft fix PR from
fix/5363-extension-skill-path-rewritefor maintainer review: main...fix/5363-extension-skill-path-rewriteSummary: extension skill path rewriting now rewrites only to existing extension assets, supports nested shorthand references via unique suffix resolution, and emits skill-directory-relative
.specify/extensions/...paths for generatedSKILL.mdfiles.Next stage: after review of the draft PR, validate the fix with the stage-3
bug-testworkflow if this repository has it configured.fix-proposedexists in this repository and is being applied for tracking.github-actions commentedon Nov 10, 2026
Bug test — extension-skill-path-rewrite: ❌ failing · 0 passed, 3 failed, 0 skipped · fix from linked PR #5364
Bug Test Report: Extension skill path rewrite regressions
fix/5363-extension-skill-path-rewrite-160a14669d50b2e6, commitd101b7af6f96b1548e58e44770d4d9113121a151)timeout 600 python3 -m pytest -q tests/test_extension_skills.py::TestExtensionSkillRegistration::test_skill_registration_rewrites_extension_subdir_paths tests/test_extension_skills.py::TestExtensionSkillRegistration::test_skill_registration_rewrites_nested_extension_refs tests/test_extension_skills.py::TestExtensionSkillRegistration::test_copilot_skill_registration_rewrites_relative_to_skill_dirSummary
Tested the proposed fix from PR #5364 against the assessment-identified regression tests. All three relevant tests failed, indicating the fix does not currently satisfy the expected nested and skill-relative path rewrite behavior.
Test Results
Failures (if any)
tests/test_extension_skills.py::TestExtensionSkillRegistration::test_skill_registration_rewrites_extension_subdir_paths— expected../../../.specify/extensions/path-ext/knowledge-base/agent-scores.yamlnot present in generatedSKILL.mdcontent.tests/test_extension_skills.py::TestExtensionSkillRegistration::test_skill_registration_rewrites_nested_extension_refs— expected nested rewrite to../../../.specify/extensions/nested-ref-ext/skills/example/references/template.md; content remainedRead references/template.md..tests/test_extension_skills.py::TestExtensionSkillRegistration::test_copilot_skill_registration_rewrites_relative_to_skill_dir— expected../../../.specify/extensions/copilot-path-ext/skills/copilot/references/guide.mdnot present; content remainedRead skills/copilot/references/guide.md..Verification vs. Historical Fix
not applicable (no historical fix referenced)
Notes & Caveats
[Bug]: Extension skill references are rewritten to project-root-relative paths and miss nested directories.@markuswondrak.FIX_SOURCE: linked pull request ([bug-fix] Fix extension-skill-path-rewrite: rewrite extension refs for skills #5364).bug-test-fix) with the repository’s existing Python/pytest environment.markuswondrak commentedon Nov 10, 2026
@mnriem Could you share your view on the copy-resources-into-the-skill-directory alternative before we extend the path-rewriting approach further in #5364?
My preference would be to make this an explicit opt-in, through a setting in
extension.ymlor a dedicated CLI flag. Existing installations would retain the current path-rewriting behavior unless copying is explicitly enabled. When enabled, each generated skill would be installed together with its required bundled resources, for example:The skill could then simply reference
references/reviewer.md, rather than reaching back into.specify/extensions/<id>/through generated../../../paths.The Agent Skills specification describes a skill directory containing
SKILL.mdplus optional scripts, references, and assets. Its file-reference guidance explicitly says:I read this as favoring self-contained packaging of bundled skill resources, although it does not prohibit external dependencies. Copying those resources seems closer to that model than generating only
SKILL.mdand leaving its supporting files elsewhere.The extension under
.specify/extensions/<id>/could remain the source of truth; skill-local copies would be generated installation outputs. Updates, removal, and rollback would need to track them and preserve user modifications appropriately. That is additional lifecycle work, but perhaps preferable to increasingly complex path detection and rewriting.Within this opt-in mode, I would favor regular copies rather than relying on symlinks, for portability. Your comment on #2988 documents the Codex limitation for symlinked
SKILL.mdfiles, though that does not necessarily apply to resource links.This would not mean blindly copying the entire extension: shared configuration and scripts requiring the project root as their working directory would still need explicit handling.
Would you support an opt-in mechanism for skill-local resource copies, and would you prefer the opt-in to live in
extension.yml, in the CLI, or both? Is there an architectural reason to avoid this approach? If it is too broad for this bugfix, should we agree on the intended packaging model in a separate issue first?AI assistance: Researched and drafted for @markuswondrak using pi with GitHub Copilot /
gpt-6-astra, in interactive, human-directed mode. No implementation or runtime testing performed.mnriem commentedon Nov 10, 2026
We would need to support both. The alongside as the new normal and the in the extension as the deprecated but still supported route
mnriem commentedon Nov 10, 2026
It would be part of the extension.yml I would think
markuswondrak commentedon Nov 10, 2026
Got it. Will create a new issue for that.
I would then close this one or do you like this one to be implemented?
We actually don't need it if we get the "copy"-version.
mnriem commentedon Nov 10, 2026
Less is more so yea lets close it then