Skip to content

fix(extensions): rewrite extension-relative paths in generated SKILL.md files#2103

Draft
mbachorik wants to merge 17 commits intogithub:mainfrom
mbachorik:fix/extension-skill-path-rewrite
Draft

fix(extensions): rewrite extension-relative paths in generated SKILL.md files#2103
mbachorik wants to merge 17 commits intogithub:mainfrom
mbachorik:fix/extension-skill-path-rewrite

Conversation

@mbachorik
Copy link
Copy Markdown
Contributor

Fixes #2101

What

When an extension command body references files relative to the extension
root (e.g. agents/control/commander.md, knowledge-base/scores.yaml),
those paths are now correctly rewritten to .specify/extensions/<id>/...
in the generated SKILL.md files.

Why

Extension commands are registered as SKILL.md files for skill-format agents
(currently kimi and codex). After installation the extension files live
at .specify/extensions/<id>/..., but render_skill_command() had no path
rewriting — it wrote bare relative paths verbatim. The AI agent resolves
them from the workspace root where they don't exist, so the referenced files
were never found.

How

  • Add CommandRegistrar.rewrite_extension_paths(text, extension_id, extension_dir): discovers which subdirectories exist in the installed extension and rewrites matching subdir/… references to .specify/extensions/<id>/subdir/… using conservative regex boundary anchoring
  • Run it before resolve_skill_placeholders() so extension-local scripts/ and templates/ aren't incorrectly redirected to project-level paths
  • Thread source_dir from register_commands() through to render_skill_command() for both primary commands and aliases

Tests

Unit tests in test_extensions.py:

  • Core fix: codex, all subdir types (agents/, templates/, scripts/, knowledge-base/)
  • Kimi agent receives the same rewriting
  • Alias commands are also rewritten
  • Extension with no subdirs — text unchanged (conservative)

Integration tests in test_integration_extension_skill_paths.py:

  • Skipped unless SPECKIT_TEST_EXT_DIR env var points to a local extension checkout
  • Installs real extension, verifies all skill files end-to-end

🤖 Generated with Claude Code

…md files

Extension command bodies reference files using paths relative to the
extension root (e.g. `agents/control/commander.md`, `knowledge-base/scores.yaml`).
After install these files live at `.specify/extensions/<id>/...`, but the
generated SKILL.md files were emitting bare relative paths that AI agents
could not resolve from the workspace root.

Add `CommandRegistrar.rewrite_extension_paths()` which discovers the
subdirectories that exist in the installed extension directory and rewrites
matching body references to `.specify/extensions/<id>/<subdir>/...`.  The
rewrite runs before `resolve_skill_placeholders()` so that extension-local
`scripts/` and `templates/` subdirectories are not incorrectly redirected to
the project-level `.specify/scripts/` and `.specify/templates/` paths.

The method is called from `render_skill_command()` when `source_dir` is
provided, which `register_commands()` now passes through for all agents.

Affected agents: any using the `/SKILL.md` extension format (currently kimi
and codex).  Aliases receive the same rewriting.

Closes github#2101

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 6, 2026 09:50
@mbachorik mbachorik requested a review from mnriem as a code owner April 6, 2026 09:50
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes extension command bodies that reference extension-root-relative files (e.g., agents/..., knowledge-base/...) by rewriting those references to the installed location under .specify/extensions/<id>/... when generating SKILL.md files for skill-format agents (notably codex and kimi).

Changes:

  • Add CommandRegistrar.rewrite_extension_paths() and invoke it during SKILL.md rendering (before placeholder resolution).
  • Thread source_dir through SKILL.md generation for primary commands and aliases so the renderer has enough context to rewrite paths.
  • Add unit tests (extensions) and an opt-in integration test (real extension install) to validate end-to-end behavior.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
src/specify_cli/agents.py Adds extension-relative path rewriting and applies it during SKILL.md rendering; threads source_dir into SKILL.md generation paths.
tests/test_extensions.py Adds unit tests covering extension path rewriting for codex/kimi, aliases, and conservative “no subdirs” behavior.
tests/test_integration_extension_skill_paths.py Adds opt-in integration tests that install a real extension and validate rewritten paths across generated skill files.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@mbachorik mbachorik marked this pull request as draft April 6, 2026 09:57
@mbachorik
Copy link
Copy Markdown
Contributor Author

Fixed the path-rewriting scope issue raised in the inline review.

Change: Gated rewrite_extension_paths() in render_skill_command() on (source_dir / "extension.yml").exists(). This ensures the rewrite only applies to extension source directories; preset directories (which have preset.yml but no extension.yml) are skipped entirely.

Test added: test_preset_skill_registration_does_not_rewrite_paths — sets up a preset-style dir with a templates/ subdir, registers commands, and asserts the output contains no .specify/extensions/... paths.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes extension command SKILL.md generation so that references to extension-relative files (e.g., agents/..., templates/...) are rewritten to their installed location under .specify/extensions/<id>/..., making those files resolvable by skill-format agents (Codex/Kimi). It addresses issue #2101 where generated SKILL.md files contained bare relative paths that don’t exist from the workspace root.

Changes:

  • Add extension-relative path rewriting during SKILL.md rendering and thread source_dir through skill rendering for primary commands and aliases.
  • Add unit tests covering rewriting across multiple subdirs, Kimi support, aliases, and “no subdirs” conservative behavior.
  • Add an opt-in integration test (env-var gated) that installs a real extension and validates end-to-end SKILL.md outputs.
