Repository navigation
Description
config: running service never picks up opencode.jsonc edits on Linux (config-directory watcher unsupported)
Summary
On Linux, a long-running background service keeps using the opencode.jsonc content it loaded at startup. Editing permissions/policies in ~/.config/opencode/opencode.jsonc has no effect for subsequent sessions, with no warning to the user, because the config-directory watcher fails to start. The user believes ask rules and deny policies are protecting them while the service runs with the previous (permissive) config.
Environment
- opencode version:
2.0.31+22728d6 - OS:
Linux euterpe 6.12.91 #1-NixOS SMP PREEMPT_DYNAMIC Sat May 23 11:05:02 UTC 2026 x86_64 GNU/Linux(NixOS 25.11, unstable channel) - Terminal:
TERM_PROGRAM=ghostty,TERM=xterm-256color,COLORTERM=truecolor - Shell:
/run/current-system/sw/bin/zsh - Install/channel:
channel=prod,local=false; installed from the Nix flake (nix storepath/nix/store/nx8y73d8m4pac0v2144bqjjpbh8hfsmp-opencode-2.0.31+22728d6/bin/.opencode-wrapped); desktop client talking to the shared background service (opencode serve --service) - Active plugins: builtin only, no third-party plugins; the relevant one is
opencode.config.location-watcher({"id":"opencode.config.location-watcher","source":{"type":"builtin"},"features":{"server":true},"state":{"status":"active"}})
Reproduction
-
Start the shared service with a minimal global config, so it is loaded at boot:
{ "$schema": "https://opencode.ai/config.json" } -
While the service is still running, replace the file with rules that must prompt or block:
{ "$schema": "https://opencode.ai/config.json", "permissions": [ { "action": "external_directory", "resource": "*", "effect": "ask" }, { "action": "shell", "resource": "*", "effect": "ask" } ], "policies": [ { "action": "tool.use", "resource": "shell:sudo *", "effect": "deny" }, { "action": "tool.use", "resource": "shell:rm -rf *", "effect": "deny" } ] } -
In a new session, have the agent run a shell command covered by the deny policy (for example
sudo --version) and any other shell command.
Expected Behavior
The service reloads the config (or at minimum reports that it could not), so the new session prompts for shell/external_directory and sudo --version fails with Blocked by configuration policy.
Actual Behavior
The service keeps the config loaded at startup for the lifetime of the process:
-
sudo --versionexecuted normally, and shell commands ran with no approval prompt at all. -
rm -rf <dir>executed, even thoughshell:rm -rf *is a hard deny. -
GET /api/configfor the already-booted location returns the document with only the startup content, while the same file parsed in a fresh location returns the full rule set:$ opencode api get /api/config | jq -c '.[] | select(.type=="document") | (.info|keys)' ["$schema"] # same file, location that had not been booted before: $ opencode api get '/api/config?location[directory]=/tmp/scratch' | jq -c '.[] | select(.type=="document") | (.info|keys)' ["$schema","permissions","policies"]
-
At startup the config-directory subscription fails while other watchers start normally:
timestamp=2026-10-16T18:44:38.471Z level=INFO run=f797ba4f message="watcher subscribe" path=/home/jb/.config/opencode type=directory ignores=3 role=server timestamp=2026-10-16T18:44:38.473Z level=ERROR run=f797ba4f message="watcher backend not supported" directory=/home/jb/.config/opencode platform=linux role=server timestamp=2026-10-16T18:44:38.474Z level=INFO run=f797ba4f message="watcher subscribe" path=/etc type=entries ignores=0 role=server timestamp=2026-10-16T18:44:38.474Z level=INFO run=f797ba4f message="watcher started" path=/etc type=entries backend=node ignores=0 role=serverFile-level watchers for
AGENTS.md,skill,skillsandentrieswatchers for/,/home,/home/jball start withbackend=node; only the recursive config-directory watch is unsupported. The error repeats on every location boot (12 occurrences in one session).
Additional Context
- Workaround (verified): restarting the service picks the new config up. After
opencode service restart,GET /api/configreports["$schema","permissions","policies"], all fivetool.usepolicies are present, and enforcement works as documented (approval prompts appear; denied commands are blocked). - Restarting fixes enforcement but not the root cause: the config-directory watcher still fails to start on Linux, so the next edit is silently ignored again.
- Impact is security-relevant:
permissions/policiesare documented as the mechanism that makes an ask-by-default profile with un-liftable denies ("Policy … overrides an ask and an 'Allow always' approval alike") safe to run without a sandbox. In this situation those rules are simply absent, so the session falls back to the base policy{ "action": "*", "resource": "*", "effect": "allow" }, and nothing is prompted or denied. - Timing in the reported case: the service booted at 20:44:38 local, the config was rewritten at 21:12:25 local, and sessions started afterwards still ran unrestricted.
- Not caused by per-session modes: the service is launched as plain
opencode serve --service(no--auto,--yolo,--dangerously-skip-permissions), no session has apermissionmode set, and/api/permission/savedwas empty at the time. - The config file is a
mkOutOfStoreSymlink-style symlink from home-manager into the repo (~/.config/opencode/opencode.jsonc→/data/.../dotfiles/config/opencode/opencode.jsonc). The content parses correctly when read fresh, so this is not a JSONC/schema issue. - Suggestion: since a stale config is invisible, either support/poll the config directory on Linux, or log a warning when the config watcher cannot be established, and/or expose an explicit "config changed on disk, reload required" signal to clients.
Activity
opencode-agent commentedon Oct 16, 2026
Thanks for the very thorough report. I think this is a duplicate of #53210.
The
watcher backend not supportederror is logged when OpenCode can't load its native recursive file watcher (@parcel/watcher). Only directory watches use it: the file andentrieswatchers use node'sfs.watch, which is why those all start withbackend=nodeand only the config-directory watch fails. #53210 explains why this happens on the Nix flake build: the bundledwatcher.nodelinkslibstdc++.so.6, and the Nix wrapper doesn't make it available. Recursive watches then never start, and config edits never reach the running service. PR #53213 proposes a fix and is still open.Possible duplicates and related issues, ordered from most to least likely:
type=directorywatches logwatcher backend not supportedand config/skill edits aren't picked up.opencode.jsoncis a symlink, so this may also affect you once the watcher loads.~/.config/opencodeitself is a symlink (inotifyENOTDIR).Until it's fixed,
opencode service restartworks around it. #53920 also reports thatopencode api post /api/location/reloadapplied a config change. The PR #53213 thread describes how to put libstdc++ on the watcher's library path. The release binary run through nix-ld reportedly loads the watcher fine.Your point that a stale security config gives no visible warning is a good one. It would be worth adding to #53210.
The bot will close this issue as a duplicate in 1 day unless you reply explaining how your problem is different.
opencode-agent commentedon Oct 17, 2026
Closing this as a duplicate of #53210, since there hasn't been a reply in the past day. The
watcher backend not supportederror for the config directory has the same cause described there: on the Nix flake build, the native recursive watcher can't loadlibstdc++.so.6. Please follow #53210 and PR #53213 for the fix. Your point that a stale security config gives no visible warning would be a useful addition there. Until it's fixed,opencode service restartpicks up config edits. If your problem turns out to be different, reply here and we can reopen it.