Skip to content

Install Claude Code as native skills and align preset/integration flows#2051

Merged
mnriem merged 8 commits intogithub:mainfrom
afurm:af/2031-claude-skills
Apr 2, 2026
Merged

Install Claude Code as native skills and align preset/integration flows#2051
mnriem merged 8 commits intogithub:mainfrom
afurm:af/2031-claude-skills

Conversation

@afurm
Copy link
Copy Markdown
Contributor

@afurm afurm commented Apr 1, 2026

Fixes #2031.

This PR moves Claude Code support from generated slash-command files in .claude/commands to native skills in .claude/skills, and aligns the surrounding init, hook, and preset flows with that model.

What changed:

  • Added a dedicated Claude integration that writes skills to .claude/skills/<skill>/SKILL.md
  • Updated Claude init behavior so specify init --ai claude installs skills by default
  • Updated CLI messaging and usage output to show Claude skill invocations like /speckit-plan
  • Updated hook rendering so Claude skills are displayed with /speckit-* invocation syntax
  • Updated README examples and docs to reflect Claude’s skills-first workflow
  • Added focused integration tests for Claude skill generation and init behavior

Follow-up fixes included in this branch:

  • Interactive Claude selection now uses the integration path too, so selecting Claude from the prompt produces the same integration metadata, scripts, and skill output as --ai claude
  • Preset skill propagation now creates missing Claude skill directories for new preset-provided commands, instead of only updating already-existing skills

Why this is needed:

  • Claude now expects spec-kit to be installed as native skills rather than legacy command files
  • Without these fixes, Claude projects behaved differently depending on how init was invoked, and fresh Claude skills projects could silently miss brand-new preset commands added by presets

Reviewer guide:

  • Claude integration implementation: src/specify_cli/integrations/claude/__init__.py
  • Claude init/autopromotion flow: src/specify_cli/__init__.py
  • Preset skill propagation fix: src/specify_cli/presets.py
  • Hook invocation rendering: src/specify_cli/extensions.py
  • Main tests: tests/integrations/test_integration_claude.py, tests/test_presets.py, tests/test_extensions.py

Testing

  • Tested locally with uv run specify --help
  • Ran existing tests with uv sync && uv run pytest
  • Tested with a sample project (if applicable)

Targeted tests run:

  • uv run pytest tests/integrations/test_integration_claude.py tests/test_presets.py -q
  • uv run pytest tests/integrations/test_cli.py -q
  • uv run pytest tests/test_extensions.py -k HookInvocationRendering -q

AI Disclosure

  • I did not use AI assistance for this contribution
  • I did use AI assistance (describe below)

Used Codex to review the branch, identify regressions in Claude preset/init flows, implement the fixes, and add/update targeted tests.

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 please make sure that any Claude specific tests are in test_integration_claude.py. This will make it easier for anyone to see what Claude specific tests there are. Thanks!

@afurm
Copy link
Copy Markdown
Contributor Author

afurm commented Apr 2, 2026

Can you please make sure that any Claude specific tests are in test_integration_claude.py. This will make it easier for anyone to see what Claude specific tests there are. Thanks!

Done. I moved the Claude-specific tests into tests/integrations/test_integration_claude.py and pushed the cleanup in ce96610.

I also reran the affected test files after the move to make sure this was only organizational and didn’t change behavior.

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 migrates Claude Code support from legacy .claude/commands generated slash-command files to native Claude skills under .claude/skills/<skill>/SKILL.md, and updates init/preset/hook flows and documentation to match the new invocation model.

Changes:

  • Added a dedicated Claude integration that generates skills at .claude/skills/<speckit-*>/SKILL.md and installs integration scripts.
  • Updated specify init --ai claude behavior and CLI messaging to default to Claude skill invocations like /speckit-plan.
  • Fixed preset skill propagation to create missing skill directories when presets introduce new commands, and added targeted Claude integration/init/preset/hook tests.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/specify_cli/integrations/claude/__init__.py Implements ClaudeIntegration writing native skill layout and frontmatter.
src/specify_cli/__init__.py Adds Claude skill migration/autopromotion and updates init usage output for Claude skills.
src/specify_cli/extensions.py Renders hook command invocations as /speckit-* when Claude skills are enabled.
src/specify_cli/presets.py Ensures preset-provided commands propagate into skills, creating missing skill dirs when needed.
tests/integrations/test_integration_claude.py Adds integration and init flow tests covering Claude skill generation and messaging.
tests/test_ai_skills.py Updates/removes tests tied to legacy Claude commands and relaxes help-text assertion.
README.md Updates docs/examples to describe Claude’s skills-first workflow and invocation syntax.

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

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.