Show a summary per file
File Description
src/specify_cli/agents.py Implements extension-relative path rewriting and applies it during SKILL.md rendering (with source_dir plumbing).
tests/test_extensions.py Adds unit tests ensuring SKILL.md content rewrites extension-relative paths for Codex/Kimi and aliases.
tests/test_integration_extension_skill_paths.py Adds env-gated integration tests to verify rewriting against a real installed extension.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 3/3 changed files
  • Comments generated: 0 new

iamaeroplane and others added 8 commits April 8, 2026 07:29
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ommands

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…during rendering

Wire translate_behavior() and strip_behavior_keys() into render_skill_command() so
that behavior: and agents: blocks are stripped from output and translated into
agent-specific fields (context, model, effort, allowed-tools, etc.) during skill rendering.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ead of .claude/skills/

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…t commands

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…t tests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add note below per-agent translation table explaining that allowed-tools
  is remapped to tools for Claude agent definitions (execution: agent)
- Add tools: full and visibility: both rows to the table (both are no-ops)
- Add comment in TestEndToEnd explaining why ai_skills is omitted from
  init-options.json (skill routing uses CommandRegistrar, not ai_skills path)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@mnriem
Copy link
Copy Markdown
Collaborator

mnriem commented Apr 8, 2026

Just to make sure the non-rendered commands are installed in the .specify/extensions/ directory and then when the extension is enabled / disabled the SKILL.md files are put into the agent specific location using the skill rendering?

Copy link
Copy Markdown
Collaborator

@mnriem mnriem left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you clarify if comment above is correct?

@dhilipkumars
Copy link
Copy Markdown
Contributor

yup i have the same question is this specifically to support to codex ? my original PR did work for Gemini and AGY when i tested it.

#1840

iamaeroplane and others added 8 commits April 10, 2026 09:21
- behavior.py: add `color` key to BEHAVIOR_KEYS; passthrough to Claude
  agent frontmatter (red|blue|green|yellow|purple|orange|pink|cyan)
- behavior.py: add `write` preset (Read Write Edit Grep Glob, no Bash)
- behavior.py: add custom tool list support — YAML list or unrecognised
  string passed verbatim as allowed-tools
- agents.py: add `color` to _SKILL_PASSTHROUGH_KEYS["claude"]
- tests: add 4 new behavior translator tests (write, color passthrough,
  all color values, color ignored for non-Claude agents)
- RFC: update RFC-EXTENSION-BEHAVIOR-DEPLOYMENT.md to document write
  preset, custom tool values, and color field with examples

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add table of addenda at the bottom of RFC-EXTENSION-SYSTEM.md and a
see-also cross-reference in the conversion appendix, so readers are
directed to RFC-EXTENSION-BEHAVIOR-DEPLOYMENT.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… loop

_register_extension_skills() now checks behavior.execution before
creating a SKILL.md directory. Commands routed to .claude/agents/
(execution: agent) are skipped — they were already deployed by
register_commands_for_all_agents(). Manifest-level behavior is merged
when the source file has no behavior: block, matching the same merge
logic used by the agent deployment path.

Also adds a preset regression test: preset source dirs (no extension.yml)
must not have paths rewritten to .specify/extensions/... prefixes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All built-in command templates (analyze, checklist, clarify, constitution,
implement, plan, specify, tasks, taskstoissues) now declare
behavior.invocation: automatic, which translates to
disable-model-invocation: false for Claude. This allows the model to
invoke these commands autonomously, matching their design intent as
workflow commands within an automated pipeline.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add .venv312, .specify, .claude, and specs/ to .gitignore to prevent
local development artefacts from appearing as untracked files.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Content superseded by extensions/RFC-EXTENSION-BEHAVIOR-DEPLOYMENT.md,
which is the canonical addendum to RFC-EXTENSION-SYSTEM.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 10, 2026 10:00
@mbachorik
Copy link
Copy Markdown
Contributor Author

@mnriem @dhilipkumars sorry for radio silence, I did not have time to come back to this. I hit several issues with recent change to spec-kit (originally I thought the fix is minimal to rewrite the relative paths). it has evolved into something bigger, I'll update the PR with proper explanation today or over the weekend.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 20 out of 21 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +783 to +791
_source_fm, _ = registrar.parse_frontmatter(
source_file.read_text(encoding="utf-8")
)
# Merge manifest-level behavior when source file has none
if "behavior" not in _source_fm and "behavior" in cmd_info:
_source_fm["behavior"] = cmd_info["behavior"]
if get_deployment_type(_source_fm) == "agent":
continue

Comment on lines +627 to +633
behavior = frontmatter.get("behavior") or {}
agents_overrides = frontmatter.get("agents") or {}
extra_fields = translate_behavior(
agent_name, behavior,
agents_overrides if isinstance(agents_overrides, dict) else {}
)
copilot_tools = get_copilot_tools(behavior if isinstance(behavior, dict) else {})
Comment on lines +607 to +611
if cmd_type == "agent" and agent_name == "claude":
output = self.render_agent_definition(
agent_name, output_name, frontmatter, body,
source_id, cmd_file, project_root, source_dir=source_dir,
)
Comment on lines +1 to +12
"""Neutral behavior vocabulary for extension commands.

Extension command source files can declare a ``behavior:`` block in their
frontmatter to express agent-neutral intent (isolation, capability, tools,
etc.). This module translates that vocabulary to concrete per-agent
frontmatter fields during rendering.

Extension authors can also declare an ``agents:`` escape-hatch block for
agent-specific fields that have no neutral equivalent::

behavior:
execution: isolated
@mnriem
Copy link
Copy Markdown
Collaborator

mnriem commented Apr 10, 2026

@mbachorik Please address Copilot feedback

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.

fix: Extension SKILL.md files contain unresolvable relative paths to extension subdirectories

4 participants