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**: Alquimia AI, Amp, Antigravity, Auggie CLI, Claude Code, Cline, CodeBuddy, Codex CLI, Command Code, Cursor, Devin for Terminal, Docker Agent, Factory Droid, DeepSeek Harness, Firebender, Forge, Gemini CLI, GitHub Copilot, Goose, Grok Build, Hermes Agent, IBM Bob, Junie, Kilo Code, Kimi Code, Kiro CLI, Lingma, Mistral Vibe, Muse Code, Oh My Pi, opencode, Pi Coding Agent, Qoder CLI, Qwen Code, RovoDev ACLI, SHAI, Tabnine CLI, Trae, ZCode, Zed
**Currently supported agents**: Alquimia AI, Amp, Antigravity, Auggie CLI, Claude Code, Cline, CodeBuddy, Codex CLI, Command Code, Cursor, Devin for Terminal, Docker Agent, Factory Droid, DeepSeek Harness, Firebender, Forge, Gemini CLI, GitHub Copilot, Goose, Grok Build, Hermes Agent, IBM Bob, Junie, Kilo Code, Kimi Code, Kiro CLI, Lingma, MiniMax Code, Mistral Vibe, Muse Code, Oh My Pi, opencode, Pi Coding Agent, Qoder CLI, Qwen Code, RovoDev ACLI, SHAI, Tabnine CLI, Trae, ZCode, Zed

