Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/agent_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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, iFlow CLI, 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, iFlow CLI, 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
Expand Down
1 change: 0 additions & 1 deletion .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ body:
- SHAI
- Tabnine CLI
- Trae
- Windsurf
- ZCode
- Zed
- Not applicable
Expand Down
1 change: 0 additions & 1 deletion .github/ISSUE_TEMPLATE/feature_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ body:
- SHAI
- Tabnine CLI
- Trae
- Windsurf
- ZCode
- Zed
- Not applicable
Expand Down
24 changes: 12 additions & 12 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -52,30 +52,30 @@ Most agents only need `MarkdownIntegration` — a minimal subclass with zero met

Create `src/specify_cli/integrations/<package_dir>/__init__.py`, where `<package_dir>` is the Python-safe directory name derived from `<key>`: 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",
}
context_file = ".windsurf/rules/specify-rules.md"
context_file = ".kilocode/rules/specify-rules.md"
```

**TOML agent (Gemini):**
Expand Down Expand Up @@ -152,7 +152,7 @@ class CodexIntegration(SkillsIntegration):
| `registrar_config` | Class attribute (dict) | Command output config: `dir`, `format`, `args` placeholder, file `extension` |
| `context_file` | Class attribute (str or None) | Path to agent context/instructions file (e.g., `"CLAUDE.md"`, `".github/copilot-instructions.md"`) |

**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

Expand Down Expand Up @@ -203,8 +203,8 @@ Only add custom setup logic when the agent needs non-standard behavior. Integrat
specify init my-project --integration <key>

# 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 <key>
Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Define what to build before building it. Rich templates, quality checklists, and

### Use any coding agent

<span class="pillar-stat">30+ integrations</span> — Copilot, Gemini, Codex, Windsurf, Zed, Claude, Forge, Kiro, and more. Switch freely between agents with a single command. No lock-in.
<span class="pillar-stat">30+ integrations</span> — 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.

Expand Down
4 changes: 1 addition & 3 deletions docs/reference/integrations.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,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-<command>` |
Comment thread
BenBtg marked this conversation as resolved.
| [Zed](https://zed.dev/) | `zed` | Skills-based integration; installs skills into `.agents/skills` and invokes them as `/speckit-<command>` |
| Generic | `generic` | Bring your own agent — use `--integration generic --integration-options="--commands-dir <path>"` for AI coding agents not listed above |
Expand Down Expand Up @@ -200,7 +199,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`.
Expand All @@ -215,7 +213,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.
Comment thread
BenBtg marked this conversation as resolved.

### When should I use `upgrade` vs `switch`?

Expand Down
4 changes: 2 additions & 2 deletions docs/upgrade.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -242,7 +242,7 @@ 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/)
Expand Down
9 changes: 0 additions & 9 deletions integrations/catalog.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion presets/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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}}` |

Expand Down
2 changes: 0 additions & 2 deletions src/specify_cli/integrations/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,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

Expand Down Expand Up @@ -120,7 +119,6 @@ def _register_builtins() -> None:
_register(TabnineIntegration())
_register(TraeIntegration())
_register(VibeIntegration())
_register(WindsurfIntegration())
_register(ZcodeIntegration())
_register(ZedIntegration())

Expand Down
22 changes: 0 additions & 22 deletions src/specify_cli/integrations/windsurf/__init__.py

This file was deleted.

2 changes: 1 addition & 1 deletion tests/integrations/test_integration_devin.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def test_returns_args_not_none_for_dispatch(self):
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"]

Expand Down
16 changes: 8 additions & 8 deletions tests/integrations/test_integration_forge.py
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ def test_registrar_does_not_affect_other_agents(self, tmp_path):
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 = [
{
Expand All @@ -417,22 +417,22 @@ def test_registrar_does_not_affect_other_agents(self, tmp_path):
]

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):
Expand Down
11 changes: 0 additions & 11 deletions tests/integrations/test_integration_windsurf.py

This file was deleted.

2 changes: 1 addition & 1 deletion tests/integrations/test_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
# Stage 3 — standard markdown integrations
"claude", "qwen", "opencode", "junie", "kilocode", "auggie",
"roo", "rovodev", "codebuddy", "qodercli", "amp", "shai", "bob", "trae",
"pi", "iflow", "kiro-cli", "windsurf", "vibe", "cursor-agent", "firebender",
"pi", "iflow", "kiro-cli", "vibe", "cursor-agent", "firebender",
# Stage 4 — TOML integrations
"gemini", "tabnine",
# Stage 5 — skills, generic & option-driven integrations
Expand Down
1 change: 0 additions & 1 deletion tests/test_agent_config_consistency.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
"shai",
"tabnine",
"trae",
"windsurf",
"zcode",
"zed",
]
Expand Down
4 changes: 2 additions & 2 deletions tests/test_workflows.py
Original file line number Diff line number Diff line change
Expand Up @@ -593,8 +593,8 @@ def test_copilot_new_env_var_takes_precedence(self, monkeypatch):
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):
Expand Down