From 9dadfa54c2e1f5ebd4880174217836d88f2a02cb Mon Sep 17 00:00:00 2001 From: David Laurence Aviado Date: Wed, 8 Apr 2026 12:09:20 +0800 Subject: [PATCH 1/4] feat: add Kilo CLI (KiloCode) as supported platform Kilo CLI is a fork of OpenCode and uses the same MCP server format. It stores its config at .opencode/opencode.jsonc (vs OpenCode's .opencode.json at repo root), so a separate platform entry is needed. Changes: - Add 'kilocode' platform entry to PLATFORMS dict in skills.py - config_path: repo/.opencode/opencode.jsonc - detect: checks for .opencode/opencode.jsonc existence - format/object/needs_type: same as OpenCode - Add 'kilocode' to --platform choices in both install and init subcommands in cli.py - Update docs/USAGE.md platform table with Kilo CLI entry and fix OpenCode config path (.opencode/config.json -> .opencode.json) --- code_review_graph/cli.py | 4 ++-- code_review_graph/skills.py | 8 ++++++++ docs/USAGE.md | 3 ++- uv.lock | 2 +- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/code_review_graph/cli.py b/code_review_graph/cli.py index 3fb4f93..82e726e 100644 --- a/code_review_graph/cli.py +++ b/code_review_graph/cli.py @@ -188,7 +188,7 @@ def main() -> None: "--platform", choices=[ "claude", "claude-code", "cursor", "windsurf", "zed", - "continue", "opencode", "antigravity", "all", + "continue", "opencode", "kilocode", "antigravity", "all", ], default="all", help="Target platform for MCP config (default: all detected)", @@ -218,7 +218,7 @@ def main() -> None: "--platform", choices=[ "claude", "claude-code", "cursor", "windsurf", "zed", - "continue", "opencode", "antigravity", "all", + "continue", "opencode", "kilocode", "antigravity", "all", ], default="all", help="Target platform for MCP config (default: all detected)", diff --git a/code_review_graph/skills.py b/code_review_graph/skills.py index 2ecc6d3..0a2b657 100644 --- a/code_review_graph/skills.py +++ b/code_review_graph/skills.py @@ -75,6 +75,14 @@ def _zed_settings_path() -> Path: "format": "object", "needs_type": True, }, + "kilocode": { + "name": "Kilo CLI", + "config_path": lambda root: root / ".opencode" / "opencode.jsonc", + "key": "mcpServers", + "detect": lambda: (root / ".opencode" / "opencode.jsonc").exists(), + "format": "object", + "needs_type": True, + }, "antigravity": { "name": "Antigravity", "config_path": lambda root: Path.home() / ".gemini" / "antigravity" / "mcp_config.json", diff --git a/docs/USAGE.md b/docs/USAGE.md index 6b8f30f..5d87aac 100644 --- a/docs/USAGE.md +++ b/docs/USAGE.md @@ -28,7 +28,8 @@ code-review-graph install --platform claude-code | **Windsurf** | `.windsurf/mcp.json` | | **Zed** | `.zed/settings.json` | | **Continue** | `.continue/config.json` | -| **OpenCode** | `.opencode/config.json` | +| **OpenCode** | `.opencode.json` | +| **Kilo CLI** | `.opencode/opencode.jsonc` | ## Core Workflow diff --git a/uv.lock b/uv.lock index cac70c0..e100451 100644 --- a/uv.lock +++ b/uv.lock @@ -260,7 +260,7 @@ wheels = [ [[package]] name = "code-review-graph" -version = "2.0.0" +version = "2.2.1" source = { editable = "." } dependencies = [ { name = "fastmcp" }, From 65814a2b6a8f929452f21695cc220c058f4633a3 Mon Sep 17 00:00:00 2001 From: David Laurence Aviado Date: Wed, 8 Apr 2026 12:17:18 +0800 Subject: [PATCH 2/4] feat: generate .kilocode/skills/ for Kilo CLI agents Adds generate_kilo_skills() which writes 4 skill files to .kilocode/skills/: - explore-codebase.md - review-changes.md - debug-issue.md - refactor-safely.md Each skill has identical body to Claude Code versions but lives in .kilocode/skills/ so Kilo CLI agents can discover and use them. Also updated CLI to call generate_kilo_skills() during init and made the print message distinguish Claude Code vs Kilo skills. --- code_review_graph/cli.py | 5 +++- code_review_graph/skills.py | 57 +++++++++++++++++++++++++++++++++++-- 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/code_review_graph/cli.py b/code_review_graph/cli.py index 82e726e..716aad8 100644 --- a/code_review_graph/cli.py +++ b/code_review_graph/cli.py @@ -128,6 +128,7 @@ def _handle_init(args: argparse.Namespace) -> None: from .skills import ( generate_skills, + generate_kilo_skills, inject_claude_md, inject_platform_instructions, install_hooks, @@ -135,7 +136,9 @@ def _handle_init(args: argparse.Namespace) -> None: if not skip_skills: skills_dir = generate_skills(repo_root) - print(f"Generated skills in {skills_dir}") + print(f"Generated Claude Code skills in {skills_dir}") + kilo_skills_dir = generate_kilo_skills(repo_root) + print(f"Generated Kilo CLI skills in {kilo_skills_dir}") inject_claude_md(repo_root) updated = inject_platform_instructions(repo_root) if updated: diff --git a/code_review_graph/skills.py b/code_review_graph/skills.py index 0a2b657..54d9b01 100644 --- a/code_review_graph/skills.py +++ b/code_review_graph/skills.py @@ -1,7 +1,7 @@ -"""Claude Code skills and hooks auto-install. +"""Claude Code and Kilo CLI skills and hooks auto-install. -Generates Claude Code agent skill files, hooks configuration, and -CLAUDE.md integration for seamless code-review-graph usage. +Generates Claude Code and Kilo CLI agent skill files, hooks configuration, +and CLAUDE.md integration for seamless code-review-graph usage. Also supports multi-platform MCP server installation. """ @@ -339,6 +339,57 @@ def generate_skills(repo_root: Path, skills_dir: Path | None = None) -> Path: return skills_dir +# Kilo CLI skill files — same body, different filenames and directory +# Written to .kilocode/skills/ so Kilo agents can discover them +_KILO_SKILLS: dict[str, dict[str, str]] = { + f"kilo-{name}": info + for name, info in _SKILLS.items() +} + +# Kilo CLI uses flat skill filenames (no subdirectory structure) +# Map: internal key -> actual filename on disk +_KILO_SKILL_FILENAME = { + f"kilo-{name}": name for name in _SKILLS +} + + +def generate_kilo_skills(repo_root: Path, skills_dir: Path | None = None) -> Path: + """Generate Kilo CLI skill files. + + Creates `.kilocode/skills/` directory with 4 skill markdown files, + identical in content to the Claude Code skills but with Kilo-compatible + filenames (e.g. `explore-codebase.md` not `kilo-explore-codebase.md`). + + Kilo skill files use YAML frontmatter with name/description and a body. + + Args: + repo_root: Repository root directory. + skills_dir: Custom skills directory. Defaults to repo_root/.kilocode/skills. + + Returns: + Path to the skills directory. + """ + if skills_dir is None: + skills_dir = repo_root / ".kilocode" / "skills" + skills_dir.mkdir(parents=True, exist_ok=True) + + for filename, skill in _KILO_SKILLS.items(): + # Kilo uses plain filenames, not prefixed + disk_name = _KILO_SKILL_FILENAME.get(filename, filename) + path = skills_dir / disk_name + content = ( + "---\n" + f"name: {skill['name']}\n" + f"description: {skill['description']}\n" + "---\n\n" + f"{skill['body']}\n" + ) + path.write_text(content) + logger.info("Wrote Kilo skill: %s", path) + + return skills_dir + + def generate_hooks_config() -> dict[str, Any]: """Generate Claude Code hooks configuration. From 2bb2410533aaa0f1723ed45fbbbf8d626a76dfdd Mon Sep 17 00:00:00 2001 From: David Laurence Aviado Date: Wed, 8 Apr 2026 12:31:28 +0800 Subject: [PATCH 3/4] fix: use Kilo's directory-per-skill format (skill-name/SKILL.md) Kilo skills must be a directory containing SKILL.md, not flat .md files. Fixes: .kilocode/skills/explore-codebase/SKILL.md (not .md directly) --- code_review_graph/skills.py | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/code_review_graph/skills.py b/code_review_graph/skills.py index 54d9b01..22a66db 100644 --- a/code_review_graph/skills.py +++ b/code_review_graph/skills.py @@ -339,28 +339,21 @@ def generate_skills(repo_root: Path, skills_dir: Path | None = None) -> Path: return skills_dir -# Kilo CLI skill files — same body, different filenames and directory -# Written to .kilocode/skills/ so Kilo agents can discover them -_KILO_SKILLS: dict[str, dict[str, str]] = { - f"kilo-{name}": info - for name, info in _SKILLS.items() -} +# Kilo CLI skill files — same body, directory-per-skill format +# Written to .kilocode/skills//SKILL.md so Kilo agents discover them +# Slug is derived from the skill name: "Explore Codebase" → "explore-codebase" -# Kilo CLI uses flat skill filenames (no subdirectory structure) -# Map: internal key -> actual filename on disk -_KILO_SKILL_FILENAME = { - f"kilo-{name}": name for name in _SKILLS -} +_KILO_SKILL_SLUG = {name: name.lower().replace(" ", "-").removesuffix(".md") for name in _SKILLS} def generate_kilo_skills(repo_root: Path, skills_dir: Path | None = None) -> Path: """Generate Kilo CLI skill files. - Creates `.kilocode/skills/` directory with 4 skill markdown files, - identical in content to the Claude Code skills but with Kilo-compatible - filenames (e.g. `explore-codebase.md` not `kilo-explore-codebase.md`). + Creates `.kilocode/skills//SKILL.md` for each skill — Kilo's + directory-per-skill format required for its agent to discover skills. - Kilo skill files use YAML frontmatter with name/description and a body. + Kilo skill files use YAML frontmatter (name, description) and a + markdown body. Args: repo_root: Repository root directory. @@ -373,10 +366,11 @@ def generate_kilo_skills(repo_root: Path, skills_dir: Path | None = None) -> Pat skills_dir = repo_root / ".kilocode" / "skills" skills_dir.mkdir(parents=True, exist_ok=True) - for filename, skill in _KILO_SKILLS.items(): - # Kilo uses plain filenames, not prefixed - disk_name = _KILO_SKILL_FILENAME.get(filename, filename) - path = skills_dir / disk_name + for name, skill in _SKILLS.items(): + slug = _KILO_SKILL_SLUG[name] + skill_dir = skills_dir / slug + skill_dir.mkdir(parents=True, exist_ok=True) + path = skill_dir / "SKILL.md" content = ( "---\n" f"name: {skill['name']}\n" From 677e2bde82ec9d47d1558f59c4cbd20e87aff690 Mon Sep 17 00:00:00 2001 From: David Laurence Aviado Date: Wed, 8 Apr 2026 12:54:39 +0800 Subject: [PATCH 4/4] fix: detect lambda for kilocode used undefined 'root' variable --- code_review_graph/skills.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code_review_graph/skills.py b/code_review_graph/skills.py index 22a66db..a985cf6 100644 --- a/code_review_graph/skills.py +++ b/code_review_graph/skills.py @@ -79,7 +79,7 @@ def _zed_settings_path() -> Path: "name": "Kilo CLI", "config_path": lambda root: root / ".opencode" / "opencode.jsonc", "key": "mcpServers", - "detect": lambda: (root / ".opencode" / "opencode.jsonc").exists(), + "detect": lambda: (Path.cwd() / ".opencode" / "opencode.jsonc").exists(), "format": "object", "needs_type": True, },