fix(extensions): preserve argument-hint in extension Claude SKILL.md (#2903)#2916
Open
jawwad-ali wants to merge 1 commit into
Open
fix(extensions): preserve argument-hint in extension Claude SKILL.md (#2903)#2916jawwad-ali wants to merge 1 commit into
jawwad-ali wants to merge 1 commit into
Conversation
Extension-provided commands that declare `argument-hint:` in their frontmatter had that field dropped from the generated Claude `.claude/skills/<name>/SKILL.md`, while core template commands keep it. The extension skill generator built the frontmatter via the shared build_skill_frontmatter() (name/description/compatibility/metadata only) and never forwarded argument-hint. Carry argument-hint from the parsed source command frontmatter into the skill frontmatter dict before serialization, gated on the integration exposing inject_argument_hint so only argument-hint-aware agents (Claude) receive the key and build_skill_frontmatter's shared shape stays unchanged for every other agent. The value is injected into the dict rather than via the string-based inject_argument_hint helper, so a folded multi-line description cannot be split into invalid YAML. Add regression tests covering a folding description (Claude) and the non-Claude gate (kimi). Closes github#2903 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Description
Closes #2903.
When a command supplied by an extension (
specify extension add) declaresargument-hint:in its frontmatter, that field was dropped from the generated Claude skill (.claude/skills/<name>/SKILL.md), even though core template commands keep it.Root cause. The extension skill generator (
ExtensionManager._register_extension_skills) builds the skill frontmatter via the sharedCommandRegistrar.build_skill_frontmatter(), which only emitsname/description/compatibility/metadata—argument-hintwas never forwarded. Core commands get their hint through a different mechanism (ClaudeIntegration.setup()injects from a hardcodedARGUMENT_HINTSmap), so the inconsistency the issue describes is real.Fix (
src/specify_cli/extensions.py): carryargument-hintfrom the already-parsed source command frontmatter into the skill frontmatter dict, beforeyaml.safe_dump, gated on the integration exposinginject_argument_hint:Two deliberate choices:
ClaudeIntegration.inject_argument_hint(which inserts a line right afterdescription:) corrupts the YAML when the description folds across lines — it splits the folded scalar:yaml.safe_dumpis always valid YAML. The new regression test uses such a folding description to lock this in.hasattr(integration, "inject_argument_hint")gate.ClaudeIntegrationis the only integration that definesinject_argument_hint, so only Claude receives the key —build_skill_frontmatter's shared shape is unchanged for every other skills agent (kimi, codex, etc.). This mirrors the adjacenthasattr(integration, "post_process_skill_content")gate a few lines below.No runtime/slash-command behavior changes — this only affects the frontmatter of generated
SKILL.mdfiles.Scope (intentionally extension-only)
Per #2903's title, body, and repro (all about
specify extension add), this fix is limited to the extension install path. The samebuild_skill_frontmatter → yaml.safe_dumppattern also dropsargument-hintin the preset skill generator (presets.py_register_skills/restore paths ~1342/1438/1475) and the init-time template-conversion path (agents.pyrender_skill_command~332; see the tech-debt note atagents.py:314-318). I've deliberately left those out to keep this PR focused (per CONTRIBUTING's "keep changes focused / split independent changes") — and because the preset path is a genuinely separate problem: presets can override core commands whose hint is dict-driven (ARGUMENT_HINTS), not frontmatter-driven, so a correct preset fix needs more than afrontmatter.get("argument-hint")forward. Happy to follow up with a separate PR if you'd like.Note on the issue's secondary claim
The issue also notes
user-invocable/disable-model-invocationas "absent". Those are not dropped on currentmain—post_process_skill_contentinjects them for Claude extension skills (extensions.py), andtests/test_extension_skills.py::test_skill_md_has_parseable_yamlalready assertsdisable-model-invocation is False. So this PR is scoped to the one genuine defect:argument-hint.Related open PRs
#2776 (integration-aware command hints) and #2103 both touch
extensions.py; #2103 also touchestests/test_extension_skills.py. This is a small, independently-shippable bug fix; I'm happy to rebase if either lands first.Testing
uv run specify --help(exit 0)uv sync && uv run pytestDetails (Windows 11, Python 3.12.12):
uvx ruff check src/— All checks passeduv run pytest tests/test_extension_skills.py tests/integrations/test_integration_claude.py -q— 83 passed, 2 skippeduv run pytest— 3600 passed, 148 skipped, 14 failed; the 14 failures are pre-existing and environment-only (os.symlink→WinError 1314; creating symlinks needs elevation/Developer Mode on Windows), identical to cleanmainon this host and unrelated to this change.New tests in
tests/test_extension_skills.py:test_argument_hint_preserved_for_extension_command— installs an extension command withargument-hintand a long, folding description, asserts the generatedSKILL.mdfrontmatter parses and retains bothargument-hintand the full description. (Fails onmainwithKeyError: 'argument-hint'.)test_argument_hint_not_added_for_non_claude_agent— installs the same kind of command under a non-Claude skills agent (kimi) and assertsargument-hintis not present, proving the gate keeps the key Claude-only.Manual sanity: this changes only the emitted
SKILL.mdfrontmatter, so no slash command's behavior changes; the generated file parses as valid YAML and surfaces the hint in Claude Code.AI Disclosure
This fix was developed with Claude Code (Claude Opus 4.8) under my direction — locating the root cause, writing the change and the regression tests, and running the verification above. I personally confirmed the folded-description YAML-corruption failure mode, verified the non-Claude gate, and reviewed the diff before submitting. I'll disclose if any review responses are AI-assisted as well.