From d579daa3ed634bcd11ab93edb9c63a2e610d8951 Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Wed, 22 Jul 2026 14:30:26 -0400 Subject: [PATCH] =?UTF-8?q?docs(#2505):=20Phase=206=20=E2=80=94=20migratio?= =?UTF-8?q?n=20guide=20+=20built-in-only=20subagent-toolkit=20enum=20(#253?= =?UTF-8?q?8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * docs(#2512): Phase 6 — migration guide + built-in-only subagent-toolkit enum * fix #2512: update CONTRACT-PIN for built-in-only subagentToolkit value * docs(changeset): backfill PR #2538 for Phase 6 (#2512) --- .changeset/2505-6-migration-docs-schema.md | 6 ++ capabilities/kimi-code/capability.json | 2 +- docs/migration/kimi-to-kimi-code.md | 66 ++++++++++++++++++++++ gsd-core/bin/lib/capability-registry.cjs | 4 +- gsd-core/bin/lib/capability-validator.cjs | 2 +- src/host-integration.cts | 2 +- tests/host-integration.test.cjs | 2 +- 7 files changed, 78 insertions(+), 6 deletions(-) create mode 100644 .changeset/2505-6-migration-docs-schema.md create mode 100644 docs/migration/kimi-to-kimi-code.md diff --git a/.changeset/2505-6-migration-docs-schema.md b/.changeset/2505-6-migration-docs-schema.md new file mode 100644 index 000000000..83132f8bc --- /dev/null +++ b/.changeset/2505-6-migration-docs-schema.md @@ -0,0 +1,6 @@ +--- +type: Added +pr: 2538 +--- + +**New `docs/migration/kimi-to-kimi-code.md` migration guide + `built-in-only` subagent-toolkit enum value** — users who installed via `--kimi` but are actually on Kimi Code (Node CLI) now have a step-by-step migration path (re-install with `--kimi-code`, remove inert YAMLs, verify skills, verify agent-skills query). The `built-in-only` enum value replaces the `undocumented` sentinel on the kimi-code descriptor's `subagentToolkit` axis, making the descriptor self-documenting: Kimi Code's three built-in subagents (coder/explore/plan) are now a first-class negotiated value rather than an escape hatch. (#2512) diff --git a/capabilities/kimi-code/capability.json b/capabilities/kimi-code/capability.json index 4e4cec7b2..f11cb887f 100644 --- a/capabilities/kimi-code/capability.json +++ b/capabilities/kimi-code/capability.json @@ -58,7 +58,7 @@ "nested": false, "maxDepth": 1, "background": true, - "subagentToolkit": "undocumented", + "subagentToolkit": "built-in-only", "backgroundDispatch": true, "builtInSubagents": [ "coder", diff --git a/docs/migration/kimi-to-kimi-code.md b/docs/migration/kimi-to-kimi-code.md new file mode 100644 index 000000000..34ac28318 --- /dev/null +++ b/docs/migration/kimi-to-kimi-code.md @@ -0,0 +1,66 @@ +# Migrating from `--kimi` to `--kimi-code` + +> **When:** you installed GSD via `--kimi --global` but you're actually running **Kimi Code** (Moonshot's Node CLI, `~/.kimi-code/config.toml`), not **Kimi CLI** (Moonshot's Python CLI, `~/.kimi/config.toml`). + +## Symptom + +Before the Phase 1 descriptor split (epic #2505), GSD conflated both products under a single `kimi` runtime. If you ran `--kimi --global` on Kimi Code: + +- `gsd-tools query agent-skills ` returned **empty** (the Python kimi-cli agent YAMLs are inert on Kimi Code). +- Every workflow that called a named GSD subagent (`gsd-planner`, `gsd-executor`, …) **failed at dispatch** (Kimi Code only recognizes `coder`, `explore`, `plan`). +- Every GSD `PreToolUse` guard (`gsd-prompt-guard`, `gsd-read-guard`, `gsd-worktree-path-guard`, `gsd-read-injection-scanner`) was **silently dormant** (#2304) — the matcher was translated but the payload check wasn't, so the guards exited 0 on every Kimi-vocabulary tool call. + +## Which product am I on? + +| Check | Kimi CLI (Python) | Kimi Code (Node) | +|---|---|---| +| Config file | `~/.kimi/config.toml` | `~/.kimi-code/config.toml` (`KIMI_CODE_HOME`) | +| Built-in subagents | Custom via YAML (`extend:`, `system_prompt_path`) | Three only: `coder`, `explore`, `plan` | +| Skills discovery | `~/.config/agents/skills` or `~/.agents/skills` | `~/.kimi-code/skills/` (auto, `merge_all_available_skills = true`) | +| Language | Python (`kimi-cli`) | Node | + +If `~/.kimi-code/config.toml` exists and `~/.kimi/config.toml` does not, you're on Kimi Code. + +## Migration steps + +### 1. Re-install with `--kimi-code` + +```bash +npx @opengsd/gsd-core --kimi-code --global +``` + +This installs the correct Agent Skills surface at `~/.kimi-code/skills/gsd-*/SKILL.md` (Phase 2) and activates the Phase 0 guard normalization (the dormant-guard fix). The Phase 5 installer will warn you if you accidentally pick the wrong variant. + +### 2. Remove inert Python-kimi-cli artifacts (if any) + +If your prior `--kimi` install wrote agent YAMLs (the `kimi-agents` artifact layout) into your config dir, they're inert on Kimi Code — Kimi Code cannot read them. Safe to remove: + +```bash +# Only if you previously installed via --kimi and are now on --kimi-code: +rm -rf ~/.config/agents/agents/gsd-*.yaml ~/.agents/agents/gsd-*.yaml 2>/dev/null || true +``` + +### 3. Verify skills are discovered + +After re-install, launch Kimi Code and confirm the GSD skills appear in the `/skill:` menu (or whatever surface Kimi Code uses for auto-discovered Agent Skills). Each `gsd-*` skill should be present at `~/.kimi-code/skills/gsd-*/SKILL.md`. + +### 4. Verify agent-skills query + +```bash +gsd-tools query agent-skills gsd-planner +``` + +Should return the planner's prompt content (non-empty) — Phase 3's fallback reads the installed agent prompt on non-Claude runtimes. + +## What about workflows that dispatch named subagents? + +Phase 4 (epic #2505) added runtime-aware dispatch. Workflows now resolve the subagent type via `gsd_run query resolve-dispatch-type --requested --raw` before dispatching. On Kimi Code, a role like `gsd-planner` resolves to the `plan` built-in; the persona rides `${AGENT_SKILLS_PLANNER}` (Phase 3's fallback) regardless of the resolved type. You do not need to edit any workflow files — the resolution is automatic. + +## What about the dormant guards? + +Phase 0 (#2304 / PR #2518) fixed all seven Kimi-surface PreToolUse/PostToolUse guards. Re-installing via `--kimi-code --global` picks up the fix automatically — the normalized guard scripts are part of the standard install. + +## Questions + +- **Can I keep both `--kimi` and `--kimi-code` installs?** Yes — they install to separate config dirs (`~/.kimi/` vs `~/.kimi-code/`). Run both if you genuinely use both products. +- **Do I need to uninstall the old `--kimi` install first?** No — `--kimi-code --global` writes to `~/.kimi-code/`, which is separate. But if you no longer use Python kimi-cli, uninstalling the old install keeps things clean: `npx @opengsd/gsd-core --kimi --global --uninstall`. diff --git a/gsd-core/bin/lib/capability-registry.cjs b/gsd-core/bin/lib/capability-registry.cjs index 8ddafbd6d..6faac5bb5 100644 --- a/gsd-core/bin/lib/capability-registry.cjs +++ b/gsd-core/bin/lib/capability-registry.cjs @@ -1812,7 +1812,7 @@ const capabilities = { "nested": false, "maxDepth": 1, "background": true, - "subagentToolkit": "undocumented", + "subagentToolkit": "built-in-only", "backgroundDispatch": true, "builtInSubagents": [ "coder", @@ -5222,7 +5222,7 @@ const runtimes = { "nested": false, "maxDepth": 1, "background": true, - "subagentToolkit": "undocumented", + "subagentToolkit": "built-in-only", "backgroundDispatch": true, "builtInSubagents": [ "coder", diff --git a/gsd-core/bin/lib/capability-validator.cjs b/gsd-core/bin/lib/capability-validator.cjs index aaf6ffa56..53fd32ec9 100644 --- a/gsd-core/bin/lib/capability-validator.cjs +++ b/gsd-core/bin/lib/capability-validator.cjs @@ -736,7 +736,7 @@ const VALID_HOOK_BUSES = new Set(['host', 'engine', 'none']); const VALID_STATE_IO = new Set(['filesystem', 'sandboxed-storage', 'session-log-append']); const VALID_TRANSPORTS = new Set(['mcp', 'native-extension']); const VALID_HOST_RUNTIMES = new Set(['node', 'bun', 'sandboxed-web', 'python', 'go', 'rust', 'electron', 'other']); -const VALID_SUBAGENT_TOOLKITS = new Set(['full', 'read-only']); +const VALID_SUBAGENT_TOOLKITS = new Set(['full', 'read-only', 'built-in-only']); // ADR-1239 amendment (#2481): how reasoning effort reaches the host. const VALID_EFFORT_SURFACES = new Set(['argv', 'none']); diff --git a/src/host-integration.cts b/src/host-integration.cts index 2e01180ad..a6feddf3c 100644 --- a/src/host-integration.cts +++ b/src/host-integration.cts @@ -44,7 +44,7 @@ const HOST_INTEGRATION_AXES = Object.freeze({ stateIO: Object.freeze(['filesystem', 'sandboxed-storage', 'session-log-append'] as const), transport: Object.freeze(['mcp', 'native-extension'] as const), runtime: Object.freeze(['node', 'bun', 'sandboxed-web', 'python', 'go', 'rust', 'electron', 'other'] as const), - subagentToolkit: Object.freeze(['full', 'read-only'] as const), + subagentToolkit: Object.freeze(['full', 'read-only', 'built-in-only'] as const), // ADR-1239 amendment (#2481): how reasoning effort reaches this host. // `argv` — deliverable as an argument on the host's own invocation. // `none` — the host exposes no reasoning-effort mechanism. diff --git a/tests/host-integration.test.cjs b/tests/host-integration.test.cjs index 93e0c2a3d..7d9cfce77 100644 --- a/tests/host-integration.test.cjs +++ b/tests/host-integration.test.cjs @@ -161,7 +161,7 @@ describe('CONTRACT-PIN', () => { test('subagentToolkit values (sorted)', () => { assert.deepStrictEqual( [...HOST_INTEGRATION_AXES.subagentToolkit].sort(), - ['full', 'read-only'], + ['built-in-only', 'full', 'read-only'], ); });