Stage 5: Skills, Generic & Option-Driven Integrations (#1924)#2052
Stage 5: Skills, Generic & Option-Driven Integrations (#1924)#2052mnriem merged 9 commits intogithub:mainfrom
Conversation
Add SkillsIntegration base class and migrate codex, kimi, agy, and
generic to the integration system.
Integrations:
- SkillsIntegration(IntegrationBase) in base.py — creates
speckit-<name>/SKILL.md layout matching release ZIP output byte-for-byte
- CodexIntegration — .agents/skills/, --skills default=True
- KimiIntegration — .kimi/skills/, --skills + --migrate-legacy options,
dotted→hyphenated skill directory migration
- AgyIntegration — .agent/skills/, skills-only (commands deprecated v1.20.5)
- GenericIntegration — user-specified --commands-dir, MarkdownIntegration
- All four have update-context.sh/.ps1 scripts
- All four registered in INTEGRATION_REGISTRY
CLI changes:
- --ai <agent> auto-promotes to integration path for all registered agents
- Interactive agent selection also auto-promotes (bug fix)
- --ai-skills and --ai-commands-dir show deprecation notices on integration path
- Next-steps display shows correct skill invocation syntax for skills integrations
- agy added to CommandRegistrar.AGENT_CONFIGS
Tests:
- test_integration_base_skills.py — reusable mixin with setup, frontmatter,
directory structure, scripts, CLI auto-promote, and complete file inventory
(sh+ps) tests
- Per-agent test files: test_integration_{codex,kimi,agy,generic}.py
- Kimi legacy migration tests, generic --commands-dir validation
- Registry updated with Stage 5 keys
- Removed 9 dead-mock tests, moved 4 integration tests to proper locations
- Fixed all bare project-name tests to use tmp_path
- Fixed 6 pre-existing ANSI escape code test failures in test_extensions.py
and test_presets.py
1524 tests pass, 0 failures.
There was a problem hiding this comment.
Pull request overview
Migrates additional agents (codex, kimi, agy, generic) onto the integrations plugin architecture by adding a new SkillsIntegration base and wiring up new integration packages, scripts, CLI auto-promotion, and expanded integration test coverage.
Changes:
- Added
SkillsIntegrationbase class to generatespeckit-*/SKILL.mdlayouts and introduced codex/kimi/agy skills integrations plus agenericoption-driven integration. - Updated
specify initto auto-promote--ai <agent>(including interactive selection) into the integration path and adjusted next-steps output for skills integrations. - Expanded/updated tests for new integrations/registry alignment and made CLI-output assertions resilient to ANSI styling.
Reviewed changes
Copilot reviewed 27 out of 27 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/test_presets.py | Strip ANSI escape codes before output assertions. |
| tests/test_extensions.py | Strip ANSI escape codes before output assertions. |
| tests/test_ai_skills.py | Reworked legacy download-path tests and updated CLI validation tests to use tmp_path + integration auto-promote behavior. |
| tests/integrations/test_registry.py | Updated required registry keys for Stage 4+5 and excluded generic from registrar alignment checks. |
| tests/integrations/test_integration_kiro_cli.py | Added CLI test ensuring --ai kiro normalizes/auto-promotes to kiro-cli. |
| tests/integrations/test_integration_kimi.py | Added skills-integration tests for kimi, including legacy dotted-skill migration + next-steps assertions. |
| tests/integrations/test_integration_generic.py | Added option-driven integration tests for generic (--commands-dir) including inventories and uninstall semantics. |
| tests/integrations/test_integration_codex.py | Added skills-integration tests for codex + auto-promote assertion. |
| tests/integrations/test_integration_base_skills.py | Introduced reusable mixin for standard SkillsIntegration subclasses (inventory + CLI promotion + manifest tracking). |
| tests/integrations/test_integration_agy.py | Added skills-integration tests for agy + auto-promote assertion. |
| tests/integrations/test_cli.py | Updated init integration CLI tests to use tmp_path. |
| src/specify_cli/integrations/kimi/scripts/update-context.sh | Added Kimi wrapper script delegating to shared update-agent-context.sh. |
| src/specify_cli/integrations/kimi/scripts/update-context.ps1 | Added Kimi wrapper script delegating to shared PowerShell updater. |
| src/specify_cli/integrations/kimi/init.py | Added KimiIntegration (skills) and dotted-skill migration helper. |
| src/specify_cli/integrations/generic/scripts/update-context.sh | Added Generic wrapper script delegating to shared update-agent-context.sh. |
| src/specify_cli/integrations/generic/scripts/update-context.ps1 | Added Generic wrapper script delegating to shared PowerShell updater. |
| src/specify_cli/integrations/generic/init.py | Added GenericIntegration requiring --commands-dir and writing to user-selected command directory. |
| src/specify_cli/integrations/codex/scripts/update-context.sh | Added Codex wrapper script delegating to shared update-agent-context.sh. |
| src/specify_cli/integrations/codex/scripts/update-context.ps1 | Added Codex wrapper script delegating to shared PowerShell updater. |
| src/specify_cli/integrations/codex/init.py | Added CodexIntegration (skills). |
| src/specify_cli/integrations/agy/scripts/update-context.sh | Added Agy wrapper script delegating to shared update-agent-context.sh. |
| src/specify_cli/integrations/agy/scripts/update-context.ps1 | Added Agy wrapper script delegating to shared PowerShell updater. |
| src/specify_cli/integrations/agy/init.py | Added AgyIntegration (skills). |
| src/specify_cli/integrations/base.py | Added SkillsIntegration implementation for generating SKILL.md layout. |
| src/specify_cli/integrations/init.py | Registered new built-in integrations (agy/codex/kimi/generic). |
| src/specify_cli/agents.py | Added agy to CommandRegistrar.AGENT_CONFIGS. |
| src/specify_cli/init.py | Added integration-path deprecation notes, fixed interactive auto-promotion, mapped legacy flags into integration parsed options, and updated next-steps rendering for skills integrations. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…and early generic validation
- --ai-skills deprecation message now distinguishes SkillsIntegration
("skills are the default") from command-based integrations ("has no effect")
- --ai-commands-dir validation for generic runs even when auto-promoted,
giving clear CLI error instead of late ValueError from setup()
- Resolves review comments from github#2052
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 27 out of 27 changed files in this pull request and generated 6 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Remove unused SKILL_DESCRIPTIONS dict from base.py (dead code after switching to template descriptions for ZIP parity) - Narrow YAML parse catch from Exception to yaml.YAMLError - Remove unused shutil import from test_integration_kimi.py - Remove unused _REGISTRAR_EXEMPT class attr from test_registry.py - Reword --ai-commands-dir deprecation to be actionable - Update generic validation error to mention both --ai and --integration
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 27 out of 27 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Clarify parsed_options forwarding is intentional (all options passed, integrations decide what to use) - Extract _strip_ansi() helper in test_extensions.py and test_presets.py - Remove unused pytest import (test_cli.py), unused locals (test_integration_base_skills.py) - Reword --ai-commands-dir deprecation to be actionable without referencing the not-yet-implemented --integration-options
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 27 out of 27 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Reorder kimi migration: run super().setup() first so hyphenated targets exist, then migrate dotted dirs (prevents user content loss) - Move _strip_ansi() to shared tests/conftest.py, import from there in test_extensions.py, test_presets.py, test_ai_skills.py - Remove now-unused re imports from all three test files
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 28 out of 28 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Use write_bytes() for LF-only newlines (no CRLF on Windows) - Add --integration-options CLI parameter — raw string passed through to the integration via opts['raw_options']; the integration owns parsing of its own options - GenericIntegration.setup() reads --commands-dir from raw_options when not in parsed_options (supports --integration-options="...") - Skip early --ai-commands-dir validation when --integration-options is provided (integration validates in its own setup()) - Remove parse_integration_options from core — integrations parse their own options
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 28 out of 28 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
src/specify_cli/integrations/generic/init.py:81
- The fallback parsing of
raw_optionsusesshlex.split(raw)(POSIX mode by default). On Windows this treats backslashes as escape characters, so a value like--commands-dir .myagent\commandsorC:\path\to\cmdscan be mis-parsed. If--integration-optionsis intended to be cross-platform, consider usingshlex.split(..., posix=os.name != 'nt')(or a small custom parser that supports--commands-dir=<value>/ quoted values) to avoid corrupting paths.
# If --commands-dir not in parsed_options, check raw_options
if "commands_dir" not in parsed_options:
raw = opts.get("raw_options")
if raw:
import shlex
tokens = shlex.split(raw)
for i, token in enumerate(tokens):
if token == "--commands-dir" and i + 1 < len(tokens):
parsed_options["commands_dir"] = tokens[i + 1]
break
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- GenericIntegration is now stateless: removed self._commands_dir instance state, overrides setup() directly to compute destination from parsed_options/raw_options on the stack - commands_dest() raises by design (stateless singleton) - _quote() in SkillsIntegration now escapes backslashes and double quotes to produce valid YAML even with special characters
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 28 out of 28 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Support --commands-dir=value form in raw_options parsing (not just --commands-dir value with space separator) - Normalize CRLF to LF in write_file_and_record() before encoding - Persist ai_skills=True in init-options.json when using a SkillsIntegration, so extensions/presets emit SKILL.md overrides correctly even without explicit --ai-skills flag
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 28 out of 28 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Summary
Migrates codex, kimi, agy (Antigravity), and generic to the integration plugin architecture. Adds
SkillsIntegrationbase class for agents that use thespeckit-<name>/SKILL.mdskills layout.Part of #1924 — Stage 5 of the integration migration plan.
What changed
New base class
SkillsIntegration(IntegrationBase)inbase.py— createsspeckit-<name>/SKILL.mdfiles matching release ZIP output byte-for-byte (validated against v0.4.4 ZIPs for codex and kimi)New integrations
codex.agents/skills/--skills(default=True)kimi.kimi/skills/--skills,--migrate-legacyagy.agent/skills/--skills(default=True)generic--commands-dir(required)Each has
scripts/update-context.{sh,ps1}and is registered inINTEGRATION_REGISTRY.CLI changes
--ai <agent>auto-promotes to integration path for all registered agents (including interactive selection — bug fix)--ai-skills/--ai-commands-dirshow deprecation notices when used with integration path$speckit-*,/skill:speckit-*) for skills integrationsagyadded toCommandRegistrar.AGENT_CONFIGSTest improvements
test_integration_base_skills.py— reusable mixin with 20+ tests includingtest_complete_file_inventory_sh/_pstmp_path(no more directories created in repo root)test_extensions.pyandtest_presets.pyValidation
.agent/commands/*.md→.agent/skills/speckit-*/SKILL.md)What's NOT changed
AGENT_SKILLS_MIGRATIONSstays in__init__.pybehindnot use_integrationguard (removed in Stage 7)--offline/ download paths untouched (Stage 7)AGENT_CONFIGdict untouched (Stage 7)