From c47dd2b81259a0526eb8a9e9bc812cee520e55bb Mon Sep 17 00:00:00 2001 From: Ben Buttigieg <70525+BenBtg@users.noreply.github.com> Date: Tue, 30 Jun 2026 14:49:49 +0100 Subject: [PATCH] =?UTF-8?q?chore:=20retire=20Windsurf=20integration=20?= =?UTF-8?q?=E2=80=94=20absorbed=20into=20Cognition=20Devin=20(#3168)=20(#3?= =?UTF-8?q?213)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: retire windsurf integration — absorbed into Cognition Devin (#3168) windsurf.com now permanently redirects to devin.ai/desktop following acquisition. Remove subpackage, registry/catalog entries, docs, and tests; re-point sample-agent test fixtures to Kilo Code. Assisted-by: GitHub Copilot (model: Claude Opus 4.8, autonomous) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: remove stale Windsurf support references Assisted-by: GitHub Copilot (model: gpt-5.3-codex, autonomous) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: fix Kilo Code command path in upgrade guide Assisted-by: GitHub Copilot (model: gpt-5.3-codex, autonomous) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * chore: align integration lists after rebase Assisted-by: GitHub Copilot (model: gpt-5.3-codex, autonomous) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * docs: align kilocode example with runtime behavior Assisted-by: GitHub Copilot (model: gpt-5.3-codex, autonomous) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/ISSUE_TEMPLATE/agent_request.yml | 2 +- .github/ISSUE_TEMPLATE/bug_report.yml | 1 - .github/ISSUE_TEMPLATE/feature_request.yml | 1 - AGENTS.md | 22 +++++++++---------- docs/index.md | 2 +- docs/reference/integrations.md | 4 +--- docs/upgrade.md | 10 ++++----- integrations/catalog.json | 9 -------- presets/ARCHITECTURE.md | 2 +- src/specify_cli/integrations/__init__.py | 2 -- .../integrations/windsurf/__init__.py | 21 ------------------ tests/integrations/test_integration_devin.py | 2 +- tests/integrations/test_integration_forge.py | 16 +++++++------- .../integrations/test_integration_windsurf.py | 10 --------- tests/integrations/test_registry.py | 2 +- tests/test_agent_config_consistency.py | 1 - tests/test_workflows.py | 4 ++-- 17 files changed, 32 insertions(+), 79 deletions(-) delete mode 100644 src/specify_cli/integrations/windsurf/__init__.py delete mode 100644 tests/integrations/test_integration_windsurf.py diff --git a/.github/ISSUE_TEMPLATE/agent_request.yml b/.github/ISSUE_TEMPLATE/agent_request.yml index 15f3f10c2..4a750bc23 100644 --- a/.github/ISSUE_TEMPLATE/agent_request.yml +++ b/.github/ISSUE_TEMPLATE/agent_request.yml @@ -8,7 +8,7 @@ body: value: | Thanks for requesting a new agent! Before submitting, please check if the agent is already supported. - **Currently supported agents**: Amp, Antigravity, Auggie CLI, Claude Code, Cline, CodeBuddy, Codex CLI, Cursor, Devin for Terminal, Firebender, Forge, Gemini CLI, GitHub Copilot, Goose, Hermes Agent, IBM Bob, Junie, Kilo Code, Kimi Code, Kiro CLI, Lingma, Mistral Vibe, Oh My Pi, opencode, Pi Coding Agent, Qoder CLI, Qwen Code, Roo Code, RovoDev ACLI, SHAI, Tabnine CLI, Trae, Windsurf, ZCode, Zed + **Currently supported agents**: Amp, Antigravity, Auggie CLI, Claude Code, Cline, CodeBuddy, Codex CLI, Cursor, Devin for Terminal, Firebender, Forge, Gemini CLI, GitHub Copilot, Goose, Hermes Agent, IBM Bob, Junie, Kilo Code, Kimi Code, Kiro CLI, Lingma, Mistral Vibe, Oh My Pi, opencode, Pi Coding Agent, Qoder CLI, Qwen Code, Roo Code, RovoDev ACLI, SHAI, Tabnine CLI, Trae, ZCode, Zed - type: input id: agent-name diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 1e3d5f14c..193f0105e 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -94,7 +94,6 @@ body: - SHAI - Tabnine CLI - Trae - - Windsurf - ZCode - Zed - Not applicable diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index 83f3169c3..a9766bca5 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -88,7 +88,6 @@ body: - SHAI - Tabnine CLI - Trae - - Windsurf - ZCode - Zed - Not applicable diff --git a/AGENTS.md b/AGENTS.md index 68d8641e4..8b5afd4e8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -23,7 +23,7 @@ src/specify_cli/integrations/ │ └── __init__.py # ClaudeIntegration class ├── gemini/ # Example: TomlIntegration subclass │ └── __init__.py -├── windsurf/ # Example: MarkdownIntegration subclass +├── kilocode/ # Example: MarkdownIntegration subclass │ └── __init__.py ├── copilot/ # Example: IntegrationBase subclass (custom setup) │ └── __init__.py @@ -52,25 +52,25 @@ Most agents only need `MarkdownIntegration` — a minimal subclass with zero met Create `src/specify_cli/integrations//__init__.py`, where `` is the Python-safe directory name derived from ``: use the key as-is when it contains no hyphens (e.g., key `"gemini"` → `gemini/`), or replace hyphens with underscores when it does (e.g., key `"kiro-cli"` → `kiro_cli/`). The `IntegrationBase.key` class attribute always retains the original hyphenated value, since that is what the CLI and registry use. For CLI-based integrations (`requires_cli: True`), the `key` should match the actual CLI tool name (the executable users install and run) so CLI checks can resolve it correctly. For IDE-based integrations (`requires_cli: False`), use the canonical integration identifier instead. -**Minimal example — Markdown agent (Windsurf):** +**Minimal example — Markdown agent (Kilo Code):** ```python -"""Windsurf IDE integration.""" +"""Kilo Code IDE integration.""" from ..base import MarkdownIntegration -class WindsurfIntegration(MarkdownIntegration): - key = "windsurf" +class KilocodeIntegration(MarkdownIntegration): + key = "kilocode" config = { - "name": "Windsurf", - "folder": ".windsurf/", + "name": "Kilo Code", + "folder": ".kilocode/", "commands_subdir": "workflows", "install_url": None, "requires_cli": False, } registrar_config = { - "dir": ".windsurf/workflows", + "dir": ".kilocode/workflows", "format": "markdown", "args": "$ARGUMENTS", "extension": ".md", @@ -148,7 +148,7 @@ class CodexIntegration(SkillsIntegration): | `config` | Class attribute (dict) | Agent metadata: `name`, `folder`, `commands_subdir`, `install_url`, `requires_cli` | | `registrar_config` | Class attribute (dict) | Command output config: `dir`, `format`, `args` placeholder, file `extension` | -**Key design rule:** For CLI-based integrations (`requires_cli: True`), `key` must be the actual executable name (e.g., `"cursor-agent"` not `"cursor"`). This ensures `shutil.which(key)` works for CLI-tool checks without special-case mappings. IDE-based integrations (`requires_cli: False`) should use their canonical identifier (e.g., `"windsurf"`, `"copilot"`). +**Key design rule:** For CLI-based integrations (`requires_cli: True`), `key` must be the actual executable name (e.g., `"cursor-agent"` not `"cursor"`). This ensures `shutil.which(key)` works for CLI-tool checks without special-case mappings. IDE-based integrations (`requires_cli: False`) should use their canonical identifier (e.g., `"kilocode"`, `"copilot"`). ### 3. Register it @@ -201,8 +201,8 @@ Only add custom setup logic when the agent needs non-standard behavior. Integrat specify init my-project --integration # Verify files were created in the commands directory configured by -# config["folder"] + config["commands_subdir"] (for example, .windsurf/workflows/) -ls -R my-project/.windsurf/workflows/ +# config["folder"] + config["commands_subdir"] (for example, .kilocode/workflows/) +ls -R my-project/.kilocode/workflows/ # Uninstall cleanly cd my-project && specify integration uninstall diff --git a/docs/index.md b/docs/index.md index 5772d6cc9..13d5e049a 100644 --- a/docs/index.md +++ b/docs/index.md @@ -31,7 +31,7 @@ Define what to build before building it. Rich templates, quality checklists, and ### Use any coding agent -30+ integrations — Copilot, Gemini, Codex, Windsurf, Zed, Claude, Forge, Kiro, and more. Switch freely between agents with a single command. No lock-in. +30+ integrations — Copilot, Gemini, Codex, Kilo Code, Zed, Claude, Forge, Kiro, and more. Switch freely between agents with a single command. No lock-in. Run `specify init` with your agent of choice and Spec Kit sets up the right command files, context rules, and directory structures automatically. If your agent isn't listed, the `generic` integration is an escape hatch for any tool. diff --git a/docs/reference/integrations.md b/docs/reference/integrations.md index 9a567d1d3..3c48c5a48 100644 --- a/docs/reference/integrations.md +++ b/docs/reference/integrations.md @@ -38,7 +38,6 @@ The Specify CLI supports a wide range of AI coding agents. When you run `specify | [SHAI (OVHcloud)](https://github.com/ovh/shai) | `shai` | | | [Tabnine CLI](https://docs.tabnine.com/main/getting-started/tabnine-cli) | `tabnine` | | | [Trae](https://www.trae.ai/) | `trae` | Skills-based integration; skills are installed automatically | -| [Windsurf](https://windsurf.com/) | `windsurf` | | | [ZCode](https://zcode.z.ai/) | `zcode` | Skills-based integration; installs skills into `.zcode/skills/` and invokes them as `$speckit-` | | [Zed](https://zed.dev/) | `zed` | Skills-based integration; installs skills into `.agents/skills` and invokes them as `/speckit-` | | Generic | `generic` | Bring your own agent — use `--integration generic --integration-options="--commands-dir "` for AI coding agents not listed above | @@ -272,7 +271,6 @@ The currently declared multi-install safe integrations are: | `shai` | `.shai/commands`, `SHAI.md` | | `tabnine` | `.tabnine/agent/commands`, `TABNINE.md` | | `trae` | `.trae/skills`, `.trae/rules/project_rules.md` | -| `windsurf` | `.windsurf/workflows`, `.windsurf/rules/specify-rules.md` | | `zcode` | `.zcode/skills`, `ZCODE.md` | Integrations that share a context file or command directory with another integration, require dynamic install paths such as `--commands-dir`, or merge shared tool settings are not declared safe by default. They can still be installed alongside another integration with `--force`. @@ -287,7 +285,7 @@ Run `specify integration list` to see all available integrations with their keys ### Do I need the AI coding agent installed to use an integration? -CLI-based integrations (like Claude Code, Gemini CLI) require the tool to be installed. IDE-based integrations (like Windsurf, Cursor) work through the IDE itself. Some agents like GitHub Copilot support both IDE and CLI usage. `specify integration list` shows which type each integration is. +CLI-based integrations (like Claude Code, Gemini CLI) require the tool to be installed. IDE-based integrations (like Cursor) work through the IDE itself. Some agents like GitHub Copilot support both IDE and CLI usage. `specify integration list` shows which type each integration is. ### When should I use `upgrade` vs `switch`? diff --git a/docs/upgrade.md b/docs/upgrade.md index c28daf396..6c5f8a6c0 100644 --- a/docs/upgrade.md +++ b/docs/upgrade.md @@ -185,7 +185,7 @@ cp -r .specify/scripts .specify/scripts-backup ### 3. Duplicate slash commands (IDE-based agents) -Some IDE-based agents (like Kilo Code, Windsurf) may show **duplicate slash commands** after upgrading—both old and new versions appear. +Some IDE-based agents (like Kilo Code, Roo Code) may show **duplicate slash commands** after upgrading—both old and new versions appear. **Solution:** Manually delete the old command files from your agent's folder. @@ -193,7 +193,7 @@ Some IDE-based agents (like Kilo Code, Windsurf) may show **duplicate slash comm ```bash # Navigate to the agent's commands folder -cd .kilocode/rules/ +cd .kilocode/workflows/ # List files and identify duplicates ls -la @@ -242,11 +242,11 @@ mv /tmp/constitution-backup.md .specify/memory/constitution.md ### Scenario 3: "I see duplicate slash commands in my IDE" -This happens with IDE-based agents (Kilo Code, Windsurf, Roo Code, etc.). +This happens with IDE-based agents (Kilo Code, Roo Code, Cline, etc.). ```bash -# Find the agent folder (example: .kilocode/rules/) -cd .kilocode/rules/ +# Find the agent folder (example: .kilocode/workflows/) +cd .kilocode/workflows/ # List all files ls -la diff --git a/integrations/catalog.json b/integrations/catalog.json index 8167924cc..435020772 100644 --- a/integrations/catalog.json +++ b/integrations/catalog.json @@ -48,15 +48,6 @@ "repository": "https://github.com/github/spec-kit", "tags": ["ide"] }, - "windsurf": { - "id": "windsurf", - "name": "Windsurf", - "version": "1.0.0", - "description": "Windsurf IDE workflow integration", - "author": "spec-kit-core", - "repository": "https://github.com/github/spec-kit", - "tags": ["ide"] - }, "amp": { "id": "amp", "name": "Amp", diff --git a/presets/ARCHITECTURE.md b/presets/ARCHITECTURE.md index 3a119cbd5..fc043143b 100644 --- a/presets/ARCHITECTURE.md +++ b/presets/ARCHITECTURE.md @@ -99,7 +99,7 @@ The `CommandRegistrar` renders commands differently per agent: | Agent | Format | Extension | Arg placeholder | |-------|--------|-----------|-----------------| -| Claude, Cursor, opencode, Windsurf, etc. | Markdown | `.md` | `$ARGUMENTS` | +| Claude, Kilo Code, opencode, Roo Code, etc. | Markdown | `.md` | `$ARGUMENTS` | | Copilot | Markdown | `.agent.md` + `.prompt.md` | `$ARGUMENTS` | | Gemini, Qwen, Tabnine | TOML | `.toml` | `{{args}}` | diff --git a/src/specify_cli/integrations/__init__.py b/src/specify_cli/integrations/__init__.py index 374d9479f..9b643b4ee 100644 --- a/src/specify_cli/integrations/__init__.py +++ b/src/specify_cli/integrations/__init__.py @@ -80,7 +80,6 @@ def _register_builtins() -> None: from .tabnine import TabnineIntegration from .trae import TraeIntegration from .vibe import VibeIntegration - from .windsurf import WindsurfIntegration from .zcode import ZcodeIntegration from .zed import ZedIntegration @@ -118,7 +117,6 @@ def _register_builtins() -> None: _register(TabnineIntegration()) _register(TraeIntegration()) _register(VibeIntegration()) - _register(WindsurfIntegration()) _register(ZcodeIntegration()) _register(ZedIntegration()) diff --git a/src/specify_cli/integrations/windsurf/__init__.py b/src/specify_cli/integrations/windsurf/__init__.py deleted file mode 100644 index eba38fd1e..000000000 --- a/src/specify_cli/integrations/windsurf/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -"""Windsurf IDE integration.""" - -from ..base import MarkdownIntegration - - -class WindsurfIntegration(MarkdownIntegration): - key = "windsurf" - config = { - "name": "Windsurf", - "folder": ".windsurf/", - "commands_subdir": "workflows", - "install_url": None, - "requires_cli": False, - } - registrar_config = { - "dir": ".windsurf/workflows", - "format": "markdown", - "args": "$ARGUMENTS", - "extension": ".md", - } - multi_install_safe = True diff --git a/tests/integrations/test_integration_devin.py b/tests/integrations/test_integration_devin.py index 52c2981bf..9e20f2f41 100644 --- a/tests/integrations/test_integration_devin.py +++ b/tests/integrations/test_integration_devin.py @@ -28,7 +28,7 @@ class TestDevinBuildExecArgs: assert args is not None, ( "DevinIntegration.build_exec_args must not return None. " "None is the codebase sentinel for IDE-only integrations " - "(see WindsurfIntegration); Devin is dispatchable via 'devin -p'." + "(see KilocodeIntegration); Devin is dispatchable via 'devin -p'." ) assert args[:3] == ["devin", "-p", "test prompt"] diff --git a/tests/integrations/test_integration_forge.py b/tests/integrations/test_integration_forge.py index 26ac7a993..e7e9ec0e3 100644 --- a/tests/integrations/test_integration_forge.py +++ b/tests/integrations/test_integration_forge.py @@ -403,7 +403,7 @@ class TestForgeCommandRegistrar: encoding="utf-8" ) - # Register with Windsurf (standard markdown agent without inject_name) + # Register with Kilo Code (standard markdown agent without inject_name) registrar = CommandRegistrar() commands = [ { @@ -413,22 +413,22 @@ class TestForgeCommandRegistrar: ] registrar.register_commands( - "windsurf", + "kilocode", commands, "test-extension", ext_dir, tmp_path ) - # Windsurf uses standard markdown format without name injection. + # Kilo Code uses standard markdown format without name injection. # The format_name callback should not be invoked for non-Forge agents. - windsurf_cmd = tmp_path / ".windsurf" / "workflows" / "speckit.my-extension.example.md" - assert windsurf_cmd.exists() + kilocode_cmd = tmp_path / ".kilocode" / "workflows" / "speckit.my-extension.example.md" + assert kilocode_cmd.exists() - content = windsurf_cmd.read_text(encoding="utf-8") - # Windsurf should NOT have a name field injected + content = kilocode_cmd.read_text(encoding="utf-8") + # Kilo Code should NOT have a name field injected assert "name:" not in content, ( - "Windsurf should not inject name field - format_name callback should be Forge-only" + "Kilo Code should not inject name field - format_name callback should be Forge-only" ) def test_git_extension_command_uses_hyphen_notation(self, tmp_path): diff --git a/tests/integrations/test_integration_windsurf.py b/tests/integrations/test_integration_windsurf.py deleted file mode 100644 index 4cdfaa94a..000000000 --- a/tests/integrations/test_integration_windsurf.py +++ /dev/null @@ -1,10 +0,0 @@ -"""Tests for WindsurfIntegration.""" - -from .test_integration_base_markdown import MarkdownIntegrationTests - - -class TestWindsurfIntegration(MarkdownIntegrationTests): - KEY = "windsurf" - FOLDER = ".windsurf/" - COMMANDS_SUBDIR = "workflows" - REGISTRAR_DIR = ".windsurf/workflows" diff --git a/tests/integrations/test_registry.py b/tests/integrations/test_registry.py index 478bc54f5..983912197 100644 --- a/tests/integrations/test_registry.py +++ b/tests/integrations/test_registry.py @@ -23,7 +23,7 @@ ALL_INTEGRATION_KEYS = [ # Stage 3 — standard markdown integrations "claude", "qwen", "opencode", "junie", "kilocode", "auggie", "roo", "rovodev", "codebuddy", "qodercli", "amp", "shai", "bob", "trae", - "pi", "kiro-cli", "windsurf", "vibe", "cursor-agent", "firebender", + "pi", "kiro-cli", "vibe", "cursor-agent", "firebender", # Stage 4 — TOML integrations "gemini", "tabnine", # Stage 5 — skills, generic & option-driven integrations diff --git a/tests/test_agent_config_consistency.py b/tests/test_agent_config_consistency.py index d35154e86..cd1e91b7f 100644 --- a/tests/test_agent_config_consistency.py +++ b/tests/test_agent_config_consistency.py @@ -43,7 +43,6 @@ ISSUE_TEMPLATE_AGENT_KEYS = [ "shai", "tabnine", "trae", - "windsurf", "zcode", "zed", ] diff --git a/tests/test_workflows.py b/tests/test_workflows.py index ee63b36ba..e1b4a5ec2 100644 --- a/tests/test_workflows.py +++ b/tests/test_workflows.py @@ -650,8 +650,8 @@ class TestBuildExecArgs: assert "--yolo" in args def test_ide_only_returns_none(self): - from specify_cli.integrations.windsurf import WindsurfIntegration - impl = WindsurfIntegration() + from specify_cli.integrations.kilocode import KilocodeIntegration + impl = KilocodeIntegration() assert impl.build_exec_args("test") is None def test_no_model_omits_flag(self):