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
11 changes: 6 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,14 @@ class KilocodeIntegration(MarkdownIntegration):
key = "kilocode"
config = {
"name": "Kilo Code",
"folder": ".kilocode/",
"commands_subdir": "workflows",
"folder": ".kilo/",
"commands_subdir": "commands",
"install_url": None,
"requires_cli": False,
}
registrar_config = {
"dir": ".kilocode/workflows",
"dir": ".kilo/commands",
"legacy_dir": ".kilocode/workflows",
"format": "markdown",
"args": "$ARGUMENTS",
"extension": ".md",
Expand Down Expand Up @@ -201,8 +202,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, .kilocode/workflows/)
ls -R my-project/.kilocode/workflows/
# config["folder"] + config["commands_subdir"] (for example, .kilo/commands/)
ls -R my-project/.kilo/commands/

# Uninstall cleanly
cd my-project && specify integration uninstall <key>
Expand Down
44 changes: 22 additions & 22 deletions docs/reference/integrations.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ The Specify CLI supports a wide range of AI coding agents. When you run `specify
| [Hermes](https://github.com/NousResearch/hermes-agent) | `hermes` | Skills-based integration; installs skills globally into `~/.hermes/skills/` |
| [IBM Bob](https://www.ibm.com/products/bob) | `bob` | Skills-based integration by default; installs skills as `speckit-<command>/SKILL.md` under `.bob/skills/` and invokes them as `/speckit-<command>`. Pass `--integration-options="--legacy-commands"` to scaffold the deprecated Bob 1.x layout (`.bob/commands/*.md`) instead; that flag will be removed in a future release. Existing legacy installs can migrate with `specify integration upgrade bob --integration-options="--skills"`, which converts them to the skills layout and removes the old command files. If preset overrides are installed, the migration is rejected with an actionable error (preset artifacts cannot yet be reconciled across a layout change) — remove the preset(s), migrate, then reinstall them. |
| [Junie](https://junie.jetbrains.com/) | `junie` | |
| [Kilo Code](https://github.com/Kilo-Org/kilocode) | `kilocode` | |
| [Kilo Code](https://github.com/Kilo-Org/kilocode) | `kilocode` | Installs commands into `.kilo/commands`; legacy `.kilocode/workflows` installs remain supported as a registration fallback |
| [Kimi Code](https://code.kimi.com/) | `kimi` | Skills-based integration; installs into `.kimi-code/skills/`. `--migrate-legacy` moves old `.kimi/skills/` installs to the new paths |
| [Kiro CLI](https://kiro.dev/docs/cli/) | `kiro-cli` | Kiro CLI does not substitute `$ARGUMENTS` in file-based prompts, so Spec Kit ships a prose fallback at render time (see [Manage prompts](https://kiro.dev/docs/cli/chat/manage-prompts/) and issue [#1926](https://github.com/github/spec-kit/issues/1926)). Alias: `--integration kiro` |
| [Lingma](https://lingma.aliyun.com/) | `lingma` | Skills-based integration; skills are installed automatically |
Expand Down Expand Up @@ -257,31 +257,31 @@ Spec Kit tracks one default integration in `.specify/integration.json` with `def

An integration is multi-install safe when it uses a static, unique agent root and command directory, stable command invocation settings, and a separate install manifest whose managed files do not overlap another safe integration. Registry tests enforce those path and manifest invariants. Shared Spec Kit templates remain aligned to the single default integration.

The Isolation column below lists paths Spec Kit manages for that integration (skills/commands roots and any integration-owned rule files). It is not a full inventory of every file an agent may read.

**Agent-context defaults are separate.** The optional agent-context extension maps each integration to a default context file in `extensions/agent-context/agent-context-defaults.json`. Those defaults are independent of multi-install safety: several agents may share a root file such as `AGENTS.md` when the extension is enabled. Multi-install safety does not require a unique context file per safe integration.
The Command directory column below lists the directory each integration installs its commands or skills into. Context-file targeting is a separate concern from integration multi-install safety: `multi_install_safe` is an integration declaration about command/skill paths, whereas the optional agent-context extension manages a per-agent context file (for example `AGENTS.md` or `CLAUDE.md`) and can even synchronize several anchors at once via its `context_files` setting. Multiple agents mapping to the same context file is expected there and does not affect whether an integration is multi-install safe; see the agent-context extension for details.

The currently declared multi-install safe integrations are:

| Key | Isolation |
| --- | --------- |
| `auggie` | `.augment/commands`, `.augment/rules/specify-rules.md` |
| `claude` | `.claude/skills`, `CLAUDE.md` |
| `cline` | `.clinerules/workflows`, `.clinerules/specify-rules.md` |
| `codebuddy` | `.codebuddy/commands`, `CODEBUDDY.md` |
| `codex` | `.agents/skills`, `AGENTS.md` |
| `cursor-agent` | `.cursor/skills`, `.cursor/rules/specify-rules.mdc` |
| `firebender` | `.firebender/commands`, `.firebender/rules/specify-rules.mdc` |
| `gemini` | `.gemini/commands`, `GEMINI.md` |
| Key | Command directory |
| --- | ----------------- |
| `auggie` | `.augment/commands` |
| `claude` | `.claude/skills` |
| `cline` | `.clinerules/workflows` |
| `codebuddy` | `.codebuddy/commands` |
| `codex` | `.agents/skills` |
| `cursor-agent` | `.cursor/skills` |
| `firebender` | `.firebender/commands` |
| `gemini` | `.gemini/commands` |
| `grok` | `.grok/skills` |
| `junie` | `.junie/commands`, `.junie/AGENTS.md` |
| `kilocode` | `.kilocode/workflows`, `.kilocode/rules/specify-rules.md` |
| `qodercli` | `.qoder/commands`, `QODER.md` |
| `qwen` | `.qwen/commands`, `QWEN.md` |
| `shai` | `.shai/commands`, `SHAI.md` |
| `tabnine` | `.tabnine/agent/commands`, `TABNINE.md` |
| `trae` | `.trae/skills`, `.trae/rules/project_rules.md` |
| `zcode` | `.zcode/skills`, `ZCODE.md` |
| `junie` | `.junie/commands` |
| `kilocode` | `.kilo/commands` |
| `kiro-cli` | `.kiro/prompts` |
| `omp` | `.omp/commands` |
| `qodercli` | `.qoder/commands` |
| `qwen` | `.qwen/commands` |
| `shai` | `.shai/commands` |
| `tabnine` | `.tabnine/agent/commands` |
| `trae` | `.trae/skills` |
| `zcode` | `.zcode/skills` |

Integrations that share a 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 Down
22 changes: 9 additions & 13 deletions docs/upgrade.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,15 +195,13 @@ Some IDE-based agents (like Kilo Code, Cline) may show **duplicate slash command
**Example for Kilo Code:**

```bash
# Navigate to the agent's commands folder
cd .kilocode/workflows/

# List files and identify duplicates
ls -la
# List current and legacy Kilo command folders
ls -la .kilo/commands/
ls -la .kilocode/workflows/

# Delete old versions (example filenames - yours may differ)
rm speckit.specify-old.md
rm speckit.plan-v1.md
rm .kilocode/workflows/speckit.specify-old.md
rm .kilocode/workflows/speckit.plan-v1.md
```

Restart your IDE to refresh the command list.
Expand Down Expand Up @@ -248,14 +246,12 @@ specify extension update
This happens with IDE-based agents (Kilo Code, Cline, etc.).

```bash
# Find the agent folder (example: .kilocode/workflows/)
cd .kilocode/workflows/

# List all files
ls -la
# For Kilo Code, inspect both current and legacy command folders
ls -la .kilo/commands/
ls -la .kilocode/workflows/

# Delete old command files
rm speckit.old-command-name.md
rm .kilocode/workflows/speckit.old-command-name.md

# Restart your IDE
```
Expand Down
21 changes: 19 additions & 2 deletions src/specify_cli/extensions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2177,14 +2177,28 @@ def _valid_name_list(value: Any) -> List[str]:
return []
return [item for item in value if isinstance(item, str)]

def unregister_agent_artifacts(self, agent_name: str) -> None:
def unregister_agent_artifacts(
self,
agent_name: str,
*,
enabled_only: bool = False,
commands_only: bool = False,
) -> None:
"""Remove extension files registered for a specific agent.

Extension command files are tracked per agent in ``registered_commands``.
Extension skills are scoped to the provided *agent_name*; they are removed
from that agent's skills directory (resolved via its integration config)
and the registry field is cleared.

Set ``enabled_only=True`` when a caller is about to re-register enabled
extensions and must preserve disabled extensions' existing artifacts and
registry entries.

Set ``commands_only=True`` for command-directory reconciliation where
skill artifacts are outside the target agent's lifecycle and must not
be touched.

Skips cleanup when *agent_name* is not a supported agent to avoid
losing registry entries while leaving orphaned files on disk.
"""
Expand All @@ -2203,6 +2217,9 @@ def unregister_agent_artifacts(self, agent_name: str) -> None:
agent_skills_dir = resolve_skills_dir(self.project_root, agent_name)

for ext_id, metadata in self.registry.list().items():
if enabled_only and not metadata.get("enabled", True):
continue

updates: Dict[str, Any] = {}

registered_commands = metadata.get("registered_commands", {})
Expand All @@ -2225,7 +2242,7 @@ def unregister_agent_artifacts(self, agent_name: str) -> None:
registered_skills = self._valid_name_list(
metadata.get("registered_skills", [])
)
if registered_skills:
if registered_skills and not commands_only:
# Only pass the resolved skills_dir when it actually exists.
# Otherwise let _unregister_extension_skills fall back to
# scanning all known agent skills directories, which is useful
Expand Down
20 changes: 20 additions & 0 deletions src/specify_cli/integrations/_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,26 @@ def _unregister_extensions_for_agent(
)


def _unregister_enabled_extension_commands_for_agent(
project_root: Path,
agent_key: str,
*,
continuing: str,
) -> None:
"""Best-effort removal of enabled extension command artifacts for ``agent_key``."""
_best_effort_extension_op(
project_root,
agent_key,
lambda mgr, key: mgr.unregister_agent_artifacts(
key,
enabled_only=True,
commands_only=True,
),
phase="clean up enabled extension command artifacts for",
continuing=continuing,
)


# ---------------------------------------------------------------------------
# CLI formatting helpers (re-exported from _commands.py)
# ---------------------------------------------------------------------------
Expand Down
Loading