Repository navigation
Description
Summary
The watcher.ignore config key is declared in the opencode config schema but is never consulted for plugin hot-reload. Its only consumer applies ignore to config documents only, while the config-directory watcher and each plugin entrypoint watcher start unconditionally with fixed ignores, so watcher.ignore cannot suppress watching of a plugin directory or plugin files.
Environment
- opencode version: 2.0.28
- OS: Linux 7.0.0-38-generic x86_64
- Terminal: TERM_PROGRAM=vscode, TERM=xterm-256color, COLORTERM=truecolor
- Shell: /bin/bash
- Install/channel: release build at
~/.opencode/bin/opencode - Active plugins: 5 local plugins under
.opencode/plugins/(agentgate.js, instructions.js, limits.js, readonly.js, taskgate.js); no plugins from config entries
Reproduction
- Create a workspace with plugins under
.opencode/plugins/(e.g.taskgate.jsimporting a helper from.opencode/lib/). - Add
"watcher": { "ignore": [".opencode/plugins", "**/.opencode/plugins/**"] }toopencode.json(the bug also reproduces with the key absent). - Start opencode and inspect
~/.local/share/opencode/log/opencode.logforwatcher started/loading pluginlines. - Edit a plugin file while opencode runs.
Expected Behavior
watcher.ignore should suppress watching of the listed paths, including the plugin directory and the plugin files, so no watcher is started for them and plugin HMR does not trigger on edits under ignored paths.
Actual Behavior
watcher.ignore is only applied to config documents. The single consumer of the key filters by document type:
if (type !== "document" || !info.watcher?.ignore) continue;
l.add(h.info.watcher.ignore)Meanwhile the config-directory watcher and every plugin entrypoint watcher start regardless of watcher.ignore, using hard-coded defaults (["node_modules",".git","**/{node_modules,.git}/**"]). The log shows the directory watcher with 3 built-in ignores, then each plugin file watched with no ignores, immediately followed by plugin loading:
watcher started path=.../.opencode type=directory backend=inotify ignores=3
loading plugin id=.../.opencode/plugins/taskgate.js entrypoint=file://.../taskgate.js
watcher started path=.../.opencode/plugins/taskgate.js type=file backend=node ignores=0
So plugin HMR keeps working for paths that watcher.ignore is documented to ignore, and the config key has no effect on it.
Additional Context
- In our project
watcher.ignoreis not set at all; the impact is reduced because plugin sources live in a separate directory and are published by an install step, but HMR still watches them withignores=0. - Reproducible consistently on every start; not intermittent.
- No workaround via config found; suppressing plugin reload currently requires not placing files under watched plugin paths.
- Related code locations: config schema (
watcher.ignoreentry) and theopencode.config.location-watcherplugin.
Activity
opencode-agent commentedon Oct 16, 2026
Thanks for the detailed write-up, @lookson111!
In the current code,
watcher.ignoreonly applies to the workspace file watcher. Theentry.type !== "document"check inopencode.config.location-watchercollects the ignore patterns from each config document (eachopencode.json). It doesn't limit them to document files. Plugin hot-reload and the.opencodeconfig-directory watcher are a separate mechanism with fixed ignores, and the docs don't saywatcher.ignorecovers them. So this works as currently designed.That makes this a feature request: a way to stop watching plugin files and the config directory, or to turn off plugin hot-reload, either through
watcher.ignoreor a dedicated option. The maintainers will consider it. A plugin can't do this, because those watchers belong to the core plugin/config loader.Related issues about config/plugin reload watching:
Dante-dan commentedon Oct 16, 2026
I’d propose an explicit opt-in
watcher.reloadIgnorerather than changingwatcher.ignore: existing workspace exclusions should not silently start disabling config/plugin reloads.Proposed contract:
reloadIgnoreaffects automatic reload watches for config directories and local plugin sources, including imported local dependencies. It does not affect discovery or initial loading. Unset means current behavior..opencode/plugins/**; out-of-tree sources require a matching absolute rule or a rule declared alongside that source.The current split is in
ConfigWatch.planandPluginModule.make. The latter also watches missing dependencies via an existing ancestor, so exclusions must be evaluated against the requested source path before selecting that fallback target.Acceptance checks would cover initial loading of excluded plugins, edits through either watch route causing no reload, ordinary config/non-excluded plugin edits still reloading, removing an exclusion, imported/missing dependencies, and relative/absolute/glob rules across global and project configs. This is based on code inspection, not a runtime reproduction; it does not address debounce or plugin disposal in the related reports.
Would a core maintainer approve this approach and config surface?