Summary
On macOS, an opencode serve process (v2.0.21, also observed on v2.0.24) enters a tight, self-sustaining subscribe/unsubscribe loop in the native filesystem watcher, pegging a core and more (~250–320% CPU). The churn is entirely @parcel/watcher's FSEvents backend re-subscribing over skill directories — with zero filesystem changes, so it is not driven by any file activity. Setting OPENCODE_DISABLE_FILEWATCHER=1 stops it instantly.
Environment
- opencode version: 2.0.21 (
.opencode/bin/opencode, launched by OpenChamber) — also reproduced on 2.0.24 (homebrew opencode serve --service)
- OS: macOS 26.6.2 (25G83) / Darwin 25.6.0, arm64
- Terminal: desktop app (OpenChamber);
TERM=xterm-256color, TERM_PROGRAM empty
- Shell:
/bin/zsh
- Install/channel: release/latest
- Active plugins: OpenChamber injects
-opencode.browser (disabled) + /Users/<user>/.config/openchamber/agent-tool/openchamber-agent-tool; global opencode.json plugin is unset.
Reproduction
- On macOS, have several skill roots present, e.g.
~/.claude/skills, ~/.agents/skills, and project-level <project>/.claude/skills + <project>/.agents/skills.
- Start a server that boots locations for those directories, e.g.
opencode serve --hostname 127.0.0.1 --port <p> with cwd $HOME (OpenChamber launches it with OPENCHAMBER_OPENCODE_CWD=$HOME), and open a project.
- Watch CPU:
top/ps shows the process climbing to ~250–320%.
- Watch the log:
~/.local/share/opencode/log/opencode.log grows ~500+ lines/s, ~94% of them watcher subscribe / watcher started / watcher stopped for the skill roots.
sample <pid> shows the time is entirely in the native watcher.
Expected: watchers subscribe once and then sit idle; CPU near zero.
Actual: continuous subscribe → started → stopped → subscribe churn; CPU stays pegged until the process is restarted.
Reproduces consistently on every fresh server launch, with no user interaction and no filesystem changes.
Expected Behavior
Skill-directory watchers should subscribe once, stay subscribed, and idle. No resubscription should occur absent filesystem activity.
Actual Behavior
The watcher loops. Samples show only @parcel/watcher frames (.bun-501-*.node):
FSEventsBackend::startStream → FSEventStreamStart (register_with_server / f2d_register_rpc)
FSEventsBackend::unsubscribe → FSEventStreamStop (dispose_f2d_private_port / f2d_unregister_rpc)
Watcher::triggerCallbacks → Watcher::isIgnored → Glob::isIgnored
Backend::watch / Backend::unwatch
Log growth during a 6-second window:
total lines: 2808
message="watcher subscribe": high
message="watcher stopped": ~257/4s
message="watcher started": ~257/4s
non-watcher lines: 0
Watched paths, all repeated:
~/.claude/skills
~/.agents/skills
<project>/.claude/skills
<project>/.agents/skills
watcher subscribe entries always carry ignores=0 (the skill dirs have no ignore patterns).
Not caused by file changes: a 6-second snapshot of every file/dir mtime under those four roots was byte-identical (diff empty), while the churn continued uninterrupted. So this is a replay/self-trigger loop inside the watcher, not a reaction to writes.
Additional Context
Disabling the file watcher stops it (A/B, same machine/paths):
| Run |
Server CPU |
log lines/4s |
| watcher enabled |
187% |
1701, 1787 |
OPENCODE_DISABLE_FILEWATCHER=1 (relaunch) |
12–18% |
45, 0, 0 |
Env confirmed on the child: OPENCODE_DISABLE_FILEWATCHER=1, OPENCODE_FILEWATCHER_DISABLE=1. In the bundle these gate fs.filewatcher:
fs: { filewatcher: !truthy(process.env.OPENCODE_FILEWATCHER_DISABLE ?? process.env.OPENCODE_DISABLE_FILEWATCHER), fff: ... } — and the @opencode/Watcher service takes an enabled option.
Not the FFF watcher: #32511 root-causes a similar high-CPU symptom to the bundled FFF indexer (@ff-labs/fff-bun, notify-rs). Ours is the Bun/parcel watcher (FSEventsBackend), and OPENCODE_DISABLE_FILEWATCHER=1 (not OPENCODE_DISABLE_FFF) removes it. Worth noting the server here is launched with cwd $HOME, i.e. exactly #32511's trigger, so both problems may coexist.
Related issues: #32511 (high CPU; also flags an fsevents watcher duplication + re-subscribe amplifier), #37111 (@parcel/watcher subscribe under multi-project attach — deadlock, Linux), #35813 (closed; recursive parcel watcher per non-home Location), #21452 (parcel watcher callback shared across subscriptions).
Workaround: OPENCODE_DISABLE_FILEWATCHER=1 opencode serve ... — confirmed to stop the churn (loses live file-tree/hot-reload only). Also OPENCODE_DISABLE_FFF=1 is worth trying since the server runs from $HOME.
Happy to attach full sample output, the raw log window, and lsof on request.
Summary
On macOS, an
opencode serveprocess (v2.0.21, also observed on v2.0.24) enters a tight, self-sustaining subscribe/unsubscribe loop in the native filesystem watcher, pegging a core and more (~250–320% CPU). The churn is entirely@parcel/watcher's FSEvents backend re-subscribing over skill directories — with zero filesystem changes, so it is not driven by any file activity. SettingOPENCODE_DISABLE_FILEWATCHER=1stops it instantly.Environment
.opencode/bin/opencode, launched by OpenChamber) — also reproduced on 2.0.24 (homebrewopencode serve --service)TERM=xterm-256color,TERM_PROGRAMempty/bin/zsh-opencode.browser(disabled) +/Users/<user>/.config/openchamber/agent-tool/openchamber-agent-tool; globalopencode.jsonpluginis unset.Reproduction
~/.claude/skills,~/.agents/skills, and project-level<project>/.claude/skills+<project>/.agents/skills.opencode serve --hostname 127.0.0.1 --port <p>with cwd$HOME(OpenChamber launches it withOPENCHAMBER_OPENCODE_CWD=$HOME), and open a project.top/psshows the process climbing to ~250–320%.~/.local/share/opencode/log/opencode.loggrows ~500+ lines/s, ~94% of themwatcher subscribe/watcher started/watcher stoppedfor the skill roots.sample <pid>shows the time is entirely in the native watcher.Expected: watchers subscribe once and then sit idle; CPU near zero.
Actual: continuous subscribe → started → stopped → subscribe churn; CPU stays pegged until the process is restarted.
Reproduces consistently on every fresh server launch, with no user interaction and no filesystem changes.
Expected Behavior
Skill-directory watchers should subscribe once, stay subscribed, and idle. No resubscription should occur absent filesystem activity.
Actual Behavior
The watcher loops. Samples show only
@parcel/watcherframes (.bun-501-*.node):Log growth during a 6-second window:
Watched paths, all repeated:
watcher subscribeentries always carryignores=0(the skill dirs have no ignore patterns).Not caused by file changes: a 6-second snapshot of every file/dir mtime under those four roots was byte-identical (
diffempty), while the churn continued uninterrupted. So this is a replay/self-trigger loop inside the watcher, not a reaction to writes.Additional Context
Disabling the file watcher stops it (A/B, same machine/paths):
OPENCODE_DISABLE_FILEWATCHER=1(relaunch)Env confirmed on the child:
OPENCODE_DISABLE_FILEWATCHER=1,OPENCODE_FILEWATCHER_DISABLE=1. In the bundle these gatefs.filewatcher:fs: { filewatcher: !truthy(process.env.OPENCODE_FILEWATCHER_DISABLE ?? process.env.OPENCODE_DISABLE_FILEWATCHER), fff: ... }— and the@opencode/Watcherservice takes anenabledoption.Not the FFF watcher: #32511 root-causes a similar high-CPU symptom to the bundled FFF indexer (
@ff-labs/fff-bun,notify-rs). Ours is the Bun/parcel watcher (FSEventsBackend), andOPENCODE_DISABLE_FILEWATCHER=1(notOPENCODE_DISABLE_FFF) removes it. Worth noting the server here is launched with cwd$HOME, i.e. exactly #32511's trigger, so both problems may coexist.Related issues: #32511 (high CPU; also flags an fsevents watcher duplication + re-subscribe amplifier), #37111 (
@parcel/watchersubscribe under multi-project attach — deadlock, Linux), #35813 (closed; recursive parcel watcher per non-home Location), #21452 (parcel watcher callback shared across subscriptions).Workaround:
OPENCODE_DISABLE_FILEWATCHER=1 opencode serve ...— confirmed to stop the churn (loses live file-tree/hot-reload only). AlsoOPENCODE_DISABLE_FFF=1is worth trying since the server runs from$HOME.Happy to attach full
sampleoutput, the raw log window, andlsofon request.