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 docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,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`, `bob`, `claude`, `cline`, `codex`, `forgecode`, `codebuddy`, `continue`, `costrict`, `crush`, `cursor`, `factory`, `gemini`, `github-copilot`, `iflow`, `junie`, `kilocode`, `kimi`, `kiro`, `lingma`, `vibe`, `oh-my-pi`, `opencode`, `pi`, `qoder`, `qwen`, `roocode`, `trae`, `windsurf`
**Supported tool IDs (`--tools`):** `amazon-q`, `antigravity`, `auggie`, `bob`, `claude`, `cline`, `codex`, `forgecode`, `codebuddy`, `continue`, `costrict`, `crush`, `cursor`, `factory`, `gemini`, `github-copilot`, `grok`, `iflow`, `junie`, `kilocode`, `kimi`, `kiro`, `lingma`, `vibe`, `oh-my-pi`, `opencode`, `pi`, `qoder`, `qwen`, `roocode`, `trae`, `windsurf`

> This list mirrors `AI_TOOLS` in `src/core/config.ts`. See [Supported Tools](supported-tools.md) for each tool's skill and command paths.

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

Expand Down
1 change: 1 addition & 0 deletions docs/how-commands-work.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ The intent is identical everywhere. The punctuation differs. Use the form that m
| Windsurf | `/opsx-propose`, `/opsx-apply` |
| GitHub Copilot (IDE) | `/opsx-propose`, `/opsx-apply` |
| Oh My Pi | `/opsx-propose`, `/opsx-apply` |
| Grok Build | skill-style, e.g. `/openspec-propose` |
| Kimi CLI | skill-style, e.g. `/skill:openspec-propose` |
| Trae | `/opsx-propose`, `/opsx-apply` |

Expand Down
3 changes: 2 additions & 1 deletion docs/supported-tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ You can enable expanded workflows (`new`, `continue`, `ff`, `verify`, `bulk-arch
| Factory Droid (`factory`) | `.factory/skills/openspec-*/SKILL.md` | `.factory/commands/opsx-<id>.md` |
| Gemini CLI (`gemini`) | `.gemini/skills/openspec-*/SKILL.md` | `.gemini/commands/opsx/<id>.toml` |
| GitHub Copilot (`github-copilot`) | `.github/skills/openspec-*/SKILL.md` | `.github/prompts/opsx-<id>.prompt.md`\*\* |
| Grok Build (`grok`) | `.grok/skills/openspec-*/SKILL.md` | Not generated (no command adapter; use skill-based `/openspec-*` invocations) |
| 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` |
Expand Down Expand Up @@ -76,7 +77,7 @@ openspec init --tools none
openspec init --profile core
```

**Available tool IDs (`--tools`):** `amazon-q`, `antigravity`, `auggie`, `bob`, `claude`, `cline`, `codex`, `forgecode`, `codebuddy`, `continue`, `costrict`, `crush`, `cursor`, `factory`, `gemini`, `github-copilot`, `iflow`, `junie`, `kilocode`, `kimi`, `kiro`, `lingma`, `vibe`, `oh-my-pi`, `opencode`, `pi`, `qoder`, `qwen`, `roocode`, `trae`, `windsurf`
**Available tool IDs (`--tools`):** `amazon-q`, `antigravity`, `auggie`, `bob`, `claude`, `cline`, `codex`, `forgecode`, `codebuddy`, `continue`, `costrict`, `crush`, `cursor`, `factory`, `gemini`, `github-copilot`, `grok`, `iflow`, `junie`, `kilocode`, `kimi`, `kiro`, `lingma`, `vibe`, `oh-my-pi`, `opencode`, `pi`, `qoder`, `qwen`, `roocode`, `trae`, `windsurf`

## Workflow-Dependent Installation

Expand Down
2 changes: 1 addition & 1 deletion docs/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ If `/opsx:propose` (or your tool's equivalent) doesn't appear or doesn't do anyt

5. **Check you initialized this project.** Skills are written per project. If you cloned a repo or switched folders, run `openspec init` (or `openspec update`) there.

6. **Confirm your tool supports command files.** A few tools (Kimi CLI, ForgeCode, Mistral Vibe) don't get generated `opsx-*` command files; they use skill-based invocations instead. The forms differ per tool: see [Supported Tools](supported-tools.md) and [How Commands Work](how-commands-work.md#slash-command-syntax-by-tool).
6. **Confirm your tool supports command files.** A few tools (Kimi CLI, ForgeCode, Mistral Vibe, Grok Build) don't get generated `opsx-*` command files; they use skill-based invocations instead. The forms differ per tool: see [Supported Tools](supported-tools.md) and [How Commands Work](how-commands-work.md#slash-command-syntax-by-tool).

## Working with changes

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-07-11
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
## Context

Grok Build (CLI binary `grok`) is not a Claude/Codex-style command-file adapter target. Its documented extension model is skill-centric:

- project skills from `./.grok/skills/` (walked up to the repo root)
- user skills from `~/.grok/skills/`
- plugin skills and optional `[skills] paths` in config
- user-invocable skills appear as slash commands: `/<skill-name>`
- core TUI commands (`/plan`, `/model`, `/skills`, …) are built-in, not project-generated files
- no documented project-local `.grok/commands/` layout for custom OpenSpec command generation

Grok also has Claude/Cursor compatibility scanners that can free-ride existing `.claude/skills` or `.cursor/skills`. That is a personal workaround, not the product integration: OpenSpec should own a native `.grok` skills install so pure-Grok users and multi-tool projects get first-class init/update behavior.

OpenSpec already represents this shape:

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

## Goals / Non-Goals

**Goals:**

- Add Grok Build using the same narrow skills-only pattern as Kimi CLI / ForgeCode / Mistral Vibe
- Keep the implementation small: metadata, docs, focused regression test, changeset
- Align specs with the existing adapterless code path

**Non-Goals:**

- designing a Grok-specific command adapter without a documented project command-file surface
- relying on Claude/Cursor free-ride as the supported integration
- changing tool capability modeling or `delivery=commands` behavior for all adapterless tools (tracked in `add-tool-command-surface-capabilities`)

## Decisions

### 1. Represent Grok Build as an adapterless tool with `.grok`

Add a new `AI_TOOLS` entry:

```ts
{ name: 'Grok Build', value: 'grok', available: true, successLabel: 'Grok Build', skillsDir: '.grok' }
```

Rationale for IDs:

- `value: 'grok'` matches the CLI binary and the project directory `.grok` (same pattern as `claude` → `.claude`, `kimi` → `.kimi`)
- display name `Grok Build` matches xAI product naming
- alternatives considered: `grok-build` (product-accurate but inconsistent with other short tool IDs)

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

No `src/core/command-generation/adapters/grok.ts`, and no registry change.

Rationale:

- skills are the documented custom extension surface and already become slash commands
- inventing `.grok/commands/...` would create OpenSpec behavior that cannot be justified against xAI docs
- existing adapterless path already skips command generation with an informational message

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

Grok docs in OpenSpec must use skill-name slash form:

- supported-tools: no generated command files; use skill-based `/openspec-*` invocations
- commands / how-commands-work: examples such as `/openspec-propose`, `/openspec-apply-change`

Do not claim generated `opsx-*` files or Claude-style `/opsx:propose` as Grok's primary surface.

### 4. Treat Claude free-ride as out-of-scope workaround, not design

Grok can discover Claude skills when compat scanners are enabled. Native `.grok` support remains required because:

- pure Grok users may never select Claude
- free-ride couples Grok to Claude layout and can be disabled via Grok config/env
- OpenSpec update tracks configured tools by skillsDir presence; free-ride never registers Grok

If both Claude and Grok are configured, duplicate skill discovery is acceptable; `.grok` remains the canonical OpenSpec target for Grok Build.

### 5. Keep behavior aligned with current adapterless tools

- skills are created whenever delivery includes skills
- command generation is skipped when no adapter exists
- init output reports `Commands skipped for: grok (no adapter)`
- update refreshes Grok when `.grok/skills/openspec-*` exists

## Test Strategy

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

- configure `delivery=both`
- run init with `--tools grok`
- verify skills under `.grok/skills/...` (use `path.join` for expectations)
- verify no `.grok/commands` directory is created
- verify init log includes skipped command generation for `grok` with `(no adapter)` (use relaxed `.some()` matching, as in the Kimi follow-up commit)

That is enough 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 introduced

## Risks / Trade-offs

| Risk | Mitigation |
|------|------------|
| Users confuse Claude free-ride with native support | Document native `.grok` path; optional brief note that Claude compat is separate |
| `delivery=commands` still not capability-aware for skills-only tools | Accept same limitation as Kimi/ForgeCode/Vibe; capability work is separate |
| Duplicate skills when both Claude and Grok selected | Acceptable; document that Grok may see both trees |
| xAI later documents project command files | Skills-only remains correct today; adapter can be added later without breaking skills |
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
## Why

xAI Grok Build is a coding agent with a documented project skills root at `.grok/skills/`, and user-invocable skills surface as slash commands (`/<skill-name>`). OpenSpec does not yet list Grok Build as a supported tool, so users must free-ride on Claude/Cursor compat scanners or configure extra skill paths manually.

OpenSpec already supports adapterless skills-only tools (Kimi CLI, ForgeCode, Mistral Vibe). Grok Build should follow that pattern: install skills under `.grok/skills/` without inventing a command adapter for a project command-file surface that xAI docs do not define.

## What Changes

- Add Grok Build as a supported tool in `AI_TOOLS` with `value: 'grok'` and `skillsDir: '.grok'`
- Document Grok Build as a skills-only integration (no generated `opsx-*` command files; invoke via `/openspec-*` skill names)
- Align specs so `ai-tool-paths` and `cli-init` cover the Grok Build path and adapterless init behavior

## Capabilities

### New Capabilities

_None._

### Modified Capabilities

- `ai-tool-paths`: define the `.grok` skills root for Grok Build
- `cli-init`: treat Grok Build as a supported adapterless selection that still generates skills and skips command-file generation

## Impact

- `src/core/config.ts` - add Grok Build tool metadata
- `docs/supported-tools.md` - add Grok Build row and tool id
- `docs/commands.md` - document `/openspec-*` skill invocations for Grok Build
- `docs/how-commands-work.md` - include Grok Build in slash-syntax table
- `docs/cli.md` - include `grok` in the supported `--tools` list
- `docs/troubleshooting.md` - list Grok Build among skills-only tools
- `test/core/init.test.ts` - cover Grok Build as an adapterless tool during init
- `.changeset/` - minor release note for the new tool

## Non-Goals

- Adding `src/core/command-generation/adapters/grok.ts`
- Defining a `.grok/commands/...` output path
- Relying on Claude/Cursor free-ride as the product integration
- Changing the broader delivery model for adapterless tools under `delivery=commands` (tracked separately in `add-tool-command-surface-capabilities`)
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# 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: Claude Code paths defined

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

#### Scenario: Cursor paths defined

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

#### Scenario: Windsurf paths defined

- **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: Grok Build paths defined

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

#### Scenario: Tools without skillsDir

- **WHEN** a tool has no `skillsDir` defined
- **THEN** skill generation SHALL error with message indicating the tool is not supported
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# 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

#### Scenario: Grok Build skips command-file generation

- **WHEN** the user selects Grok Build during initialization
- **THEN** OpenSpec SHALL treat it as a supported tool with `skillsDir: '.grok'`
- **AND** command-file generation SHALL be skipped because no Grok adapter is registered
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
## 1. Tool Metadata

- [x] 1.1 Add `Grok Build` to `src/core/config.ts` with `value: 'grok'`, `successLabel: 'Grok Build'`, and `skillsDir: '.grok'` (alphabetically near related tools)

## 2. Documentation

- [x] 2.1 Update `docs/supported-tools.md` with a Grok Build row (`skillsDir` `.grok`, no command adapter; skill-based `/openspec-*` invocations) and add `grok` to the `--tools` list
- [x] 2.2 Update `docs/commands.md` to document Grok Build skill invocations such as `/openspec-propose`, `/openspec-apply-change`
- [x] 2.3 Update `docs/how-commands-work.md` slash-syntax table to include Grok Build (`/openspec-*` skill form)
- [x] 2.4 Update `docs/cli.md` so the supported `--tools` list includes `grok`
- [x] 2.5 Update `docs/troubleshooting.md` skills-only tool list to include Grok Build

## 3. Tests

- [x] 3.1 Add a targeted init regression test for `--tools grok` with `delivery=both`: skills under `.grok/skills/...`, no `.grok/commands`, and commands-skipped log for `grok` `(no adapter)` using relaxed log matching and `path.join` expectations

## 4. Release Notes

- [x] 4.1 Add a changeset noting Grok Build as a supported skills-only tool via `.grok/skills/`

## 5. Validation

- [x] 5.1 Validate the change artifacts with `openspec validate add-grok-build-skills-only-support --strict` (or project-equivalent)
- [x] 5.2 Run targeted tests (`test/core/init.test.ts` Grok case) and fix any regressions
5 changes: 5 additions & 0 deletions openspec/specs/ai-tool-paths/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ The `AI_TOOLS` array SHALL include `skillsDir` for tools that support the Agent
- **WHEN** looking up the `kimi` tool
- **THEN** `skillsDir` SHALL be `.kimi`

#### Scenario: Grok Build paths defined

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

#### Scenario: Tools without skillsDir

- **WHEN** a tool has no `skillsDir` defined
Expand Down
6 changes: 6 additions & 0 deletions openspec/specs/cli-init/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,12 @@ The command SHALL generate opsx slash commands only for selected tools that have
- **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

#### Scenario: Grok Build skips command-file generation

- **WHEN** the user selects Grok Build during initialization
- **THEN** OpenSpec SHALL treat it as a supported tool with `skillsDir: '.grok'`
- **AND** command-file generation SHALL be skipped because no Grok 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 @@ -35,6 +35,7 @@ export const AI_TOOLS: AIToolOption[] = [
{ name: 'Factory Droid', value: 'factory', available: true, successLabel: 'Factory Droid', skillsDir: '.factory' },
{ name: 'Gemini CLI', value: 'gemini', available: true, successLabel: 'Gemini CLI', skillsDir: '.gemini' },
{ name: 'GitHub Copilot', value: 'github-copilot', available: true, successLabel: 'GitHub Copilot', skillsDir: '.github', detectionPaths: ['.github/copilot-instructions.md', '.github/instructions', '.github/workflows/copilot-setup-steps.yml', '.github/prompts', '.github/agents', '.github/skills', '.github/.mcp.json'] },
{ name: 'Grok Build', value: 'grok', available: true, successLabel: 'Grok Build', skillsDir: '.grok' },
{ 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' },
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 @@ -194,6 +194,30 @@ describe('InitCommand', () => {
).toBe(true);
});

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

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

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

const commandsDir = path.join(testDir, '.grok', '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: grok') && entry.includes('(no adapter)'),
),
).toBe(true);
});

it('should create both skills and commands for Trae with adapter', async () => {
saveGlobalConfig({
configuredTools: [],
Expand Down