Please address Copilot feedback

afurm added 2 commits April 2, 2026 16:27
Keep Claude on the skills integration path and align preset-generated Claude skill frontmatter with the core integration.
@afurm afurm requested a review from mnriem April 2, 2026 13:46
@afurm
Copy link
Copy Markdown
Contributor Author

afurm commented Apr 2, 2026

Please address Copilot feedback

Done

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 10 out of 10 changed files in this pull request and generated 2 comments.


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

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.

Please address Copilot feedback. If not applicable, please explain why

@afurm
Copy link
Copy Markdown
Contributor Author

afurm commented Apr 2, 2026

Addressed one suggestion directly and reviewed the other in detail.

What I fixed:

  • Switched ClaudeIntegration to use skills_dest() now that it subclasses SkillsIntegration.
  • Fixed a related native-skill preset cleanup issue I found while validating the review.
  • Added regression tests for the native-skill preset flow.

What I did not change:

  • I did not apply the create_missing_skills == "/SKILL.md" change as written. Native skill agents already create new preset skills through _register_commands(), so flipping that condition directly would be incorrect for the current code 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

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


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

@mnriem mnriem self-requested a review April 2, 2026 14:15
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.

Please address Copilot feedback keeping in mind that the legacy path will very soon be removed

@afurm
Copy link
Copy Markdown
Contributor Author

afurm commented Apr 2, 2026

Addressed. I removed the test from the legacy-path suite and replaced it with a CLI-level test that covers the current Claude integration behavior instead. It now verifies that specify init --here --ai claude preserves pre-existing .claude/commands while installing skills, which felt more appropriate given that the legacy path is expected to be removed soon.

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 11 out of 11 changed files in this pull request and generated no new comments.


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

@afurm afurm requested a review from mnriem April 2, 2026 14:31
@mnriem mnriem merged commit a858c1d into github:main Apr 2, 2026
12 checks passed
@mnriem
Copy link
Copy Markdown
Collaborator

mnriem commented Apr 2, 2026

Thank you!

@afurm afurm deleted the af/2031-claude-skills branch April 2, 2026 14:56
mnriem added a commit to mnriem/spec-kit that referenced this pull request Apr 2, 2026
- Fix circular import: move CommandRegistrar import in claude
  integration to inside method bodies (was at module level)
- Lazy-populate AGENT_CONFIGS via _ensure_configs() to avoid
  circular import at class definition time
- Set claude registrar_config to .claude/commands (extension/preset
  target) since the integration handles .claude/skills in setup()
- Update tests from github#2051 to match: registrar_config assertions,
  remove --integration tip assertions, remove install_ai_skills mocks

1086 tests pass.
mnriem added a commit to mnriem/spec-kit that referenced this pull request Apr 2, 2026
Restore ClaudeIntegration.registrar_config to .claude/skills (not
.claude/commands) so extension/preset registrations write to the
correct skills directory.

Update tests that simulate claude setup to use .claude/skills and
check for SKILL.md layout. Some tests still need updating for the
full skills path — 10 remaining failures from the github#2051 test
expectations around the extension/preset skill registration flow.

WIP: 1076/1086 pass.
@mariozig
Copy link
Copy Markdown

mariozig commented Apr 2, 2026

@afurm I noticed we have a mix of references to skills using both speckit- and speckit.. Some use dash instead of dot.

Is this intentional? ...is the project switching to dash?

I noticed after taking this code i now see both:

Screenshot 2026-04-02 at 10 23 02 AM

Thank you!

mnriem added a commit that referenced this pull request Apr 2, 2026
)

