Skip to content
Merged
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: 11 additions & 0 deletions .changeset/kind-rings-notice.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"@fission-ai/openspec": minor
---

### New Features

- **Kimi CLI support** — OpenSpec can now initialize Kimi CLI as a supported skills-only tool using `.kimi/skills/`

### Other

- Added Kimi-specific docs and init coverage aligned with skill-based `/skill:openspec-*` usage
2 changes: 1 addition & 1 deletion docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ openspec init [path] [options]

`--profile custom` uses whatever workflows are currently selected in global config (`openspec config profile`).

**Supported tool IDs (`--tools`):** `amazon-q`, `antigravity`, `auggie`, `claude`, `cline`, `codex`, `codebuddy`, `continue`, `costrict`, `crush`, `cursor`, `factory`, `gemini`, `github-copilot`, `iflow`, `kilocode`, `kiro`, `opencode`, `pi`, `qoder`, `qwen`, `roocode`, `trae`, `windsurf`
**Supported tool IDs (`--tools`):** `amazon-q`, `antigravity`, `auggie`, `claude`, `cline`, `codex`, `codebuddy`, `continue`, `costrict`, `crush`, `cursor`, `factory`, `gemini`, `github-copilot`, `iflow`, `kilocode`, `kimi`, `kiro`, `opencode`, `pi`, `qoder`, `qwen`, `roocode`, `trae`, `windsurf`
Comment thread
Miss-you marked this conversation as resolved.

**Examples:**

Expand Down
1 change: 1 addition & 0 deletions docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,7 @@ Different AI tools use slightly different command syntax. Use the format that ma
| Cursor | `/opsx-propose`, `/opsx-apply` |
| Windsurf | `/opsx-propose`, `/opsx-apply` |
| Copilot (IDE) | `/opsx-propose`, `/opsx-apply` |
| Kimi CLI | Skill-based invocations such as `/skill:openspec-propose`, `/skill:openspec-apply-change` (no generated `opsx-*` command files) |
| Trae | Skill-based invocations such as `/openspec-propose`, `/openspec-apply-change` (no generated `opsx-*` command files) |

