Add specify integration subcommand for post-init integration management#2083
Add specify integration subcommand for post-init integration management#2083
specify integration subcommand for post-init integration management#2083Conversation
Implements the `specify integration` subcommand group for managing integrations in existing projects after initial setup: - `specify integration list` — shows available integrations and installed status - `specify integration install <key>` — installs an integration into existing project - `specify integration uninstall [key]` — hash-safe removal preserving modified files - `specify integration switch <target>` — uninstalls current, installs target Follows the established `specify <noun> <verb>` CLI pattern used by extensions and presets. Shared infrastructure (scripts, templates) is preserved during uninstall and switch operations. Agent-Logs-Url: https://github.com/github/spec-kit/sessions/1cca6c84-3e12-465d-88b8-a646d3504f63 Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com>
- Extract _update_init_options_for_integration() to deduplicate init-options update logic between install and switch commands - Fix _parse_integration_options return type to dict[str, Any] | None Agent-Logs-Url: https://github.com/github/spec-kit/sessions/1cca6c84-3e12-465d-88b8-a646d3504f63 Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
specify integration subcommand for post-init integration management
There was a problem hiding this comment.
Pull request overview
Adds a new specify integration CLI subcommand group to manage AI agent integrations in an already-initialized spec-kit project.
Changes:
- Added
specify integrationsubcommands:list,install,uninstall, andswitch. - Introduced helper utilities for reading/writing
.specify/integration.jsonand parsing--integration-options. - Added a comprehensive new test suite covering the new subcommands and lifecycle behaviors.
Show a summary per file
| File | Description |
|---|---|
src/specify_cli/__init__.py |
Implements the new integration Typer subcommands and supporting helper functions. |
tests/integrations/test_integration_subcommand.py |
Adds end-to-end CLI tests for list/install/uninstall/switch, including manifest-safe teardown behavior. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 2/2 changed files
- Comments generated: 6
…ix metadata cleanup - Add _normalize_script_type() to validate script type against SCRIPT_TYPE_CHOICES - Handle --name=value syntax in _parse_integration_options() - Clear init-options.json keys in no-manifest uninstall early-return path - Clear stale metadata between switch teardown and install phases - Add 5 tests covering the new edge cases
There was a problem hiding this comment.
Pull request overview
Adds a new specify integration subcommand group so integrations can be managed after project initialization, using the existing integration setup/teardown + manifest hash-tracking mechanisms.
Changes:
- Introduces
specify integration list/install/uninstall/switchcommands and supporting helpers. - Adds parsing for
--integration-optionspassthrough to integrations that declare custom options. - Adds a comprehensive new test suite covering the new subcommands and lifecycle scenarios.
Show a summary per file
| File | Description |
|---|---|
src/specify_cli/__init__.py |
Adds the integration Typer sub-app and implements list/install/uninstall/switch flows. |
tests/integrations/test_integration_subcommand.py |
Adds end-to-end CLI tests for all new integration subcommands and edge cases. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 2/2 changed files
- Comments generated: 3
…-options - --force on install now rejects overwriting a different integration; users must use 'specify integration switch' instead - _update_init_options_for_integration() now accepts and persists script_type - Fix misleading test docstring for switch metadata test - Add test_force_blocked_with_different_integration
There was a problem hiding this comment.
Pull request overview
Adds a new specify integration subcommand group to manage AI agent integrations in already-initialized spec-kit projects (list/install/uninstall/switch), reusing the existing integration setup/teardown + manifest hashing mechanics and adding dedicated CLI tests.
Changes:
- Introduces
specify integration {list,install,uninstall,switch}commands and supporting helpers (integration.jsonread/write, script-type resolution, init-options updates, integration-options parsing). - Implements install/uninstall/switch flows using
IntegrationManifest+IntegrationBase.setup()/teardown(). - Adds a comprehensive test suite covering command behavior and lifecycle scenarios.
Show a summary per file
| File | Description |
|---|---|
src/specify_cli/__init__.py |
Adds the integration Typer sub-app and core command implementations/helpers. |
tests/integrations/test_integration_subcommand.py |
New tests validating all integration subcommands and lifecycle behaviors. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comments suppressed due to low confidence (1)
src/specify_cli/init.py:1856
- In the switch uninstall phase, if the current integration can’t be resolved (
current_integration is None) but a manifest exists, the code skips teardown entirely, leaving the old integration files in place and potentially conflicting with the target integration. Consider falling back toIntegrationManifest.load(...).uninstall(...)whencurrent_integrationis missing, rather than skipping uninstall.
current_integration = get_integration(installed_key)
manifest_path = project_root / ".specify" / "integrations" / f"{installed_key}.manifest.json"
if current_integration and manifest_path.exists():
console.print(f"Uninstalling current integration: [cyan]{installed_key}[/cyan]")
old_manifest = IntegrationManifest.load(installed_key, project_root)
removed, skipped = current_integration.teardown(
project_root, old_manifest, force=force,
)
if removed:
console.print(f" Removed {len(removed)} file(s)")
if skipped:
console.print(f" [yellow]⚠[/yellow] {len(skipped)} modified file(s) preserved")
else:
console.print(f"[dim]No manifest for '{installed_key}' — skipping uninstall phase[/dim]")
- Files reviewed: 2/2 changed files
- Comments generated: 4
…ll/switch - Remove --force parameter entirely from integration install; users must uninstall before reinstalling to prevent orphaned files - Auto-install shared infrastructure (.specify/scripts/, .specify/templates/) when missing during install or switch - Add test for shared infra creation on bare project install
The == key case already returns above, so the != key guard is always true at this point. Simplify to just 'if installed_key:'.
There was a problem hiding this comment.
Pull request overview
Adds a new specify integration subcommand group to manage AI agent integrations after project initialization, enabling listing, install, uninstall (hash-safe), and switching integrations in existing spec-kit projects.
Changes:
- Introduces
specify integration {list,install,uninstall,switch}commands and supporting helpers for reading/writing integration metadata and init-options updates. - Implements integration option passthrough via
--integration-optionsparsing and script type resolution via CLI → init-options → platform default. - Adds a comprehensive test suite covering command validation, lifecycle behavior, safe uninstall preservation, and switching semantics.
Show a summary per file
| File | Description |
|---|---|
src/specify_cli/__init__.py |
Adds integration Typer sub-app with list/install/uninstall/switch logic and shared helpers. |
tests/integrations/test_integration_subcommand.py |
Adds end-to-end CLI tests for the new integration subcommands and edge cases. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comments suppressed due to low confidence (1)
src/specify_cli/init.py:1870
- Same issue as
integration install: shared infra setup is conditioned only on.specify/scriptsexisting. Switching into a project where scripts exist but templates are missing will skip_install_shared_infra()and can break integrations that expect.specify/templatesto be present. Recommend checking for both directories (and/or calling_install_shared_infra()unconditionally).
# Ensure shared infrastructure exists
if not (project_root / ".specify" / "scripts").exists():
_install_shared_infra(project_root, selected_script)
if os.name != "nt":
ensure_executable_scripts(project_root)
- Files reviewed: 2/2 changed files
- Comments generated: 2
- Call _install_shared_infra() unconditionally on install and switch since it merges without overwriting existing files - Remove premature metadata cleanup between switch phases; metadata is now only updated after successful Phase 2 install
There was a problem hiding this comment.
Pull request overview
Adds a new specify integration subcommand group to manage AI agent integrations after project initialization (list/install/uninstall/switch), reusing the existing integration manifest + setup/teardown mechanisms.
Changes:
- Introduces
specify integration {list,install,uninstall,switch}commands with shared helpers for metadata, script-type resolution, and init-options updates. - Implements
--integration-optionsparsing to pass integration-specific flags through to integrations that declare options. - Adds a comprehensive test suite covering command behavior and lifecycle scenarios (including preserving modified files and shared infrastructure).
Show a summary per file
| File | Description |
|---|---|
src/specify_cli/__init__.py |
Adds the integration command group and supporting helpers for install/uninstall/switch flows and metadata management. |
tests/integrations/test_integration_subcommand.py |
Adds end-to-end CLI tests for the new integration subcommands and key edge cases. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 2/2 changed files
- Comments generated: 2
…ifest - Wrap IntegrationManifest.load() in switch with ValueError/FileNotFoundError handling, matching the pattern used in uninstall - Split else branch to report 'unknown integration' vs 'no manifest' separately
There was a problem hiding this comment.
Pull request overview
Adds a new specify integration subcommand group to manage AI integrations after project initialization (list/install/uninstall/switch), reusing existing integration setup/teardown + manifest tracking.
Changes:
- Introduces
specify integration {list,install,uninstall,switch}commands with script-type resolution and init-options updates. - Adds parsing for
--integration-optionspassthrough to integrations that declare custom options. - Adds a comprehensive test suite covering install/uninstall/switch lifecycle behaviors and edge cases.
Show a summary per file
| File | Description |
|---|---|
src/specify_cli/__init__.py |
Implements the new integration command group, integration metadata helpers, option parsing, and init-options synchronization. |
tests/integrations/test_integration_subcommand.py |
Adds integration subcommand tests covering validation, lifecycle flows, and metadata/shared-infra preservation. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comments suppressed due to low confidence (1)
src/specify_cli/init.py:1804
- Same init-options cleanup issue as above: this only clears keys when
opts.get("integration") == key. To avoid leaving staleai/ai_skillsbehind, consider clearing whenopts.get("integration") == keyORopts.get("ai") == key.
# Update init-options.json to clear the integration
opts = load_init_options(project_root)
if opts.get("integration") == key:
opts.pop("integration", None)
opts.pop("ai", None)
opts.pop("ai_skills", None)
save_init_options(project_root, opts)
- Files reviewed: 2/2 changed files
- Comments generated: 4
- Remove integration.json in install/switch rollback paths so failed installs don't leave stale metadata - Match on both 'integration' and 'ai' keys when clearing init-options.json during uninstall to handle partially-written metadata
There was a problem hiding this comment.
Pull request overview
Adds a new specify integration subcommand group to manage integrations after project initialization, enabling listing, installing, uninstalling (hash-safe), and switching integrations for existing spec-kit projects.
Changes:
- Introduces
specify integration {list,install,uninstall,switch}commands and supporting helpers (script resolution, integration.json read/write, init-options updates, option parsing). - Reuses existing
IntegrationManifest+ integrationsetup()/teardown()for safe lifecycle operations and shared infra installation. - Adds a comprehensive new test suite covering command validation and end-to-end lifecycle behaviors.
Show a summary per file
| File | Description |
|---|---|
src/specify_cli/__init__.py |
Adds integration Typer subcommands and helpers for metadata, script type resolution, init-options updates, and integration option parsing. |
tests/integrations/test_integration_subcommand.py |
New tests covering list/install/uninstall/switch flows, including modified-file preservation and script type validation. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 2/2 changed files
- Comments generated: 2
- Recovery instructions now guide users through delete manifest → uninstall → reinstall workflow that actually works - Type annotations for optional CLI parameters changed from str to str | None
There was a problem hiding this comment.
Pull request overview
Adds a new specify integration subcommand group to manage AI agent integrations after project initialization, aligning integration management with existing specify <noun> <verb> CLI patterns.
Changes:
- Introduces
specify integration list|install|uninstall|switchcommands that reuse the existingIntegrationManifest+IntegrationBase.setup()/teardown()mechanisms. - Adds helpers for script-type resolution, integration metadata (
.specify/integration.json) read/write, init-options updates, and--integration-optionsparsing. - Adds a comprehensive new test suite covering happy paths, validation/errors, lifecycle behaviors, and edge cases.
Show a summary per file
| File | Description |
|---|---|
src/specify_cli/__init__.py |
Adds the integration Typer sub-app plus implementations for list/install/uninstall/switch and supporting helpers. |
tests/integrations/test_integration_subcommand.py |
New tests covering all integration subcommands, lifecycle behavior, and parsing/validation edge cases. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 2/2 changed files
- Comments generated: 2
- Uninstall no longer requires the integration to be in the registry; falls back to manifest.uninstall() directly when get_integration() returns None - Switch Phase 1 similarly uses manifest-only uninstall for unknown integrations instead of skipping teardown, preventing orphaned files
There was a problem hiding this comment.
Pull request overview
Adds a new specify integration subcommand group to manage AI agent integrations after project initialization, enabling listing, installation, uninstallation, and switching of integrations in existing spec-kit projects.
Changes:
- Introduces
specify integration list|install|uninstall|switchcommands and supporting helpers (script-type resolution, integration.json read/write, init-options updates, integration-options parsing). - Implements integration lifecycle behavior using existing
IntegrationManifesthash tracking andIntegrationBase.setup()/teardown()patterns. - Adds a comprehensive test suite covering command behavior, lifecycle flows, and edge cases.
Show a summary per file
| File | Description |
|---|---|
src/specify_cli/__init__.py |
Adds the integration Typer sub-app, helper utilities, and command implementations for list/install/uninstall/switch. |
tests/integrations/test_integration_subcommand.py |
Adds 21 CLI tests covering all new integration subcommands and key edge cases. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 2/2 changed files
- Comments generated: 3
- _read_integration_json() now exits with an actionable error when integration.json exists but is corrupt/unreadable - _parse_integration_options() rejects unknown options, validates flag usage, and requires values for non-flag options
There was a problem hiding this comment.
Pull request overview
Adds a new specify integration subcommand group to manage AI integrations in already-initialized spec-kit projects (list/install/uninstall/switch), reusing existing integration setup/teardown + manifest tracking.
Changes:
- Introduces
specify integration {list,install,uninstall,switch}commands and supporting helpers for integration metadata, script-type resolution, and init-options updates. - Adds parsing for
--integration-optionspassthrough to integrations that declare custom options. - Adds a comprehensive test suite covering command behaviors and lifecycle scenarios.
Show a summary per file
| File | Description |
|---|---|
src/specify_cli/__init__.py |
Implements the new integration Typer subcommands plus helpers for metadata, script resolution, options parsing, and init-options updates. |
tests/integrations/test_integration_subcommand.py |
New end-to-end CLI tests for integration list/install/uninstall/switch, including lifecycle and edge cases. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 2/2 changed files
- Comments generated: 2
… switch - _read_integration_json() validates parsed JSON is a dict, not a list/string - Switch fails fast with recovery guidance when manifest is missing instead of silently skipping teardown and risking co-existing integration files
There was a problem hiding this comment.
Pull request overview
Adds a new specify integration subcommand group to manage AI integrations after project initialization, enabling listing, installing, uninstalling, and switching integrations within existing spec-kit projects.
Changes:
- Introduces
specify integration {list,install,uninstall,switch}commands and supporting helpers (integration.json handling, script-type resolution, init-options updates, integration-options parsing). - Implements safe uninstall/switch workflows using
IntegrationManifest(hash-based preservation of modified files) and shared-infra reuse. - Adds a comprehensive test suite covering command behaviors and lifecycle scenarios.
Show a summary per file
| File | Description |
|---|---|
src/specify_cli/__init__.py |
Adds the integration command group plus helpers for metadata, script type resolution, and option parsing. |
tests/integrations/test_integration_subcommand.py |
Adds end-to-end CLI tests for list/install/uninstall/switch, including edge cases and lifecycle preservation behavior. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 2/2 changed files
- Comments generated: 0 new
Integrations can currently only be configured during
specify init. This adds aspecify integrationsubcommand group for managing integrations in existing projects, following the establishedspecify <noun> <verb>pattern used by extensions and presets.Commands
specify integration list— table of available integrations with installed status from.specify/integration.jsonspecify integration install <key>— writes files + manifest, updatesintegration.jsonandinit-options.jsonspecify integration uninstall [key]— hash-safe removal viaIntegrationManifest; preserves modified files, reports skippedspecify integration switch <target>— reads current fromintegration.json, teardown → setup; shared infra untouchedImplementation
IntegrationManifesthash tracking andIntegrationBase.setup()/teardown()— no new install/uninstall mechanics_update_init_options_for_integration()helper to deduplicate init-options update logic between install and switch_resolve_script_type()falls back toinit-options.jsonthen platform default when--scriptis omitted_parse_integration_options()handles--integration-optionspassthrough for integrations that declare custom options (e.g. generic's--commands-dir)Tests
21 tests in
tests/integrations/test_integration_subcommand.pycovering:.specify/scripts/,.specify/templates/)