Repository navigation
Description
Description
After one or more plugin config reloads during the background service's lifetime, the service accumulates plugin instances and never tears down the old ones. Every event (e.g. session.created) is then delivered once per accumulated instance.
Core opencode.plan subscribes to session.created and injects the Plan-mode <system-reminder>. Result: the same reminder is persisted N times (N = instance count), byte-identical, 1–2 ms apart. Observed N from 1 to 18 over a single day; stable repro at N=4.
Not plan-specific: any plugin with event handlers fires N times. A third-party plugin's own log shows the same session.created delivered 4× within one millisecond.
Plugins
oh-my-opencode-slim + a few local .ts plugins. (The duplicate delivery affects any plugin; that one is just the consumer whose own logs exposed the multiplicity.)
OpenCode version
2.0.26 (Bun 1.4.2 runtime), Windows 10 x64
Steps to reproduce
-
Start the app so the background service is running. Cause ≥1 plugin config reload —
opencode reload, or just save any config file (file-watcher reload does the same). -
Run a headless prompt against the live service:
opencode run --agent plan -m <model> --title T --auto "Reply exactly: T" -
Count identical reminders in the new session:
SELECT json_extract(data,'$.text'), COUNT(*) FROM session_message WHERE session_id='<id>' AND type='synthetic' GROUP BY 1;
Dose–response on the same service, one change at a time:
| change | plugin instances in service | identical reminders in next session |
|---|---|---|
| baseline | 4 | 4 |
opencode reload |
5 (new instance added, none destroyed) | 5 |
opencode service restart |
1 | 1 |
| restarting only the terminal/TUI tab | unchanged | unchanged |
Control: the same run with --standalone (private server) → 1.
Screenshot and/or share link
n/a — counts above are from the local session DB.
Additional probe evidence
- Temporary probe plugin counted distinct plugin instances inside the service process: 4 at baseline; every
session.createdwas delivered 4× within 1–2 ms, each delivery injecting exactly 1 reminder → 4 identical synthetic rows, same payload, same md5. - A new instance appears on each reload (probe
SETUPlogged at the reload instant); old instances keep receiving events (no teardown). Watcher leak is visible too: the same config file is watched 6×; deleted plugin files are still watched. - Distribution of reminder multiplicity across sessions that day: {1:8, 2:7, 3:2, 4:6, 6:3, 9:1, 12:1, 14:1, 18:1} — non-monotonic, consistent with per-process accumulation over a long-lived service.
Suggested fix: on reload, dispose previous instances/subscriptions before activating new ones (idempotent activation keyed by plugin id); and/or make stale instances stop receiving events.
Related: #46217 (similar symptom family), #52965, #47727 (related instance-accumulation class), #42764 (closed; different cause).
Activity
opencode-agent commentedon Oct 9, 2026
Thanks for the detailed report and the probe evidence.
I tried to reproduce this on Linux with 2.0.26 and the background service. I used a local probe plugin that logs a per-instance id on setup, dispose and every event, with
oh-my-opencode-slimalso loaded. After each of these I ranopencode run --agent plan --auto ...:opencode reloadseveral timesopencode.jsonIn every case the old plugin instance was disposed before the new one was set up.
session.createdreached exactly one instance, and each new session had exactly one Plan-mode<system-reminder>.So this looks specific to Windows, possibly to how file watching or paths behave there. That would fit the same config file being watched 6× in your logs. I can't test Windows here, so a maintainer with a Windows machine will need to look at it.
If you can, it would help to add:
level=INFO ... message="watcher started"/"watcher subscribe") around a singleopencode reloadthat adds an instance/vs\separatorsRelated issues, most likely first:
Vcza5 commentedon Oct 9, 2026
Follow-up with the two things you asked for.
1. Log lines around a single
opencode reloadthat adds an instanceRepro: duplicate count in the next session went 1 → 2 with this reload. All lines
role=server, ~1s window:Window totals:
watcher subscribe= 18,watcher stopped= 1,msg="loading plugin"= 9.Two things stand out.
(a) The same absolute paths are re-subscribed many times inside one server process (no process restart in between):
watcher subscribecount within this server run...\.config\opencode\skill,...\skills,...\.opencode\skill,...\.opencode\skills...\.config\opencode\AGENTS.md,...\AGENTS.md...\.config\opencode\plugins\*.tsC:\,C:\Users,C:\Users\<user>(entries)(b)
plugin reconciliationruns constantly with a monotonically increasing id: 3080reconciliation completedlines in the log; ids 35–40 all completed within the same second.2. Path alias check (your second question): negative
~/.config/opencode,~/.opencode,~/.cache/opencode,~/.local/share/opencode— checked file attributes andfsutil reparsepoint query. No symlinks/junctions.C:\Users\<user>\...: uppercase drive letter,\separators. No lowercase-drive form, no/form, no 8.3 short form (~1) ever appears in the logs (though all three resolve on this machine). Env vars are not set (OPENCODE_CONFIG/XDG_CONFIG_HOMEempty).~\AGENTS.md,~\.config\opencode\AGENTS.md,~\AppData\...\AGENTS.md), each subscribed separately — expected for instruction discovery.So the 49× subscription is not an alias artifact: identical absolute paths get subscribed repeatedly within one process.
3. Updated dose–response (same live service,
opencode service restartbetween sessions)opencode reloadopencode reloadopencode reloadLocation-scoped: at one moment, a session opened in a brand-new temp directory got 1 reminder while a session in the home directory got 3 — same service process. So multiplicity is per-location, not global.
4. Counter-finding (may help triage)
Ordinary file writes cause heavy watcher churn but did not change the duplicate count in our samples:
.tsloading plugin, 39 re-subscribes)opencode.json(changedshell)loading plugin)opencode.jsonAGENTS.mdopencode reloadSo on Windows the explicit
opencode reloadpath reliably bumps the count in our measurements, while file writes mostly churn watchers. The original "N grew to 18 over a day of config editing" correlation is real, but we cannot currently say which edit produced it — the instrumenting probe plugin has been removed. I can re-add a probe and run a longer session if that would help narrow it down.Env: v2.0.26, Windows 10 x64, background service (
opencode serve --service), Bun 1.4.2.