The intent is the same across tools, but how commands are surfaced can differ by integration.
Expand Down
3 changes: 2 additions & 1 deletion docs/supported-tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ You can enable expanded workflows (`new`, `continue`, `ff`, `verify`, `sync`, `b
| iFlow (`iflow`) | `.iflow/skills/openspec-*/SKILL.md` | `.iflow/commands/opsx-<id>.md` |
| Junie (`junie`) | `.junie/skills/openspec-*/SKILL.md` | `.junie/commands/opsx-<id>.md` |
| Kilo Code (`kilocode`) | `.kilocode/skills/openspec-*/SKILL.md` | `.kilocode/workflows/opsx-<id>.md` |
| Kimi CLI (`kimi`) | `.kimi/skills/openspec-*/SKILL.md` | Not generated (no command adapter; use skill-based `/skill:openspec-*` invocations) |
| Kiro (`kiro`) | `.kiro/skills/openspec-*/SKILL.md` | `.kiro/prompts/opsx-<id>.prompt.md` |
| OpenCode (`opencode`) | `.opencode/skills/openspec-*/SKILL.md` | `.opencode/commands/opsx-<id>.md` |
| Pi (`pi`) | `.pi/skills/openspec-*/SKILL.md` | `.pi/prompts/opsx-<id>.md` |
Expand Down Expand Up @@ -71,7 +72,7 @@ openspec init --tools none
openspec init --profile core
```

**Available tool IDs (`--tools`):** `amazon-q`, `antigravity`, `auggie`, `bob`, `claude`, `cline`, `codex`, `codebuddy`, `continue`, `costrict`, `crush`, `cursor`, `factory`, `forgecode`, `gemini`, `github-copilot`, `iflow`, `junie`, `kilocode`, `kiro`, `opencode`, `pi`, `qoder`, `qwen`, `roocode`, `trae`, `windsurf`
**Available tool IDs (`--tools`):** `amazon-q`, `antigravity`, `auggie`, `bob`, `claude`, `cline`, `codex`, `codebuddy`, `continue`, `costrict`, `crush`, `cursor`, `factory`, `forgecode`, `gemini`, `github-copilot`, `iflow`, `junie`, `kilocode`, `kimi`, `kiro`, `opencode`, `pi`, `qoder`, `qwen`, `roocode`, `trae`, `windsurf`
Comment thread
Miss-you marked this conversation as resolved.

## Workflow-Dependent Installation

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-04-23
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# add-kimi-cli-skills-only-support

Add Kimi CLI as a supported skills-only tool without a command adapter
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
## Context

Kimi CLI is not another Claude/Codex-style adapter target. Its extension model is built around discovered skills, not external command files:

- skills are discovered from `.kimi/skills/`
- skills are exposed as `/skill:<name>`
- no stable `.kimi/commands/` or prompt-file loading mechanism was found in the Kimi CLI codebase

OpenSpec's existing architecture can already represent that shape:

- `AI_TOOLS` can advertise a `skillsDir`
- `init` can install skills for any selected tool with `skillsDir`
- when command generation is attempted for a tool without an adapter, OpenSpec already records `commandsSkipped`

## Goals

- Add Kimi CLI using the same narrow `skills-only` pattern already used by Trae
- Keep the implementation small: metadata, docs, and a focused regression test
- Make the spec text match the current code path for adapterless tools

## Non-Goals

- designing a Kimi-specific command adapter without upstream support
- changing tool capability modeling across the whole generation pipeline
- reworking `delivery=commands` behavior for all adapterless tools

## Decisions

### 1. Represent Kimi CLI as an adapterless tool with `.kimi`

Add a new `AI_TOOLS` entry:

```ts
{ name: 'Kimi CLI', value: 'kimi', available: true, successLabel: 'Kimi CLI', skillsDir: '.kimi' }
```

This matches Kimi CLI's project-local skills root and lets existing init/update detection paths treat it as a supported tool.

### 2. Do not add a Kimi command adapter

No `src/core/command-generation/adapters/kimi.ts` file will be added, and the command adapter registry will remain unchanged.

Rationale:

- Kimi CLI exposes skills dynamically as `/skill:<name>`
- the previous upstream PR stalled specifically because no legitimate adapter target was available
- adding a fake `.kimi/commands/...` path would create behavior OpenSpec cannot justify against upstream Kimi CLI behavior

### 3. Document Kimi by its real invocation surface

Kimi documentation in OpenSpec must use Kimi's actual skill invocation form:

- supported-tools: no generated command files, use `/skill:openspec-*`
- commands doc: examples such as `/skill:openspec-propose`

The docs must not claim generated `opsx-*` files or `/openspec-*` direct invocations for Kimi.

### 4. Keep the change compatible with existing Trae-style behavior

This change intentionally follows the current adapterless-tool behavior already present in the codebase:

- skills are created whenever delivery includes skills
- command generation is skipped when no adapter exists
- init output reports `Commands skipped for: kimi (no adapter)`

This keeps the Kimi change small and avoids overlapping implementation work already captured in `add-tool-command-surface-capabilities`.

## Test Strategy

Add one focused regression test in `test/core/init.test.ts`:

- configure `delivery=both`
- run init with `--tools kimi`
- verify Kimi skills are created under `.kimi/skills/...`
- verify init reports the skipped command generation path for `kimi`

That test is enough for this narrow change because:

- adapterless update behavior already has generic coverage
- CLI tool-id rendering is derived from `AI_TOOLS`
- no command adapter or path formatting logic is being introduced

## Risks / Trade-offs

The main trade-off is scope: Kimi will inherit the current adapterless-tool behavior, including the broader limitation that `delivery=commands` is not yet capability-aware for skills-invocable tools. That is acceptable for this change because it matches the existing Trae/ForgeCode model and keeps the implementation aligned with verified Kimi CLI behavior.
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
## Why

OpenSpec already has user demand for Kimi CLI support, but the previous upstream attempt stalled because it assumed Kimi needed a command adapter. Local review of the Kimi CLI codebase shows a different integration surface: Kimi discovers `SKILL.md` files from `.kimi/skills/` and exposes them through `/skill:<name>`, but it does not provide a stable, file-based custom command directory like Claude Code or Codex.

OpenSpec already supports tools that install skills without a command adapter. Trae and ForgeCode are the existing examples. Kimi should follow the same pattern instead of introducing undocumented `.kimi/commands/...` behavior.

## What Changes

- Add Kimi CLI as a supported tool in `AI_TOOLS` with `skillsDir: '.kimi'`
- Document Kimi CLI as a skills-only integration in supported tools and command usage docs
- Align change specs so `cli-init` explicitly allows selected tools with `skillsDir` but no registered command adapter

## Capabilities

### New Capabilities

_None._

### Modified Capabilities

- `ai-tool-paths`: define the `.kimi` skills root for Kimi CLI
- `cli-init`: clarify that adapterless tools remain valid selections and skip command-file generation with an informational message

## Impact

- `src/core/config.ts` - add Kimi CLI tool metadata
- `docs/supported-tools.md` - add Kimi CLI row and tool id
- `docs/commands.md` - document `/skill:openspec-*` usage for Kimi CLI
- `docs/cli.md` - include `kimi` in the supported `--tools` list
- `test/core/init.test.ts` - cover Kimi CLI as an adapterless tool during init

## Non-Goals

- Adding `src/core/command-generation/adapters/kimi.ts`
- Defining a `.kimi/commands/...` output path
- Changing the broader delivery model for adapterless tools under `delivery=commands`

That broader capability-aware delivery work is already being explored separately in `add-tool-command-surface-capabilities`. This change stays narrow and follows the existing Trae/ForgeCode pattern.
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# ai-tool-paths Delta Specification

## MODIFIED Requirements

### Requirement: Path configuration for supported tools

The `AI_TOOLS` array SHALL include `skillsDir` for tools that support the Agent Skills specification.

#### Scenario: Kimi CLI paths defined

- **WHEN** looking up the `kimi` tool
- **THEN** `skillsDir` SHALL be `.kimi`
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# cli-init Delta Specification

## MODIFIED Requirements

### Requirement: Slash Command Generation

The command SHALL generate opsx slash commands only for selected tools that have a registered command adapter, while keeping adapterless tools valid for skill generation.

#### Scenario: Generating slash commands for a tool with a registered adapter

- **WHEN** a tool with a registered command adapter is selected during initialization
- **THEN** create 9 slash command files using the tool's command adapter:
- `/opsx:explore`
- `/opsx:new`
- `/opsx:continue`
- `/opsx:apply`
- `/opsx:ff`
- `/opsx:verify`
- `/opsx:sync`
- `/opsx:archive`
- `/opsx:bulk-archive`
- **AND** use tool-specific path conventions (e.g., `.claude/commands/opsx/` for Claude)
- **AND** include tool-specific frontmatter format

#### Scenario: Selected tool has no command adapter

- **GIVEN** a selected tool has `skillsDir` configured but no registered command adapter
- **WHEN** initialization includes command generation
- **THEN** skill generation for that tool SHALL still remain valid
- **AND** command-file generation SHALL be skipped for that tool
- **AND** the command output SHALL include `Commands skipped for: <tool-id> (no adapter)`

#### Scenario: Kimi CLI skips command-file generation

- **WHEN** the user selects Kimi CLI during initialization
- **THEN** OpenSpec SHALL treat it as a supported tool with `skillsDir: '.kimi'`
- **AND** command-file generation SHALL be skipped because no Kimi adapter is registered
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
## 1. Change Artifacts

- [x] 1.1 Write proposal, design, and spec deltas for Kimi CLI skills-only support

## 2. Tool Metadata

- [x] 2.1 Add `Kimi CLI` to `src/core/config.ts` with `value: 'kimi'` and `skillsDir: '.kimi'`

## 3. Documentation

- [x] 3.1 Update `docs/supported-tools.md` with a Kimi CLI row that clearly states there is no command adapter
- [x] 3.2 Update `docs/commands.md` to document Kimi CLI usage via `/skill:openspec-*`
- [x] 3.3 Update `docs/cli.md` so the supported `--tools` list includes `kimi`

## 4. Tests

- [x] 4.1 Add a targeted init regression test for `--tools kimi` under adapterless command generation

## 5. Validation

- [x] 5.1 Validate the change artifacts with `openspec validate`
- [x] 5.2 Run targeted tests and fix any regressions
7 changes: 5 additions & 2 deletions openspec/specs/ai-tool-paths/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

## Purpose
Define AI tool path metadata used to generate OpenSpec skills and commands in tool-specific directories.

## Requirements
### Requirement: AIToolOption skillsDir field

Expand Down Expand Up @@ -38,6 +37,11 @@ The `AI_TOOLS` array SHALL include `skillsDir` for tools that support the Agent
- **WHEN** looking up the `windsurf` tool
- **THEN** `skillsDir` SHALL be `.windsurf`

#### Scenario: Kimi CLI paths defined

- **WHEN** looking up the `kimi` tool
- **THEN** `skillsDir` SHALL be `.kimi`

#### Scenario: Tools without skillsDir

- **WHEN** a tool has no `skillsDir` defined
Expand All @@ -57,4 +61,3 @@ The system SHALL handle paths correctly across operating systems.

- **WHEN** constructing skill paths on macOS or Linux
- **THEN** the system SHALL use `path.join()` for consistency

20 changes: 17 additions & 3 deletions openspec/specs/cli-init/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,11 +200,11 @@ The command SHALL generate Agent Skills for selected AI tools.

### Requirement: Slash Command Generation

The command SHALL generate opsx slash commands for selected AI tools.
The command SHALL generate opsx slash commands only for selected tools that have a registered command adapter, while keeping adapterless tools valid for skill generation.

#### Scenario: Generating slash commands for a tool
#### Scenario: Generating slash commands for a tool with a registered adapter

- **WHEN** a tool is selected during initialization
- **WHEN** a tool with a registered command adapter is selected during initialization
- **THEN** create 9 slash command files using the tool's command adapter:
- `/opsx:explore`
- `/opsx:new`
Expand All @@ -218,6 +218,20 @@ The command SHALL generate opsx slash commands for selected AI tools.
- **AND** use tool-specific path conventions (e.g., `.claude/commands/opsx/` for Claude)
- **AND** include tool-specific frontmatter format

#### Scenario: Selected tool has no command adapter

- **GIVEN** a selected tool has `skillsDir` configured but no registered command adapter
- **WHEN** initialization includes command generation
- **THEN** skill generation for that tool SHALL still remain valid
- **AND** command-file generation SHALL be skipped for that tool
- **AND** the command output SHALL include `Commands skipped for: <tool-id> (no adapter)`

#### Scenario: Kimi CLI skips command-file generation

- **WHEN** the user selects Kimi CLI during initialization
- **THEN** OpenSpec SHALL treat it as a supported tool with `skillsDir: '.kimi'`
- **AND** command-file generation SHALL be skipped because no Kimi adapter is registered

### Requirement: Config File Generation

The command SHALL create an OpenSpec config file with schema settings.
Expand Down
1 change: 1 addition & 0 deletions src/core/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export const AI_TOOLS: AIToolOption[] = [
{ name: 'iFlow', value: 'iflow', available: true, successLabel: 'iFlow', skillsDir: '.iflow' },
{ name: 'Junie', value: 'junie', available: true, successLabel: 'Junie', skillsDir: '.junie' },
{ name: 'Kilo Code', value: 'kilocode', available: true, successLabel: 'Kilo Code', skillsDir: '.kilocode' },
{ name: 'Kimi CLI', value: 'kimi', available: true, successLabel: 'Kimi CLI', skillsDir: '.kimi' },
{ name: 'Kiro', value: 'kiro', available: true, successLabel: 'Kiro', skillsDir: '.kiro' },
{ name: 'OpenCode', value: 'opencode', available: true, successLabel: 'OpenCode', skillsDir: '.opencode' },
{ name: 'Pi', value: 'pi', available: true, successLabel: 'Pi', skillsDir: '.pi' },
Expand Down
24 changes: 24 additions & 0 deletions test/core/init.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,30 @@ describe('InitCommand', () => {
expect(await fileExists(skillFile)).toBe(true);
});

it('should support Kimi CLI as an adapterless skills-only tool', async () => {
saveGlobalConfig({
featureFlags: {},
profile: 'core',
delivery: 'both',
});

const initCommand = new InitCommand({ tools: 'kimi', force: true });
await initCommand.execute(testDir);

const skillFile = path.join(testDir, '.kimi', 'skills', 'openspec-explore', 'SKILL.md');
expect(await fileExists(skillFile)).toBe(true);

const commandsDir = path.join(testDir, '.kimi', 'commands');
expect(await directoryExists(commandsDir)).toBe(false);

const logCalls = (console.log as unknown as { mock: { calls: unknown[][] } }).mock.calls.flat().map(String);
expect(
logCalls.some(
(entry) => entry.includes('Commands skipped for: kimi') && entry.includes('(no adapter)'),
),
).toBe(true);
});

it('should create skills for multiple tools at once', async () => {
const initCommand = new InitCommand({ tools: 'claude,cursor', force: true });

Expand Down
Loading