fix: support SKILL.md rendering for the generic integration - #4562
chelsealong wants to merge 3 commits into
Conversation
The generic (bring-your-own-agent) escape hatch could only ever emit flat speckit.<name>.md command files, with no way to opt into the speckit-<name>/SKILL.md layout every skills-format agent (Claude, Codex, etc.) uses. Add a --skills flag to --integration-options that renders the same command templates as SKILL.md directories under --commands-dir instead, matching the agentskills.io layout used elsewhere. Default behavior (flat .md files) is unchanged. Fixes github#4561
_build_skill_content() duplicated SkillsIntegration.setup()'s per-file body but dropped the call to post_process_skill_content(), which injects the dot-to-hyphen hook-invocation note before every "For each executable hook" instruction. Without it, a configured extension hook (e.g. speckit.git.commit) would be invoked verbatim as /speckit.git.commit, which doesn't exist under the speckit-<name>/SKILL.md layout this feature introduces. Add a small _GenericSkillsHelper(SkillsIntegration) — the same delegation pattern CopilotIntegration uses for its own skills mode — and call its post_process_skill_content() after building the SKILL.md body. Add a regression test asserting the note appears.
|
This supplies the generic skills layout requested in #4561, but the mode needs to be wired through beyond file generation. With Please align the mode-specific separator, saved settings/shared-template references, and init guidance with the generated layout. Add an end-to-end regression covering those surfaces while retaining the default flat-command behavior, and document Drafted for @mnriem with assistance from GitHub Copilot (model: GPT-6 Astra; interactive comment drafting). |
There was a problem hiding this comment.
🟡 Changes recommended
Generic skills currently misroute add-on skills and expose dotted invocations for hyphenated skill names.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Adds optional SKILL.md rendering to the generic integration.
Changes:
- Adds the
--skillslayout option. - Adds skill rendering, manifest, uninstall, and regression tests.
File summaries
| File | Description |
|---|---|
src/specify_cli/integrations/generic/__init__.py |
Implements generic skills mode. |
tests/integrations/test_integration_generic.py |
Tests rendering and lifecycle behavior. |
Review details
- Files reviewed: 2/2 changed files
- Comments generated: 2
- Review effort level: Balanced
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| IntegrationOption( | ||
| "--skills", | ||
| is_flag=True, | ||
| default=False, | ||
| help=( |
| skills_enabled = bool((parsed_options or {}).get("skills")) | ||
| created: list[Path] = [] | ||
|
|
||
| for src_file in templates: | ||
| if skills_enabled: |
…kill registration Reviewer feedback on github#4562: generic --skills persisted ai_skills=True but rendered shared templates and init's next-step guidance with the dotted /speckit.plan separator, and let extension/preset registration silently fall back to writing add-on skills under .agents/skills instead of the user's --commands-dir. GenericIntegration now overrides effective_invoke_separator() to match the layout it actually writes, "generic" is classified as a conditional-slash agent for next-step display, and resolve_active_skills_dir() explicitly stays disabled for generic in both layouts since its output directory is a runtime option, not a static per-agent folder.
|
Addressed the alignment feedback in one commit (0e6767c):
|
Fixes #4561
Problem
--integration generic(the "bring your own agent" escape hatch) could onlyever emit flat
speckit.<name>.mdcommand files. There was no way to get thespeckit-<name>/SKILL.mdlayout that every skills-format agent (Claude,Codex, Kimi, Bob, Copilot in skills mode, …) uses, even though
GenericIntegrationalready has all the machinery (
process_template,write_file_and_record,manifest tracking) needed to produce it.
Fix
Added a
--skillsflag toGenericIntegration.options()(parsed the same wayevery other integration's
--integration-optionsflags are — no specialcasing needed). When set,
setup()renders each command template as<commands-dir>/speckit-<name>/SKILL.mdwith the same frontmatter shape(
name,description,compatibility,metadata) thatSkillsIntegration.setup()produces for other agents, instead of the flatspeckit.<name>.mdfile. Default behavior (no--skills) is unchangedbyte-for-byte.
This is scoped to
GenericIntegration's ownsetup()only — it does nottouch
CommandRegistrar.AGENT_CONFIGS, presets, or extensions, which alreadyexclude
genericentirely (its output directory is a runtime CLI option, nota static per-agent convention) regardless of layout. So skills-mode
genericgets the exact same (lack of) preset/extension registration support that
flat-mode
genericalready has today — no new inconsistency introduced.Also,
_build_skill_content()now callspost_process_skill_content()(via asmall internal
_GenericSkillsHelper(SkillsIntegration), the same delegationpattern
CopilotIntegrationuses for its own skills mode) so generatedSKILL.mdbodies get the shared dot-to-hyphen hook-invocation note(
_HOOK_COMMAND_NOTEinbase.py) before every "For each executable hook,output the following" instruction — matching what every other
SkillsIntegrationsubclass (Claude, Codex, Kimi, Bob, …) already emits.Without it, a hook configured in
.specify/extensions.yml(e.g.speckit.git.commit) would have been invoked verbatim as/speckit.git.commit,which doesn't exist under the
speckit-<name>/SKILL.mdlayout this PRintroduces — the real skill lives at
speckit-git-commit/SKILL.md, invokedas
/speckit-git-commit.Testing
Added tests to
tests/integrations/test_integration_generic.py:--skillsis a declared, non-required boolean flag defaulting toFalsesetup()with--skillswritesspeckit-<name>/SKILL.mdfiles under--commands-dirSKILL.mdhas the expected frontmatter and fully-processedbody (no leftover
{SCRIPT}/__AGENT__/__SPECKIT_COMMAND_*__tokens)SKILL.mdbody includes the dot-to-hyphen hook-invocationnote with the
/-prefixed (not$- or/skill:-prefixed) example, sincegenericisn't inDOLLAR_SKILLS_AGENTS/SKILL_COLON_AGENTS--skills, output is still flatspeckit.<name>.md(regressionguard)
round trip
Verified the new tests fail without the fix and pass with it:
Separately, reverting only the
post_process_skill_content()call (keepingeverything else) reproduces the missing-hook-note failure in isolation:
test_skill_content_has_hook_command_notefails with the note absent, andpasses once the call is restored. Also ran the full
tests/integrations/suite: 2911 passed, 5 skipped — no regressions.
Also ran the full suite (
.venv/bin/python -m pytest tests -q): 8049 passed,12 skipped, 10 failed. The 10 failures are pre-existing
*_python_paritytests (
test_check_prerequisites_python_parity.py,test_create_new_feature_python_parity.py,test_resolve_template_python_parity.py,test_setup_plan_python_parity.py,test_setup_tasks_python_parity.py) thatfail identically on unmodified
mainin this sandbox (verified viagit stash), unrelated to this change.Manually exercised the CLI end-to-end:
and confirmed omitting
--skillsstill produces the original flat.myagent/commands/speckit.<name>.mdlayout.AI disclosure
This PR was written by an autonomous Claude Code agent (Claude Sonnet 5),
including the code change, tests, and this description. I (the human
submitter) reviewed the diff and the test run output above before opening it.
🤖 Generated with Claude Code