From b9783534e8abbfaf0e66ee3ff41d748e10cac3c5 Mon Sep 17 00:00:00 2001 From: Vilius Kazlauskas Date: Thu, 9 Jul 2026 14:56:41 +0300 Subject: [PATCH 1/6] feat: Adding kimchi CLI option --- apps/daemon/src/app-config.ts | 1 + apps/daemon/src/memory-llm.ts | 5 ++-- apps/daemon/src/runtimes/defs/kimchi.ts | 27 ++++++++++++++++++ apps/daemon/src/runtimes/executables.ts | 1 + apps/daemon/src/runtimes/registry.ts | 2 ++ .../tests/runtimes/env-and-detection.test.ts | 1 + .../tests/runtimes/helpers/test-helpers.ts | 1 + apps/web/public/agent-icons/kimchi.png | Bin 0 -> 6785 bytes apps/web/src/App.tsx | 1 + apps/web/src/components/AgentIcon.tsx | 1 + apps/web/src/components/HandoffButton.tsx | 2 ++ apps/web/src/components/MemoryModelInline.tsx | 1 + .../contracts/src/analytics/events/mappers.ts | 2 ++ .../src/analytics/events/shared-enums.ts | 1 + .../src/analytics/events/ui-click.ts | 2 +- 15 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 apps/daemon/src/runtimes/defs/kimchi.ts create mode 100644 apps/web/public/agent-icons/kimchi.png diff --git a/apps/daemon/src/app-config.ts b/apps/daemon/src/app-config.ts index 3ab9e4faf38..210089f1c32 100644 --- a/apps/daemon/src/app-config.ts +++ b/apps/daemon/src/app-config.ts @@ -204,6 +204,7 @@ const AGENT_CLI_ENV_KEYS: ReadonlyMap> = new Map([ ['kimi', new Set(['KIMI_BIN'])], ['kiro', new Set(['KIRO_BIN'])], ['kilo', new Set(['KILO_BIN'])], + ['kimchi', new Set(['KIMCHI_BIN', 'KIMCHI_API_KEY'])], ['opencode', new Set(['OPENCODE_BIN'])], ['pi', new Set(['PI_BIN'])], ['qoder', new Set(['QODER_BIN'])], diff --git a/apps/daemon/src/memory-llm.ts b/apps/daemon/src/memory-llm.ts index 1f040f95304..d0db30f0816 100644 --- a/apps/daemon/src/memory-llm.ts +++ b/apps/daemon/src/memory-llm.ts @@ -251,8 +251,8 @@ function chatProtocolFromAgentId(agentId) { if (id === 'claude') return 'anthropic'; if (id === 'gemini') return 'google'; // Codex, OpenCode, Qwen, DeepSeek, Kimi, Copilot, Pi, Kiro, Kilo, - // Vibe, Devin, Hermes, Cursor-Agent, Qoder all use the OpenAI chat- - // completions wire format. + // Vibe, Devin, Hermes, Cursor-Agent, Qoder, Kimchi all use the + // OpenAI chat-completions wire format. if ( id === 'codex' || id === 'opencode' @@ -268,6 +268,7 @@ function chatProtocolFromAgentId(agentId) { || id === 'hermes' || id === 'cursor-agent' || id === 'qoder' + || id === 'kimchi' ) { return 'openai'; } diff --git a/apps/daemon/src/runtimes/defs/kimchi.ts b/apps/daemon/src/runtimes/defs/kimchi.ts new file mode 100644 index 00000000000..9fdf65fa554 --- /dev/null +++ b/apps/daemon/src/runtimes/defs/kimchi.ts @@ -0,0 +1,27 @@ +import { detectAcpModels, DEFAULT_MODEL_OPTION } from "./shared.js"; +import type { RuntimeAgentDef } from "../types.js"; + +export const kimchiAgentDef = { + id: "kimchi", + name: "Kimchi", + bin: "kimchi", + versionArgs: ["--version"], + fallbackModels: [ + DEFAULT_MODEL_OPTION, + { id: "kimi-k2.6", label: "kimi-k2.6" }, + { id: "minimax-m3", label: "minimax-m3" }, + { id: "deepseek-v4-flash", label: "deepseek-v4-flash" }, + ], + fetchModels: async (resolvedBin, env) => + detectAcpModels({ + bin: resolvedBin, + args: ["--mode", "acp"], + env, + timeoutMs: 15_000, + defaultModelOption: DEFAULT_MODEL_OPTION, + }), + buildArgs: () => ["--mode", "acp"], + streamFormat: "acp-json-rpc", + installUrl: "https://kimchi.dev", + docsUrl: "https://docs.kimchi.dev", +} satisfies RuntimeAgentDef; diff --git a/apps/daemon/src/runtimes/executables.ts b/apps/daemon/src/runtimes/executables.ts index a9b3c46adff..13014dc66f4 100644 --- a/apps/daemon/src/runtimes/executables.ts +++ b/apps/daemon/src/runtimes/executables.ts @@ -27,6 +27,7 @@ const AGENT_BIN_ENV_KEYS = new Map([ ['kimi', 'KIMI_BIN'], ['kiro', 'KIRO_BIN'], ['kilo', 'KILO_BIN'], + ['kimchi', 'KIMCHI_BIN'], ['mimo', 'MIMO_BIN'], ['opencode', 'OPENCODE_BIN'], ['byok-opencode', 'OPENCODE_BIN'], diff --git a/apps/daemon/src/runtimes/registry.ts b/apps/daemon/src/runtimes/registry.ts index 8469e6246d7..64248ff0e31 100644 --- a/apps/daemon/src/runtimes/registry.ts +++ b/apps/daemon/src/runtimes/registry.ts @@ -23,6 +23,7 @@ import { antigravityAgentDef } from './defs/antigravity.js'; import { codebuddyAgentDef } from './defs/codebuddy.js'; import { reasonixAgentDef } from './defs/reasonix.js'; import { mimoAgentDef } from './defs/mimo.js'; +import { kimchiAgentDef } from './defs/kimchi.js'; import { readLocalAgentProfileDefs as readLocalAgentProfileDefsFromFile } from './local-profiles.js'; import type { RuntimeAgentDef } from './types.js'; @@ -52,6 +53,7 @@ const BASE_AGENT_DEFS: RuntimeAgentDef[] = [ reasonixAgentDef, codebuddyAgentDef, mimoAgentDef, + kimchiAgentDef, ]; export function readLocalAgentProfileDefs( diff --git a/apps/daemon/tests/runtimes/env-and-detection.test.ts b/apps/daemon/tests/runtimes/env-and-detection.test.ts index 1936995f5b7..35caee3553f 100644 --- a/apps/daemon/tests/runtimes/env-and-detection.test.ts +++ b/apps/daemon/tests/runtimes/env-and-detection.test.ts @@ -420,6 +420,7 @@ test('resolveAgentExecutable supports configured binary overrides for non-Codex ['deepseek', 'deepseek', 'DEEPSEEK_BIN'], ['trae-cli', 'traecli', 'TRAE_CLI_BIN'], ['aider', 'aider', 'AIDER_BIN'], + ['kimchi', 'kimchi', 'KIMCHI_BIN'], ]; const dir = mkdtempSync(join(tmpdir(), 'od-agent-bin-overrides-')); try { diff --git a/apps/daemon/tests/runtimes/helpers/test-helpers.ts b/apps/daemon/tests/runtimes/helpers/test-helpers.ts index bcd2a3c80ce..01fd1a6b081 100644 --- a/apps/daemon/tests/runtimes/helpers/test-helpers.ts +++ b/apps/daemon/tests/runtimes/helpers/test-helpers.ts @@ -89,6 +89,7 @@ export const qoder = requireAgent('qoder'); export const qwen = requireAgent('qwen'); export const opencode = requireAgent('opencode'); export const mimo = requireAgent('mimo'); +export const kimchi = requireAgent('kimchi'); export const grokBuild = requireAgent('grok-build'); export const aider = requireAgent('aider'); export const antigravity = requireAgent('antigravity'); diff --git a/apps/web/public/agent-icons/kimchi.png b/apps/web/public/agent-icons/kimchi.png new file mode 100644 index 0000000000000000000000000000000000000000..d774d724207ca04568b2f99f34a5921c6a4f6126 GIT binary patch literal 6785 zcmV-{8h+)8P)t0?2ks(uLtsaCA+>Hk~pPUWQOw2#+qbbOv^ylWw8- zx&z&|8>ZP^O4-785}*|F0P_C_Nd7#0WdjX?&;)GD36$7z5)w&HEcp>hwsrm^*$R$h z#d=)nT-|#UVzU@jGU4azewrl9C#$xdy;I0F{!%QYqOjc2HUYpnUu> zYy2xFd`%DK?*cK%wKZTg;LuI03py za#)0{Z`_a1=liZ8O$?GKHxR#hl)gQP%Xwaq0vtt&vN1P~`{J=qa& zvc0$Az|f{Y?HkyU+8r&e`jO7x=Kagw6SAf!GQzXqsV3*Px-l+J(f8%Bu!>|UaDJwG7TFqB9 zRF>8?%$<1^2rdIq%37C(*xMc)ZryP3_`4nb!*6XkFyvz`hy{i-NTbtMB{_t;%Z1|R>)j0gzckUhc2nmPhIS&PXB zx;IG77;?4se#tI8z$1pLyeE4CtD8K*&8&sw65SfaWf$ynwe?|1wA?*DV$I17yJSy5 z)~iu;XAmASn6XRt1b^A&32b96L``&K5SQIzmaDDzNTTo(2avBo?m$uzR7ho%iuQ&wbZsGNDd?6f@$g2k-$a8xDI-aq_IQ%CT(8x9U>cDb--4dSv3XDW4$ z7eKI-wH8iJ2`Rndd+Xiab*zO5MyKu4wHMERn@0^pV6G}LUn|)KdsishthL-k za}lI@iQ{(3EIsM&2{3#wbr5sSnJ?u4N|Ktas0z&7tUd+f~i58>%>M$v^>UA14q*= zP?k6pmL_4=i`87`_+OGJJjCk$oPwfDYVj^}`@?(kePbpDX|5ChD2W!{tm34@VX4I{ z<=Z5AZ(=pqiT{(EgOdRjut$)a7HuJ?8_3HDyIb%}X4AxMa5QNUrb2F%0D^&ndkT1TAh~_^VvrD5nv`Ww)4> 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 = { hermes: 'svg', 'grok-build': 'svg', kimi: 'svg', + kimchi: 'png', pi: 'svg', kiro: 'svg', kilo: 'svg', diff --git a/apps/web/src/components/HandoffButton.tsx b/apps/web/src/components/HandoffButton.tsx index f853f42334f..9838399cad7 100644 --- a/apps/web/src/components/HandoffButton.tsx +++ b/apps/web/src/components/HandoffButton.tsx @@ -74,6 +74,7 @@ const CLI_ORDER = [ 'devin', 'kiro', 'kilo', + 'kimchi', 'vibe', 'antigravity', 'aider', @@ -95,6 +96,7 @@ const FALLBACK_CLI_TARGETS: CliTarget[] = [ { id: 'deepseek', name: 'DeepSeek TUI', bin: 'deepseek', available: false }, { id: 'kimi', name: 'Kimi CLI', bin: 'kimi', available: false }, { id: 'hermes', name: 'Hermes', bin: 'hermes', available: false }, + { id: 'kimchi', name: 'Kimchi', bin: 'kimchi', available: false }, { id: 'devin', name: 'Devin for Terminal', bin: 'devin', available: false }, { id: 'kiro', name: 'Kiro CLI', bin: 'kiro-cli', available: false }, { id: 'kilo', name: 'Kilo', bin: 'kilo', available: false }, diff --git a/apps/web/src/components/MemoryModelInline.tsx b/apps/web/src/components/MemoryModelInline.tsx index 64f316cfb67..e6e0b2c5b0d 100644 --- a/apps/web/src/components/MemoryModelInline.tsx +++ b/apps/web/src/components/MemoryModelInline.tsx @@ -123,6 +123,7 @@ function chatProtocolFromAgent( || id === 'hermes' || id === 'cursor-agent' || id === 'qoder' + || id === 'kimchi' ) { return 'openai'; } diff --git a/packages/contracts/src/analytics/events/mappers.ts b/packages/contracts/src/analytics/events/mappers.ts index 16f1f70460d..84ded501932 100644 --- a/packages/contracts/src/analytics/events/mappers.ts +++ b/packages/contracts/src/analytics/events/mappers.ts @@ -190,6 +190,8 @@ export function agentIdToTracking(agentId: string | null | undefined): TrackingC return 'pi'; case 'kilo': return 'kilo'; + case 'kimchi': + return 'kimchi'; case 'amr': return 'amr'; default: diff --git a/packages/contracts/src/analytics/events/shared-enums.ts b/packages/contracts/src/analytics/events/shared-enums.ts index 09ee3afc152..d1fc36784be 100644 --- a/packages/contracts/src/analytics/events/shared-enums.ts +++ b/packages/contracts/src/analytics/events/shared-enums.ts @@ -143,6 +143,7 @@ export type TrackingCliProviderId = | 'github_copilot_cli' | 'pi' | 'kilo' + | 'kimchi' | 'amr' | 'other'; diff --git a/packages/contracts/src/analytics/events/ui-click.ts b/packages/contracts/src/analytics/events/ui-click.ts index 0f4bc658292..a544cc513ba 100644 --- a/packages/contracts/src/analytics/events/ui-click.ts +++ b/packages/contracts/src/analytics/events/ui-click.ts @@ -1144,7 +1144,7 @@ export const TRACKING_HANDOFF_TARGET_IDS = [ // code-agent CLIs (HandoffButton CLI_ORDER; qoder / antigravity already above) 'amr', 'claude', 'codex', 'opencode', 'cursor-agent', 'gemini', 'qwen', 'copilot', 'grok-build', 'deepseek', 'kimi', 'hermes', 'devin', 'kiro', - 'kilo', 'vibe', 'aider', 'trae-cli', 'pi', 'reasonix', + 'kilo', 'kimchi', 'vibe', 'aider', 'trae-cli', 'pi', 'reasonix', ] as const; export type TrackingHandoffTargetId = From f92cca6014e94cdfce0d535bb1420a3950d10cc8 Mon Sep 17 00:00:00 2001 From: Vilius Kazlauskas Date: Thu, 9 Jul 2026 16:16:55 +0300 Subject: [PATCH 2/6] docs and rpc changed --- README.md | 8 ++- apps/daemon/src/mcp-agent-install.ts | 10 ++++ apps/daemon/src/runtimes/defs/kimchi.ts | 66 +++++++++++++++++---- apps/daemon/tests/mcp-agent-install.test.ts | 2 +- docs/agent-adapters.md | 14 ++++- 5 files changed, 84 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index d6f380783a6..19bb3c25a68 100644 --- a/README.md +++ b/README.md @@ -129,11 +129,12 @@ Inside a project's Studio, the same design system streams out multiple artifact | [Pi Agent](https://github.com/badlogic/pi-mono) | ✅ Supported | `od mcp install pi` | | [Mistral Vibe CLI](https://github.com/mistralai/mistral-vibe) | ✅ Supported | `od mcp install vibe` | | [Hermes Agent](https://github.com/nousresearch/hermes-agent) | ✅ Supported | `od mcp install hermes` | +| [Kimchi](https://github.com/getkimchi/kimchi) | ✅ Supported | `od mcp install kimchi` | `od mcp install --print` for a dry-run preview · `--uninstall` to remove · full list with `od mcp install --help`.

- The 21 coding-agent CLIs Open Design supports — Claude Code · Codex · OpenCode · Hermes · Antigravity · Gemini · Grok Build · Kimi · Cursor Agent · Qwen · Qoder · GitHub Copilot · Pi · Kiro · Kilo · Mistral Vibe · DeepSeek · Reasonix · Aider · Devin · Trae + The 22 coding-agent CLIs Open Design supports — Claude Code · Codex · OpenCode · Hermes · Antigravity · Gemini · Grok Build · Kimi · Cursor Agent · Qwen · Qoder · GitHub Copilot · Pi · Kiro · Kilo · Mistral Vibe · DeepSeek · Reasonix · Aider · Devin · Trae · Kimchi

**No CLI installed?** The BYOK proxy at `POST /api/proxy/{anthropic,openai,azure,google,ollama,senseaudio}/stream` gives you the same loop (no process spawn) — paste `baseUrl` + `apiKey` + `model`, with support for OpenAI, Anthropic, Azure OpenAI, Google Gemini, Ollama, LM Studio, vLLM, or any OpenAI-compatible endpoint. Per-target SSRF protection blocks internal IPs / link-local / CGNAT at the daemon edge. @@ -262,7 +263,7 @@ Every deck exports to **HTML** (single file, inlined assets), **PDF** (browser p Open Design (OD) is the open-source alternative. Same loop, same artifact-first mental model, none of the lock-in: -- 🤖 **Agent-native, model-agnostic.** We don't ship an agent. The `claude` / `codex` / `cursor-agent` / `copilot` / `hermes` / `kimi` already on your `PATH` are the design engine. Swap with one click. +- 🤖 **Agent-native, model-agnostic.** We don't ship an agent. The `claude` / `codex` / `cursor-agent` / `copilot` / `hermes` / `kimi` / `kimchi` already on your `PATH` are the design engine. Swap with one click. - 🧠 **Brand-grade by default.** Every render reads the active `DESIGN.md` — a 9-section schema covering palette, type, spacing, motion, voice, anti-patterns. 150 systems ship with the repo (Linear, Stripe, Vercel, Airbnb, Apple, Tesla, Notion, Anthropic, Cursor, Supabase, Figma…). Drop a folder in, the picker finds it. - 🖥️ **Local-first, BYOK at every layer.** Native desktop apps for macOS (Apple Silicon + Intel) and Windows (x64). Linux AppImage on the optional release lane. No telemetry, no cloud round-trip. Before describing daemon data paths, contributors and operators MUST read `AGENTS.md` → **Daemon data directory contract**. This README MUST NOT restate it. - 🌍 **Composable on three planes.** **Plugins** carry runnable workflows · **skills** carry the agent's design taste · **design systems** carry the brand. All three are plain files anyone can author, version, and publish. @@ -562,7 +563,8 @@ Plugin registry endpoint: `GET /api/plugins`. Directory overview → [`plugins/R ┌──────────────────────────────────────────────────────────────────┐ │ claude · codex · cursor-agent · copilot · openclaw · antigravity ·│ │ gemini · opencode · qwen · qoder · hermes (ACP) · kimi (ACP) · │ - │ pi (RPC) · kiro · kilo · vibe (ACP) · cline · trae · deepseek │ + │ pi (RPC) · kiro · kilo · vibe (ACP) · cline · trae · deepseek · │ + │ kimchi (RPC) │ │ reads SKILL.md + DESIGN.md, writes artifacts to disk │ └──────────────────────────────────────────────────────────────────┘ ``` diff --git a/apps/daemon/src/mcp-agent-install.ts b/apps/daemon/src/mcp-agent-install.ts index 96b054b29f7..9e301cc4000 100644 --- a/apps/daemon/src/mcp-agent-install.ts +++ b/apps/daemon/src/mcp-agent-install.ts @@ -44,6 +44,7 @@ export const AGENT_SLUGS = [ 'kiro', 'trae', 'opencode', + 'kimchi', ] as const; export type AgentSlug = (typeof AGENT_SLUGS)[number]; @@ -274,6 +275,15 @@ export function planAgentInstall( serverKey: serverName, entry: jsonEntry(spec), }; + case 'kimchi': + return { + kind: 'json', + slug, + configPath: path.join(home, '.config', 'kimchi', 'harness', 'mcp.json'), + keyPath: ['mcpServers'], + serverKey: serverName, + entry: jsonEntry(spec), + }; // ----- Unverified formats: print-only, never write ----- case 'vibe': diff --git a/apps/daemon/src/runtimes/defs/kimchi.ts b/apps/daemon/src/runtimes/defs/kimchi.ts index 9fdf65fa554..4ba69ef4f29 100644 --- a/apps/daemon/src/runtimes/defs/kimchi.ts +++ b/apps/daemon/src/runtimes/defs/kimchi.ts @@ -1,4 +1,9 @@ -import { detectAcpModels, DEFAULT_MODEL_OPTION } from "./shared.js"; +import path from "node:path"; +import { + DEFAULT_MODEL_OPTION, + execAgentFile, + parsePiModels, +} from "./shared.js"; import type { RuntimeAgentDef } from "../types.js"; export const kimchiAgentDef = { @@ -6,22 +11,61 @@ export const kimchiAgentDef = { name: "Kimchi", bin: "kimchi", versionArgs: ["--version"], + // Kimchi is built on the pi-mono SDK (same engine as pi), so it inherits + // pi's `--mode rpc` JSON-RPC-over-stdio transport, `--list-models` TSV + // output, `--thinking` levels, and `--append-system-prompt` for extra + // directories. Using pi-rpc instead of ACP gives us multimodal image + // support, reasoning levels, richer event stream, and avoids the ACP + // `mcpServers` rejection issue. + versionProbeTimeoutMs: 15_000, + fetchModels: async (resolvedBin, env) => { + try { + const { stderr } = await execAgentFile(resolvedBin, ["--list-models"], { + env, + timeout: 60_000, + maxBuffer: 8 * 1024 * 1024, + }); + const parsed = parsePiModels(stderr); + if (!parsed || parsed.length === 0) return null; + return parsed; + } catch { + return null; + } + }, fallbackModels: [ DEFAULT_MODEL_OPTION, { id: "kimi-k2.6", label: "kimi-k2.6" }, { id: "minimax-m3", label: "minimax-m3" }, { id: "deepseek-v4-flash", label: "deepseek-v4-flash" }, ], - fetchModels: async (resolvedBin, env) => - detectAcpModels({ - bin: resolvedBin, - args: ["--mode", "acp"], - env, - timeoutMs: 15_000, - defaultModelOption: DEFAULT_MODEL_OPTION, - }), - buildArgs: () => ["--mode", "acp"], - streamFormat: "acp-json-rpc", + reasoningOptions: [ + { id: "default", label: "Default" }, + { id: "off", label: "Off" }, + { id: "minimal", label: "Minimal" }, + { id: "low", label: "Low" }, + { id: "medium", label: "Medium" }, + { id: "high", label: "High" }, + { id: "xhigh", label: "XHigh" }, + ], + buildArgs: (_prompt, _imagePaths, extraAllowedDirs = [], options = {}) => { + const args = ["--mode", "rpc"]; + if (options.model && options.model !== "default") { + args.push("--model", options.model); + } + if (options.reasoning && options.reasoning !== "default") { + args.push("--thinking", options.reasoning); + } + const dirs = (extraAllowedDirs || []).filter( + (d) => typeof d === "string" && path.isAbsolute(d), + ); + for (const d of dirs) { + args.push("--append-system-prompt", d); + } + return args; + }, + promptViaStdin: true, + streamFormat: "pi-rpc", + supportsImagePaths: true, installUrl: "https://kimchi.dev", docsUrl: "https://docs.kimchi.dev", } satisfies RuntimeAgentDef; diff --git a/apps/daemon/tests/mcp-agent-install.test.ts b/apps/daemon/tests/mcp-agent-install.test.ts index a748dc8bd1d..c5ba7cd2da7 100644 --- a/apps/daemon/tests/mcp-agent-install.test.ts +++ b/apps/daemon/tests/mcp-agent-install.test.ts @@ -28,7 +28,7 @@ describe('agent slug guard', () => { it('accepts every documented slug and rejects others', () => { for (const s of AGENT_SLUGS) expect(isAgentSlug(s)).toBe(true); expect(isAgentSlug('not-an-agent')).toBe(false); - expect(AGENT_SLUGS).toHaveLength(14); + expect(AGENT_SLUGS).toHaveLength(15); expect(isAgentSlug('kiro')).toBe(true); }); }); diff --git a/docs/agent-adapters.md b/docs/agent-adapters.md index 9b559d2463c..4f9e02de54e 100644 --- a/docs/agent-adapters.md +++ b/docs/agent-adapters.md @@ -102,6 +102,7 @@ If both signals agree, detection is confident. If only one signal fires, we mark | **deepseek** | `deepseek` | `~/.deepseek/` | `~/.deepseek/skills/` | ❌ (prompt-injected) | ✅ | ✅ (plain text) | P2 | | **qoder** | `qodercli` | Qoder CLI config | Qoder CLI managed | ❌ (prompt-injected) | ✅ | ✅ (`stream-json`) | P2 | | **pi** | `pi` | `~/.pi/agent/` | `~/.pi/agent/skills/` | ❌ (prompt-injected) | ✅ | ✅ (`pi-rpc` JSON-RPC) | P2 | +| **kimchi** | `kimchi` | `~/.config/kimchi/harness/` | ❌ | ✅ | ✅ (`pi-rpc` JSON-RPC) | P2 | "P0/P1/P2" correspond to the roadmap phases in [`roadmap.md`](roadmap.md). @@ -244,7 +245,18 @@ The adapter declares which strategy to use via `capabilities().nativeSkillLoadin - Models: ships `deepseek-v4-pro` and `deepseek-v4-flash` as fallback hints (1M-token context windows, native thinking-mode streaming). Users can paste any other id (e.g. `nvidia-nim/deepseek-v4-pro`, `fireworks/deepseek-v4-flash`) via the Settings dialog's custom-model input. - **Gotcha — auth state is not auto-detected.** DeepSeek TUI reads its API key from `~/.deepseek/config.toml` or `DEEPSEEK_API_KEY`. If the user hasn't run `deepseek auth set --provider deepseek` (or set the env var), the first run errors out with a non-actionable message. Detection currently only reports `available: true` based on the binary being on PATH; surface auth state via `deepseek doctor --json` in a follow-up. -### 5.13 Plain stream artifact handoff +### 5.13 Kimchi + +- Invocation: `kimchi --mode rpc [--model ] [--thinking ] [--append-system-prompt …]`, with the composed prompt delivered over stdin via JSON-RPC. Kimchi is built on the [pi-mono](https://github.com/badlogic/pi-mono) coding agent SDK and inherits pi's RPC transport. Using `--mode rpc` (instead of `--mode acp`) gives us multimodal image support, reasoning levels, richer event stream, and avoids the ACP `mcpServers` rejection issue. +- Streaming: `pi-rpc` JSON-RPC over stdio. Events include `agent_start`, `turn_start/end`, `message_update` (text deltas, thinking deltas, tool calls), `tool_execution_start/end`, `compaction_start`, `auto_retry_start/end`, `extension_error`. `apps/daemon/src/pi-rpc.ts` maps these onto the same UI event set as the other stream parsers. +- Models: dynamic — `kimchi --list-models` prints a TSV table to stderr that the daemon parses into provider/model picker entries. Fallback hints for the default orchestrator/builder/explorer models (`kimi-k2.6`, `minimax-m3`, `deepseek-v4-flash`) are shipped for when the list command times out. +- Images: kimchi's RPC `prompt` command supports an `images` field (base64-encoded `ImageContent` objects), inherited from pi-mono. The daemon reads validated `imagePaths` at session attach time and includes them in the prompt command. +- Thinking: the daemon exposes kimchi's `--thinking` levels (`off`, `minimal`, `low`, `medium`, `high`, `xhigh`) in the Settings model picker. +- Skills: prompt injection in v1. `extraAllowedDirs` (skill seed and design-system directories) are forwarded as `--append-system-prompt` repeatable flags so the agent knows these directories exist and can Read files inside them. Same pattern as the pi adapter. +- MCP: Kimchi does not accept `mcpServers` in the ACP `session/new` message — it rejects with `Invalid params: mcpServers is not supported`. MCP servers are configured via `~/.config/kimchi/harness/mcp.json` (same `mcpServers` JSON schema as Claude Desktop / Cursor). `od mcp install kimchi` writes to the JSON config file directly. +- Auth: API key resolved from `KIMCHI_API_KEY` env var or `~/.config/kimchi/config.json`. Run `kimchi setup` for interactive first-time configuration. + +### 5.14 Plain stream artifact handoff Adapters with `streamFormat: 'plain'` do not expose structured file-write tool calls to the daemon. Their stdout is still a valid artifact handoff when the model emits Anthropic-style source blocks: From f7153e5d56bdb3ef667aac4575adc1ceba181123 Mon Sep 17 00:00:00 2001 From: Vilius Kazlauskas Date: Thu, 9 Jul 2026 16:38:42 +0300 Subject: [PATCH 3/6] docs fix --- docs/agent-adapters.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/agent-adapters.md b/docs/agent-adapters.md index 4f9e02de54e..509564e1018 100644 --- a/docs/agent-adapters.md +++ b/docs/agent-adapters.md @@ -102,7 +102,7 @@ If both signals agree, detection is confident. If only one signal fires, we mark | **deepseek** | `deepseek` | `~/.deepseek/` | `~/.deepseek/skills/` | ❌ (prompt-injected) | ✅ | ✅ (plain text) | P2 | | **qoder** | `qodercli` | Qoder CLI config | Qoder CLI managed | ❌ (prompt-injected) | ✅ | ✅ (`stream-json`) | P2 | | **pi** | `pi` | `~/.pi/agent/` | `~/.pi/agent/skills/` | ❌ (prompt-injected) | ✅ | ✅ (`pi-rpc` JSON-RPC) | P2 | -| **kimchi** | `kimchi` | `~/.config/kimchi/harness/` | ❌ | ✅ | ✅ (`pi-rpc` JSON-RPC) | P2 | +| **kimchi** | `kimchi` | `~/.config/kimchi/harness/` | ❌ | ❌ (prompt-injected) | ✅ | ✅ (`pi-rpc` JSON-RPC) | P2 | "P0/P1/P2" correspond to the roadmap phases in [`roadmap.md`](roadmap.md). From 59d1c6e7af258f93292afc5b137df1f2f7d40ac1 Mon Sep 17 00:00:00 2001 From: Vilius Kazlauskas Date: Thu, 9 Jul 2026 16:38:49 +0300 Subject: [PATCH 4/6] model list fix --- apps/daemon/src/runtimes/defs/kimchi.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/daemon/src/runtimes/defs/kimchi.ts b/apps/daemon/src/runtimes/defs/kimchi.ts index 4ba69ef4f29..b471f457721 100644 --- a/apps/daemon/src/runtimes/defs/kimchi.ts +++ b/apps/daemon/src/runtimes/defs/kimchi.ts @@ -20,12 +20,14 @@ export const kimchiAgentDef = { versionProbeTimeoutMs: 15_000, fetchModels: async (resolvedBin, env) => { try { - const { stderr } = await execAgentFile(resolvedBin, ["--list-models"], { + // Unlike pi (which prints to stderr), kimchi outputs the TSV table + // to stdout. Stderr carries config permission warnings only. + const { stdout } = await execAgentFile(resolvedBin, ["--list-models"], { env, timeout: 60_000, maxBuffer: 8 * 1024 * 1024, }); - const parsed = parsePiModels(stderr); + const parsed = parsePiModels(stdout); if (!parsed || parsed.length === 0) return null; return parsed; } catch { @@ -34,7 +36,7 @@ export const kimchiAgentDef = { }, fallbackModels: [ DEFAULT_MODEL_OPTION, - { id: "kimi-k2.6", label: "kimi-k2.6" }, + { id: "kimi-k2.7", label: "kimi-k2.7" }, { id: "minimax-m3", label: "minimax-m3" }, { id: "deepseek-v4-flash", label: "deepseek-v4-flash" }, ], From 460c8a3f066aeae0febbba092c25422c6793911e Mon Sep 17 00:00:00 2001 From: Vilius Kazlauskas Date: Thu, 9 Jul 2026 16:54:42 +0300 Subject: [PATCH 5/6] docs fix --- docs/agent-adapters.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/agent-adapters.md b/docs/agent-adapters.md index 509564e1018..6b9aab56a09 100644 --- a/docs/agent-adapters.md +++ b/docs/agent-adapters.md @@ -249,7 +249,7 @@ The adapter declares which strategy to use via `capabilities().nativeSkillLoadin - Invocation: `kimchi --mode rpc [--model ] [--thinking ] [--append-system-prompt …]`, with the composed prompt delivered over stdin via JSON-RPC. Kimchi is built on the [pi-mono](https://github.com/badlogic/pi-mono) coding agent SDK and inherits pi's RPC transport. Using `--mode rpc` (instead of `--mode acp`) gives us multimodal image support, reasoning levels, richer event stream, and avoids the ACP `mcpServers` rejection issue. - Streaming: `pi-rpc` JSON-RPC over stdio. Events include `agent_start`, `turn_start/end`, `message_update` (text deltas, thinking deltas, tool calls), `tool_execution_start/end`, `compaction_start`, `auto_retry_start/end`, `extension_error`. `apps/daemon/src/pi-rpc.ts` maps these onto the same UI event set as the other stream parsers. -- Models: dynamic — `kimchi --list-models` prints a TSV table to stderr that the daemon parses into provider/model picker entries. Fallback hints for the default orchestrator/builder/explorer models (`kimi-k2.6`, `minimax-m3`, `deepseek-v4-flash`) are shipped for when the list command times out. +- Models: dynamic — `kimchi --list-models` prints a TSV table to stdout that the daemon parses into provider/model picker entries. Fallback hints for the default orchestrator/builder/explorer models (`kimi-k2.7`, `minimax-m3`, `deepseek-v4-flash`) are shipped for when the list command times out. - Images: kimchi's RPC `prompt` command supports an `images` field (base64-encoded `ImageContent` objects), inherited from pi-mono. The daemon reads validated `imagePaths` at session attach time and includes them in the prompt command. - Thinking: the daemon exposes kimchi's `--thinking` levels (`off`, `minimal`, `low`, `medium`, `high`, `xhigh`) in the Settings model picker. - Skills: prompt injection in v1. `extraAllowedDirs` (skill seed and design-system directories) are forwarded as `--append-system-prompt` repeatable flags so the agent knows these directories exist and can Read files inside them. Same pattern as the pi adapter. From 528be97641bf802a515049ff81e0b242635ee2e2 Mon Sep 17 00:00:00 2001 From: Vilius Kazlauskas Date: Wed, 15 Jul 2026 15:22:04 +0300 Subject: [PATCH 6/6] chore: trigger mergeability re-check