* Stage 6: Complete migration — remove legacy scaffold path (#1924)

Remove the legacy GitHub download and offline scaffold code paths.
All 26 agents now use the integration system exclusively.

Code removal (~1073 lines from __init__.py):
- download_template_from_github(), download_and_extract_template()
- scaffold_from_core_pack(), _locate_release_script()
- install_ai_skills(), _get_skills_dir (restored slim version for presets)
- _has_bundled_skills(), _migrate_legacy_kimi_dotted_skills()
- AGENT_SKILLS_MIGRATIONS, _handle_agent_skills_migration()
- _parse_rate_limit_headers(), _format_rate_limit_error()
- Three-way branch in init() collapsed to integration-only

Config derivation (single source of truth):
- AGENT_CONFIG derived from INTEGRATION_REGISTRY (replaced 180-line dict)
- CommandRegistrar.AGENT_CONFIGS derived from INTEGRATION_REGISTRY (replaced 160-line dict)
- Backward-compat constants kept for presets/extensions: SKILL_DESCRIPTIONS,
  NATIVE_SKILLS_AGENTS, DEFAULT_SKILLS_DIR

Release pipeline cleanup:
- Deleted create-release-packages.sh/.ps1 (948 lines of ZIP packaging)
- Deleted create-github-release.sh, generate-release-notes.sh
- Deleted simulate-release.sh, get-next-version.sh, update-version.sh
- Removed .github/workflows/scripts/ directory entirely
- release.yml is now self-contained: check, notes, release all inlined
- Install instructions use uv tool install with version tag

Test cleanup:
- Deleted test_ai_skills.py (tested removed functions)
- Deleted test_core_pack_scaffold.py (tested removed scaffold)
- Cleaned test_agent_config_consistency.py (removed 19 release-script tests)
- Fixed test_branch_numbering.py (removed dead monkeypatches)
- Updated auto-promote tests (verify files created, not tip messages)

1089 tests pass, 0 failures, ruff clean.

* fix: resolve merge conflicts with #2051 (claude as skills)

- Fix circular import: move CommandRegistrar import in claude
  integration to inside method bodies (was at module level)
- Lazy-populate AGENT_CONFIGS via _ensure_configs() to avoid
  circular import at class definition time
- Set claude registrar_config to .claude/commands (extension/preset
  target) since the integration handles .claude/skills in setup()
- Update tests from #2051 to match: registrar_config assertions,
  remove --integration tip assertions, remove install_ai_skills mocks

1086 tests pass.

* fix: properly preserve claude skills migration from #2051

Restore ClaudeIntegration.registrar_config to .claude/skills (not
.claude/commands) so extension/preset registrations write to the
correct skills directory.

Update tests that simulate claude setup to use .claude/skills and
check for SKILL.md layout. Some tests still need updating for the
full skills path — 10 remaining failures from the #2051 test
expectations around the extension/preset skill registration flow.

WIP: 1076/1086 pass.

* fix: properly handle SKILL.md paths in extension update rollback and tests

Fix extension update rollback using _compute_output_name() for SKILL.md
agents (converts dots to hyphens in skill directory names). Previously
the backup and cleanup code constructed paths with raw command names
(e.g. speckit.test-ext.hello/SKILL.md) instead of the correct computed
names (speckit-test-ext-hello/SKILL.md).

Test fixes for claude skills migration:
- Update claude tests to use .claude/skills paths and SKILL.md layout
- Use qwen (not claude) for skills-guard tests since claude's agent dir
  IS the skills dir — creating it triggers command registration
- Fix test_extension_command_registered_when_extension_present to check
  skills path format

1086 tests pass, 0 failures, ruff clean.

* fix: address PR review — lazy init, assertions, deprecated flags

- _ensure_configs(): catch ImportError (not Exception), don't set
  _configs_loaded on failure so retries work
- Move _ensure_configs() before unregister loop (not inside it)
- Module-level try/except catches ImportError specifically
- Remove tautology assertion (or True) in test_extensions.py
- Strengthen preset provenance assertion to check source: field
- Mark --offline, --skip-tls, --debug, --github-token as hidden
  deprecated no-ops in init()

1086 tests pass.

* fix: remove deleted release scripts from pyproject.toml force-include

Removes force-include entries for create-release-packages.sh/.ps1
which were deleted but still referenced in [tool.hatch.build].
@afurm
Copy link
Copy Markdown
Contributor Author

afurm commented Apr 2, 2026

@afurm I noticed we have a mix of references to skills using both speckit- and speckit.. Some use dash instead of dot.

Is this intentional? ...is the project switching to dash?

I noticed after taking this code i now see both:

Screenshot 2026-04-02 at 10 23 02 AM Thank you!

For Claude, the dashed form is intentional. The PR switched Claude to skills in .claude/skills, so the user-facing invocation is now /speckit-*.

The dotted form still exists in the codebase as the canonical internal command ID (speckit.plan, speckit.specify, etc.) and is still used by other agents, extensions, presets, and metadata, so seeing both styles in source is expected.

What you are likely seeing locally is both legacy .claude/commands entries and new .claude/skills entries present at the same time after the upgrade. That would explain why Claude shows both. So I don’t think this points to a bug in the merged naming change itself, but it may indicate a follow-up migration/cleanup gap for older Claude installs.

@mnriem
Copy link
Copy Markdown
Collaborator

mnriem commented Apr 2, 2026

@afurm Is correct

@mariozig
Copy link
Copy Markdown

mariozig commented Apr 2, 2026

Got it! Thank you both. 💪

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.

[Bug]: .claude/commands/ no longer recognized in Claude Code v2.1.88 — needs migration to .claude/skills/

4 participants