Skip to content

fix(cli): stop eager file watchers on JetBrains - #12897

Merged
kirillk merged 3 commits into
mainfrom
fix-jetbrains-eager-watchers
Aug 5, 2026
Merged

fix(cli): stop eager file watchers on JetBrains#12897
kirillk merged 3 commits into
mainfrom
fix-jetbrains-eager-watchers

Conversation

@kirillk

@kirillk kirillk commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

What

Extend the existing VS Code watcher gate so the JetBrains client also skips eagerly warming the v2 location stack. One-line behavioral change in KilocodeWatcher.eager():

return client !== "vscode" && client !== "jetbrains"

Why

Reported in #12721: on macOS, the JetBrains-spawned kilo serve process pins 150–198% CPU and grows RSS to 10+ GB while idle. VS Code does not reproduce it.

The cause is a structural difference between the two clients. KilocodeWatcher eagerly warms the location stack for every instance and holds it for the whole session, which starts a native @parcel/watcher subscription. This gate was already turned off for VS Code (commit 160b0666, "avoid eager worktree watchers") but left on for JetBrains.

On macOS, @parcel/watcher uses FSEvents, which watches the entire subtree recursively at the kernel level — the ignore list is only a userspace post-filter. So an always-on watcher on a churny workspace (Rider/ReSharper constantly touch .git and build outputs) keeps receiving and processing every event, and the per-event fiber fork amplifies it into CPU burn and native-memory growth (RSS, not JS heap).

That work has no consumer on JetBrains:

  • The watcher's only event consumer is Vcs, which publishes vcs.branch.updated.
  • The only consumer of vcs.branch.updated is the CLI/TUI sidebar branch label (packages/tui/src/context/sync.tsx).
  • JetBrains reads its branch on demand via its own git branch --show-current and never subscribes to the event (verified — no consumer in packages/kilo-jetbrains/).

So the eager watcher is pure idle overhead for JetBrains, exactly as it was for VS Code.

Behavior after this change

  • JetBrains / VS Code: no eager, idle watcher. If a real file/pty route needs the stack during active work, it still builds lazily and is torn down with the instance. No functional loss (branch display comes from their own git).
  • Standalone CLI / TUI: unchanged — stays eager so its sidebar branch label keeps updating live (the live integration test still passes).

Testing

From packages/opencode/:

  • bun test ./test/kilocode/instance-vcs-watcher.test.ts — added a eager("jetbrains") === false case; all 4 tests pass (incl. the live branch-update test proving the standalone CLI still watches). Note: the suite must run with KILO_CLIENT unset (as in CI); inside a Kilo session shell KILO_CLIENT=vscode is inherited and skews eager(undefined).
  • bun run typecheck — clean.
  • bun run script/check-opencode-annotations.ts --worktree — no markers needed (kilocode/-owned path).

Rollout note

JetBrains runs a pinned, downloaded CLI release, so this fix reaches JetBrains users only after a CLI release is published and the pin in packages/kilo-jetbrains/package.json is bumped to it. Interim user workaround: launch with KILO_EXPERIMENTAL_DISABLE_FILEWATCHER=true.

Fixes #12721

The JetBrains backend eagerly warmed the v2 location stack for every
instance, which starts a native @parcel/watcher subscription that lives
for the whole session. On macOS FSEvents watches the entire subtree
recursively (the ignore list is only a userspace filter), so this
always-on watcher burns CPU and leaks native memory while the IDE is
idle — the cause of the 150%+ CPU and multi-GB RSS growth reported in
`kilo serve` on macOS.

The watcher's only consumer is the CLI/TUI sidebar branch label via the
vcs.branch.updated event. JetBrains, like VS Code, has its own git
integration and does not consume that event, so eager watchers are pure
overhead for it. Extend the existing VS Code gate to also exclude
jetbrains; the standalone CLI/TUI stays eager, and editor clients still
build the stack lazily if a real file/pty route needs it.

Fixes #12721
@kilo-code-bot

kilo-code-bot Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

lgtm — the one-line gate extension is correct and matches the established VS Code pattern. Verified that the JetBrains plugin spawns kilo serve with KILO_CLIENT=jetbrains (so the gate actually triggers), that nothing in packages/kilo-jetbrains/ consumes vcs.branch.updated (only the TUI sidebar does), and that other LocationServiceMap consumers (file/pty routes, agent) build the stack lazily on demand, so skipping the eager warm has no functional loss. The change strictly reduces resource usage — no new allocations, subscriptions, or handles, so no memory-leak concerns. Test addition exercises the real gate, and the changeset is user-facing and correctly patch-scoped.

Files Reviewed (3 files)
  • .changeset/quiet-jetbrains-watchers.md
  • packages/opencode/src/kilocode/watcher.ts
  • packages/opencode/test/kilocode/instance-vcs-watcher.test.ts

Reviewed by kimi-k3 · Input: 48.2K · Output: 5.5K · Cached: 258K

Review guidance: REVIEW.md from base branch main

@kirillk
kirillk merged commit b50e660 into main Aug 5, 2026
30 checks passed
@kirillk
kirillk deleted the fix-jetbrains-eager-watchers branch August 5, 2026 15:26
t7tran pushed a commit to t7tran/kilocode that referenced this pull request Aug 14, 2026
…atchers

fix(cli): stop eager file watchers on JetBrains
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Severe Memory Leak (10+ GB RAM) & High CPU (>150%) in background daemon (kilo serve) on macOS / JetBrains Rider

2 participants