- type: input
id: agent-name
Expand Down
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ body:
- Kimi Code
- Kiro CLI
- Lingma
- MiniMax Code
- Mistral Vibe
- Muse Code
- Oh My Pi
Expand Down
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/feature_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ body:
- Kimi Code
- Kiro CLI
- Lingma
- MiniMax Code
- Mistral Vibe
- Muse Code
- Oh My Pi
Expand Down
1 change: 1 addition & 0 deletions docs/reference/integrations.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ The Specify CLI supports a wide range of AI coding agents. When you run `specify
| [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 |
| [MiniMax Code](https://github.com/MiniMax-AI/minimax-code) | `mcode` | Skills-based integration; installs skills into `.minimax/skills` and invokes them as `/speckit-<command>` |
| [Mistral Vibe](https://github.com/mistralai/mistral-vibe) | `vibe` | |
| [Muse Code](https://dev.meta.ai/docs/muse-code) | `muse` | Skills-based integration; installs skills into `.agents/skills` and invokes them as `/speckit-<command>` |
| [Oh My Pi](https://www.npmjs.com/package/@oh-my-pi/pi-coding-agent) | `omp` | Installs slash commands into `.omp/commands` |
Expand Down
1 change: 1 addition & 0 deletions extensions/agent-context/agent-context-defaults.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"kimi": "AGENTS.md",
"kiro-cli": "AGENTS.md",
"lingma": ".lingma/rules/specify-rules.md",
"mcode": "AGENTS.md",
"muse": "AGENTS.md",
"omp": "AGENTS.md",
"opencode": "AGENTS.md",
Expand Down
9 changes: 9 additions & 0 deletions integrations/catalog.json
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,15 @@
"author": "spec-kit-core",
"repository": "https://github.com/github/spec-kit",
"tags": ["cli", "skills"]
},
"mcode": {
"id": "mcode",
"name": "MiniMax Code",
"version": "1.0.0",
"description": "MiniMax Code CLI skills-based integration",
"author": "spec-kit-core",
"repository": "https://github.com/github/spec-kit",
"tags": ["cli", "skills"]
}
}
}
2 changes: 1 addition & 1 deletion src/specify_cli/_invocation_style.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

# Agents that always render /speckit-<name>, regardless of ai_skills.
ALWAYS_SLASH_AGENTS: frozenset[str] = frozenset(
{"devin", "droid", "dsh", "grok", "muse", "qodercli", "trae", "zed"}
{"devin", "droid", "dsh", "grok", "mcode", "muse", "qodercli", "trae", "zed"}
)

# Agents that render /speckit-<name> only when ai_skills is enabled.
Expand Down
7 changes: 7 additions & 0 deletions src/specify_cli/commands/init.py
Original file line number Diff line number Diff line change
Expand Up @@ -1010,6 +1010,7 @@ def init(
zcode_skill_mode = selected_ai == "zcode" and _is_skills_integration
claude_skill_mode = selected_ai == "claude" and _is_skills_integration
kimi_skill_mode = selected_ai == "kimi"
mcode_skill_mode = selected_ai == "mcode" and _is_skills_integration
agy_skill_mode = selected_ai == "agy" and _is_skills_integration
trae_skill_mode = selected_ai == "trae"
cursor_agent_skill_mode = (
Expand All @@ -1029,6 +1030,7 @@ def init(
or zcode_skill_mode
or claude_skill_mode
or kimi_skill_mode
or mcode_skill_mode
or agy_skill_mode
or trae_skill_mode
or cursor_agent_skill_mode
Expand Down Expand Up @@ -1091,6 +1093,11 @@ def init(
f"{step_num}. Start Bob in this project directory; spec-kit skills were installed to [cyan].bob/skills[/cyan]"
)
step_num += 1
if mcode_skill_mode:
steps_lines.append(
f"{step_num}. Start MiniMax Code in this project directory; spec-kit skills were installed to [cyan].minimax/skills[/cyan]"
)
step_num += 1
usage_label = "skills" if native_skill_mode else "slash commands"

from .._invocation_style import (
Expand Down
2 changes: 2 additions & 0 deletions src/specify_cli/integrations/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ def _register_builtins() -> None:
from .kimi import KimiIntegration
from .kiro_cli import KiroCliIntegration
from .lingma import LingmaIntegration
from .mcode import McodeIntegration
from .muse import MuseIntegration
from .omp import OmpIntegration
from .opencode import OpencodeIntegration
Expand Down Expand Up @@ -118,6 +119,7 @@ def _register_builtins() -> None:
_register(KimiIntegration())
_register(KiroCliIntegration())
_register(LingmaIntegration())
_register(McodeIntegration())
_register(MuseIntegration())
_register(OmpIntegration())
_register(OpencodeIntegration())
Expand Down
71 changes: 71 additions & 0 deletions src/specify_cli/integrations/mcode/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
"""MiniMax Code integration — skills-based agent.

MiniMax Code discovers project skills from
``.minimax/skills/speckit-<name>/SKILL.md`` and invokes them via their
slash shortcut (``/speckit-<command>``).

See: https://github.com/MiniMax-AI/minimax-code
"""

from __future__ import annotations

from collections.abc import Mapping, Sequence
from pathlib import Path
from typing import Any

from ..base import IntegrationOption, SkillsIntegration


class McodeIntegration(SkillsIntegration):
"""Integration for MiniMax Code CLI."""

key = "mcode"
config = {
"name": "MiniMax Code",
"folder": ".minimax/",
"commands_subdir": "skills",
"install_url": "https://github.com/MiniMax-AI/minimax-code",
"requires_cli": True,
}
registrar_config = {
"dir": ".minimax/skills",
"format": "markdown",
"args": "$ARGUMENTS",
"extension": "/SKILL.md",
}
multi_install_safe = True

@classmethod
def options(cls) -> list[IntegrationOption]:
opts = super().options()
opts.append(
IntegrationOption(
"--skills",
is_flag=True,
default=True,
help="Install as agent skills (default for MiniMax Code)",
)
)
return opts

def build_exec_args(
self,
prompt: str,
*,
model: str | None = None,
output_json: bool = True,
integration_args: Sequence[str] | None = None,
integration_options: Mapping[str, Any] | None = None,
project_root: Path | None = None,
) -> list[str] | None:
self.validate_runtime_config(
integration_args,
integration_options,
)
args = [self._resolve_executable(), "exec", prompt]
self._apply_extra_args_env_var(args)
if model:
args.extend(["--model", model])
if output_json:
args.extend(["--output-format", "json"])
return args
109 changes: 109 additions & 0 deletions tests/integrations/test_integration_mcode.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
"""Tests for McodeIntegration — skills-based integration (MiniMax Code)."""

from .test_integration_base_skills import SkillsIntegrationTests


class TestMcodeIntegration(SkillsIntegrationTests):
KEY = "mcode"
FOLDER = ".minimax/"
COMMANDS_SUBDIR = "skills"
REGISTRAR_DIR = ".minimax/skills"


class TestMcodeMetadata:
"""MiniMax Code-specific metadata and headless dispatch."""

def test_display_name(self):
from specify_cli.integrations import get_integration

assert get_integration("mcode").config["name"] == "MiniMax Code"

def test_requires_cli(self):
from specify_cli.integrations import get_integration

assert get_integration("mcode").config["requires_cli"] is True

def test_install_url_points_to_github(self):
from specify_cli.integrations import get_integration

assert (
get_integration("mcode").config["install_url"]
== "https://github.com/MiniMax-AI/minimax-code"
)

def test_multi_install_safe(self):
from specify_cli.integrations import get_integration

assert get_integration("mcode").multi_install_safe is True

def test_build_exec_args_uses_mcode_exec(self):
from specify_cli.integrations import get_integration

args = get_integration("mcode").build_exec_args("do the thing")
assert args[:3] == ["mcode", "exec", "do the thing"]
assert "--output-format" in args
assert args[args.index("--output-format") + 1] == "json"

def test_build_exec_args_model_flag(self):
from specify_cli.integrations import get_integration

args = get_integration("mcode").build_exec_args(
"do the thing", model="MiniMax-Text-01", output_json=False
)
assert "--model" in args
assert args[args.index("--model") + 1] == "MiniMax-Text-01"
assert "--output-format" not in args

def test_build_exec_args_extra_args_env_var(self, monkeypatch):
monkeypatch.setenv(
"SPECKIT_INTEGRATION_MCODE_EXTRA_ARGS", "--verbose --timeout 60"
)
from specify_cli.integrations import get_integration

args = get_integration("mcode").build_exec_args("do the thing")
assert "--verbose" in args
assert "--timeout" in args
assert args[args.index("--timeout") + 1] == "60"

def test_options_declares_skills_flag(self):
from specify_cli.integrations import get_integration

opts = get_integration("mcode").options()
skills_opts = [o for o in opts if o.name == "--skills"]
assert len(skills_opts) == 1
assert skills_opts[0].is_flag is True
assert skills_opts[0].default is True

def test_next_steps_show_slash_skill_invocation(self, tmp_path):
"""MiniMax Code next-steps guidance should display /speckit-* usage."""
import os
from typer.testing import CliRunner
from specify_cli import app

project = tmp_path / "mcode-next-steps"
project.mkdir()
old_cwd = os.getcwd()
try:
os.chdir(project)
runner = CliRunner()
result = runner.invoke(
app,
[
"init",
"--here",
"--integration",
"mcode",
"--ignore-agent-tools",
"--script",
"sh",
],
catch_exceptions=False,
)
finally:
os.chdir(old_cwd)

assert result.exit_code == 0
assert "/speckit-constitution" in result.output
assert "/speckit.constitution" not in result.output
assert "MiniMax Code" in result.output
assert ".minimax/skills" in result.output
2 changes: 1 addition & 1 deletion tests/integrations/test_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"gemini", "tabnine",
# Stage 5 — skills, generic & option-driven integrations
"codex", "kimi", "agy", "zed", "generic",
"droid", "command-code", "dsh", "muse",
"droid", "command-code", "dsh", "muse", "mcode",
]


Expand Down
26 changes: 26 additions & 0 deletions tests/test_agent_config_consistency.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"kimi",
"kiro-cli",
"lingma",
"mcode",
"vibe",
"muse",
"omp",
Expand Down Expand Up @@ -442,3 +443,28 @@ def test_rovodev_in_extension_registrar(self):
def test_agent_config_includes_rovodev(self):
"""AGENT_CONFIG should include rovodev."""
assert "rovodev" in AGENT_CONFIG

# --- MiniMax Code consistency checks ---

def test_mcode_in_agent_config(self):
"""AGENT_CONFIG should include mcode with skills-based scaffold metadata."""
assert "mcode" in AGENT_CONFIG
assert AGENT_CONFIG["mcode"]["folder"] == ".minimax/"
assert AGENT_CONFIG["mcode"]["commands_subdir"] == "skills"
assert AGENT_CONFIG["mcode"]["requires_cli"] is True

def test_mcode_in_extension_registrar(self):
"""CommandRegistrar.AGENT_CONFIGS should include mcode skill scaffold metadata."""
cfg = CommandRegistrar.AGENT_CONFIGS

assert "mcode" in cfg
mcode_cfg = cfg["mcode"]
assert mcode_cfg["dir"] == ".minimax/skills"
assert mcode_cfg["format"] == "markdown"
assert mcode_cfg["args"] == "$ARGUMENTS"
assert mcode_cfg["extension"] == "/SKILL.md"

def test_agent_config_includes_mcode(self):
"""AGENT_CONFIG should include mcode."""
assert "mcode" in AGENT_CONFIG