Skip to content

feat(kilo-cli): add the Kilo host and the feature placement finder - #15232

Merged
marius-kilocode merged 5 commits into
v2from
kilo-host
Oct 19, 2026
Merged

marius-kilocode merged 5 commits into
v2from
kilo-host

Conversation

@marius-kilocode

Copy link
Copy Markdown
Collaborator

Implements #15229 (the host, plan unit U-E0-01, #15172, and the automation behind the v2-feature-placement skill). Stacked on #15228.

What Problem This Solves

The v2 line had no Kilo entry point. bun dev ran the upstream CLI, so the only way to add a Kilo plugin was a marked line in an upstream built-in list (the Gateway in packages/core/src/plugin/provider.ts). Every new Kilo feature would add another line to a shared upstream file. The placement skill also had no tool: its commands had to be run by hand, and several of them gave wrong answers.

Why This Change Was Made

  • Host (rung 2). packages/kilo-cli is Kilo's entry. src/index.ts mirrors packages/cli/src/index.ts (the upstream handler map, the same layers, Global.layerWith composition point) and adds KILO_* environment translation (src/env.ts), Kilo's app name (src/app.ts) and a serve handler (src/serve.ts, mirror of the upstream one) that passes KiloHost.overrides to the server. src/host.ts replaces SdkPlugins.node with a node that registers KiloPlugins through SdkPlugins.register, and replaces App.node with Kilo's app name. bun dev (script/dev-isolated.ts) starts this entry. The CLI builds every server command from selfCommand(), so the background service, --standalone and serve --stdio all run the host's serve with the overrides.
  • Kilo plugin. packages/kilo-plugin now exports KiloPlugins (the Gateway plugin). The Gateway registration left provider.ts; that file and its test are back to the upstream version. Upstream's KiloPlugin is back in the built-in list and runs before host-registered plugins; the Gateway overwrites its OpenCode referer and title (the core Gateway tests now run both in that order).
  • No SdkPlugins.register typing seam. The loader gives a registered plugin only its Scope. The host provides the Gateway's Bus with Effect.provideService from the replacement node's deps, the same global Bus. Limit, recorded in the strategy and the skill: a Location service (for example SessionCompaction.Service) cannot be given this way; that needs one seam in plugin/supervisor.ts when the first feature needs it.
  • Generic seams (rung 3). ServerProcess.start takes overrides and passes them to createRoutes, which already accepts them. Options.overrides in packages/cli/src/server-process.ts passes them through. packages/cli/package.json exports ./* like core, server and util. Each is in shared-patches.json with its missing seam.
  • Environment. env.ts translates the 17 v1 KILO_* names whose OPENCODE_* name v2 reads (v1 flag modules on main intersected with v2 reads). No prefix rule: v2 reads OPENCODE_API_KEY as the OpenCode Zen key, so KILO_API_KEY must not be copied.
  • Root patches. The default bun dev profile moved into the host package (packages/kilo-cli/.gitignore), so its two root .gitignore lines went. The root dev script stays (it is the only bun dev entry, and upstream's script runs the upstream CLI with the real data). The README patch stays (a package does not own the front page). The other .gitignore patterns are not host entries.
  • Wrinkles. The client default ["opencode", "serve", "--service"] (packages/client/src/effect/service.ts:61) is never used by the CLI or TUI: they pass selfCommand(), so the host spawns itself. The default stays for clients that pass no command (D-4). The TUI built-in list (KiloTeams in packages/tui/src/plugin/builtins.ts) keeps its marked line: the list is in the TUI process, which SdkPlugins does not reach; a generic seam needs an @opencode/tui export plus an extension point (not fewer lines), and the config path (tui/src/plugin/context.tsx) loads only npm packages or local files, which a compiled binary does not have.
  • Placement automation. bun script/upstream/placement.ts <path-or-module> prints, mechanically, the plugin domains and hooks that match a module, the upstream plugins that are or extend it, its service nodes with the host call, the OPENCODE_* variables it reads, existing seams and markers, whether the path is Kilo-owned, and a suggested first rung. --imports fails when a logic package (packages/kilo-*-core) imports @opencode/* and prints the distinct core-internal modules per adapter. CI runs --imports, and a new kilo packages job runs the kilo-plugin and kilo-cli tests (Turborepo runs only the package tests listed in turbo.json; this avoids another shared patch).
  • Skill fixes. Every command in .kilo/skills/v2-feature-placement/SKILL.md was run under POSIX sh. Fixed: the hook listing (missed editor methods and non-readonly hooks), the upstream plugin search (** does not expand in sh, and tool plugins have no define(), the node search for single-file areas, the environment search (missed packages/util), the import checks (rg -oh prints help, so every count was 124), and the pre-commit patch checks (need --worktree). The host step now says where each kind of change goes. v2-migration, kilocode-merge-minimizer and the fork conventions say the host exists.

User Impact

  • bun dev starts the Kilo host. The Kilo Gateway provider and the /teams commands work as before; the plugin list shows kilocode.gateway with source sdk.
  • The default dev profile moved from <repo>/.kilo-v2-dev to packages/kilo-cli/.kilo-v2-dev. Move an existing profile there, or keep using KILO_V2_PROFILE.
  • KILO_CONFIG_DIR, KILO_CONFIG_CONTENT, KILO_SERVER_PASSWORD and the other translated names now work on the v2 CLI.
  • A new Kilo server plugin goes into KiloPlugins, with no upstream edit.

Evidence

Self-test (real CLI, isolated profiles, --standalone where a service port could collide):

Scenario Result
TUI through the host (vscode-self-test harness, signed in with KILO_API_KEY from the v1 auth file): processes are packages/kilo-cli/src/index.ts --standalone and packages/kilo-cli/src/index.ts serve --stdio --port 0 pass
Model picker shows the Kilo Gateway provider; selected DeepSeek: DeepSeek V4.1 Flash (Kilo Gateway), asked for VERSION in math.ts: one search, answer 1.2.3, no log errors pass
/team shows /team, /teams, /org, /orgs ("Switch between Kilo Gateway teams") pass
bun dev run --standalone --model kilo/deepseek/deepseek-v4.1-flash "Reply with only the word PONG" prints PONG pass
Background service: bun dev plugin list --builtin lists kilocode.gateway sdk; the service process is packages/kilo-cli/src/index.ts serve --service; bun dev models lists the Gateway free models; bun dev service stop stops it pass

Automated checks:

Command Result
bun test in packages/kilo-cli (isolated HOME/XDG) 4 pass: env translation, Gateway token not copied, server with the host overrides lists kilocode.gateway (sdk, active) and serves the Kilo provider from a local Gateway fixture, and a host service smoke (service set port, service start, /api/plugin, service stop with isolated HOME and XDG). A mutation check (upstream serve handler in the host) makes the service smoke fail
bun test in packages/kilo-plugin 1 pass
bun test test/kilocode/gateway.test.ts test/plugin/provider-kilo.test.ts in packages/core 14 pass
bun test test/process.test.ts in packages/server; bun test test/kilocode in packages/cli (dev-isolated now runs the host) 3 pass; 1 pass
bun test in packages/cli (whole package) 338 pass, 1 fail: debug-paths.test.ts compares home with the real home, and my isolation set OPENCODE_TEST_HOME. It passes with only XDG isolated
Upstream compiled service smoke: bun run script/build.ts --single --skip-install, then script/service-smoke.ts with isolated HOME and XDG exit 0
bun test and bun run typecheck in script/upstream 83 pass; clean
bun typecheck in packages/kilo-cli, packages/kilo-plugin, packages/core clean
bun run check 28/28 typecheck tasks, lint 0 errors, run in a copy of this tree outside the main checkout. Inside this worktree, packages/plugins/figma and the tsgo -b packages fail on zstdCompressSync: TypeScript also loads @types/node@22.13.9 from the enclosing main checkout's node_modules. Not related to the change
bun script/check-shared-patches.ts, bun script/check-opencode-annotations.ts, bun script/check-workflows.ts ok
bun script/upstream/progress.ts, then --check up to date

Shared-patch baseline (check-shared-patches.ts):

Count Before After
files 14 15
markedLines 48 45
unmarkedLines 18 18
deletedFiles 0 0

Two feature files retired (provider.ts, provider-kilo.test.ts), three generic seam files added. files rises by one, which is why the limit goes up in this PR.

Import rule (bun script/upstream/placement.ts --imports): packages/kilo-gateway-core 0 @opencode/* imports. Core-internal modules per adapter: packages/core/src/kilocode 2 (bus, variant), packages/kilo-cli/src 3 (app, bus, plugin/sdk: the host's composition seams), packages/kilo-plugin/src 0 (its import of @opencode/core/kilocode/gateway is Kilo-owned), packages/tui/src/kilocode 0. Distinct total 4.

Placement finder on the strategy's examples: session/compaction.ts gives the session.compaction hook, opencode.config.compaction (transform on SessionCompaction.Service) and a location node; tool/plugin/grep.ts gives the file as opencode.tool.grep with the tool hooks and ToolEditor.update("grep", ...); util/src/global.ts gives no hook and Global.node.replace(Global.layerWith(...)).

Progress map: no change, 12/9854 before and after. The host is v2 infrastructure with no v1 cell; no disposition added.

Skipped tests: none. Mirrored files: packages/kilo-cli/src/index.ts (from packages/cli/src/index.ts) and packages/kilo-cli/src/serve.ts (from packages/cli/src/commands/handlers/serve.ts), both at v2.0.30.

Limits: only the free and DeepSeek V4.1 Flash models were exercised; team switching was not run.

Placement

Change Rung Why not lower Proof
Host entry, serve handler, app name, Global.layerWith point 2 n/a packages/kilo-cli/src/{index,serve,app}.ts (index and serve are mirrors)
Gateway registration through SdkPlugins.register, Bus provided by the host 2 n/a packages/kilo-cli/src/host.ts, KiloPlugins in packages/kilo-plugin/src/index.ts; provider.ts back to upstream
KILO_* environment translation 2 n/a packages/kilo-cli/src/env.ts
Dev profile in the host package Kilo-owned n/a script/dev-isolated.ts, packages/kilo-cli/.gitignore; 2 root .gitignore lines removed
overrides on ServerProcess.start 3 no rung 1 or 2 way to give the process server's routes a replacement packages/server/src/process.ts, 3 lines kilocode_change(host) seam
Options.overrides pass-through 3 ServerProcess.run built the server options itself packages/cli/src/server-process.ts, 2 lines kilocode_change(host) seam
./* export of @opencode/cli 3 the CLI exported only ./run and ./server-process, so no entry could reach Commands, Runtime or a handler packages/cli/package.json, 1 unmarked JSON line
SdkPlugins.register typing none upstream already allows it: the host satisfies the requirement with Effect.provideService not added
KiloTeams TUI registration 3 (unchanged) the TUI list is in the TUI process; seam is not smaller (see above) packages/tui/src/plugin/builtins.ts, seam text updated
Root dev script, README 3 and 4 (unchanged) see above shared-patches.json texts updated
placement.ts, tests, CI jobs, skills Kilo-owned n/a script/upstream/placement.ts, .github/workflows/kilo-v2.yml

Shared files touched: packages/server/src/process.ts (3), packages/cli/src/server-process.ts (3), packages/cli/package.json (3), .gitignore (3, two lines removed), packages/core/src/plugin/provider.ts and packages/core/test/plugin/provider-kilo.test.ts (restored to upstream). Core-internal imports added: @opencode/core/app, @opencode/core/bus, @opencode/core/plugin/sdk in the host.

@github-actions github-actions Bot added the area:cli CLI, TUI and core engine label Oct 19, 2026
Base automatically changed from host-strategy to v2 October 19, 2026 09:06
# Conflicts:
#	migration-tracking/plans/v2-host-strategy.md
@github-actions

Copy link
Copy Markdown
Contributor

➖ v2 migration progress: 0.1% → 0.1% (0 done, 0 total, 0 dropped; 12/9854 cells)

No change to the progress map.

v2 migration progress map at this commit

Full map · how cells close

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:cli CLI, TUI and core engine

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants