You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
On Linux x64 with opencode 1.18.31 (stable, Homebrew), every invocation of the compiled CLI that executes a JS script — e.g. plugin hook subprocesses spawned as opencode /path/hook.js — extracts a fresh 13,745,312-byte libopentui.so into $TMPDIR (/tmp) and never reuses or removes it. The embedded Bun runtime is v1.3.14, which predates the extraction-dedup fix (oven-sh/bun#29587, shipped in Bun 1.4.0).
In an agent setup where a plugin adapter spawns guard hooks with spawnSync(process.execPath, [hookPath]) on every tool/message event, this leaks ~13.7 MB per event. Observed accumulation: 1,332 files / 18,308,755,584 bytes (~17.05 GiB) in under 2 hours on a 32 GiB tmpfs /tmp, still growing (~12 files / 20 s during active tool use).
This is related to but distinct from #42700 / #28089 / #42880: this report pins the per-script-invocation / hook-subprocess amplification on current stable V1 and gives a deterministic, seconds-long repro that does not require a full TUI launch or a long-running server session.
Each file: sha256 ce73133a58d35e35610ef53353ddeeeb93fb29505dde0cf1854ce25facee241d, SONAME libopentui.so (x86-64 ELF, not stripped, debug info, Zig/clang 20.1.2 via zig-bootstrap).
Control: opencode --version with the same TMPDIR/BUN_TMPDIR leaves 0 files, so this is specific to the script/hook execution path, not all CLI commands.
Observed in normal use (hook amplification)
The plugin adapter runs each guard hook as a child process of the opencode binary: spawnSync(process.execPath, [hookPath]) (~/.config/opencode/plugins/gsd-core.js:230).
Sampling /proc/<serve-pid>/task/<tid>/children + /proc/<pid>/maps for 20 s caught 23 short-lived opencode .../hooks/*.js children, each mapping a distinct, freshly-created 13,745,312-byte /tmp/.*-00000000.so.
lsof on older copies shows none held open; files persist after the creating processes exit.
Natural accumulation: 1,033 → 1,332 files in ~45 min of inspection (rate scales with tool-call/message events); baseline idle ~1 file / 2 s.
All sampled copies are byte-identical to each other and to the hash above.
Expected behavior
Each process reuses a single extracted copy (e.g. a content-hashed path) or cleans up after itself. $TMPDIR must not grow without bound from process invocations.
Actual behavior
One new randomly-named 13.7 MB copy per opencode <script>.js invocation; no dedup, no unlink on clean exit.
Impact
/tmp on tmpfs consumes RAM: ~17 GiB already; ENOSPC is reachable within hours of agent use.
OpenTUI (trigger):@opentui/core eagerly resolves and dlopen()s its embedded type: "file" native lib at module init, so merely importing the TUI code materializes the library — in a --compile binary that materialization goes through the buggy Bun path above.
Workaround
Contain extraction off tmpfs and purge periodically:
Age-based cleanup (safe while running on Linux; mapped inodes survive unlink). Filter by size so the unrelated 5,576,816-byte .bcddef7ff5a7b7ee-00000000.so (a different embedded lib, held open by opencode serve) is not touched:
Permanent: land chore: bump embedded Bun to 1.4.2 #44946 (Bun ≥ 1.4.x). Once a fixed build is in use, the remaining stale files can be deleted after all older processes stop.
Summary
On Linux x64 with opencode 1.18.31 (stable, Homebrew), every invocation of the compiled CLI that executes a JS script — e.g. plugin hook subprocesses spawned as
opencode /path/hook.js— extracts a fresh 13,745,312-bytelibopentui.sointo$TMPDIR(/tmp) and never reuses or removes it. The embedded Bun runtime is v1.3.14, which predates the extraction-dedup fix (oven-sh/bun#29587, shipped in Bun 1.4.0).In an agent setup where a plugin adapter spawns guard hooks with
spawnSync(process.execPath, [hookPath])on every tool/message event, this leaks ~13.7 MB per event. Observed accumulation: 1,332 files / 18,308,755,584 bytes (~17.05 GiB) in under 2 hours on a 32 GiB tmpfs/tmp, still growing (~12 files / 20 s during active tool use).This is related to but distinct from #42700 / #28089 / #42880: this report pins the per-script-invocation / hook-subprocess amplification on current stable V1 and gives a deterministic, seconds-long repro that does not require a full TUI launch or a long-running server session.
Environment
/home/linuxbrew/.linuxbrew/Cellar/opencode/1.18.31/bin/opencode, 185,030,784 bytes, sha256f9dab32248695e9e…, built 2026-09-14Bun v1.3.14 (0d9b296a)(confirmed via strings in the binary)libopentui-h3hyjpa5.so/tmpis tmpfs (32 GiB), uid/gid 1000@openchamber/web1.23.2) →opencode serve(PID 1076) → per-eventopencode ~/.config/opencode/hooks/*.jschildrenTMPDIR/BUN_TMPDIRunset for the serverSteps to reproduce (minimal, no TUI, no server)
Result (verified):
Each file:
sha256 ce73133a58d35e35610ef53353ddeeeb93fb29505dde0cf1854ce25facee241d,SONAME libopentui.so(x86-64 ELF, not stripped, debug info, Zig/clang 20.1.2 via zig-bootstrap).Control:
opencode --versionwith the sameTMPDIR/BUN_TMPDIRleaves 0 files, so this is specific to the script/hook execution path, not all CLI commands.Observed in normal use (hook amplification)
spawnSync(process.execPath, [hookPath])(~/.config/opencode/plugins/gsd-core.js:230)./proc/<serve-pid>/task/<tid>/children+/proc/<pid>/mapsfor 20 s caught 23 short-livedopencode .../hooks/*.jschildren, each mapping a distinct, freshly-created 13,745,312-byte/tmp/.*-00000000.so.lsofon older copies shows none held open; files persist after the creating processes exit.Expected behavior
Each process reuses a single extracted copy (e.g. a content-hashed path) or cleans up after itself.
$TMPDIRmust not grow without bound from process invocations.Actual behavior
One new randomly-named 13.7 MB copy per
opencode <script>.jsinvocation; no dedup, no unlink on clean exit.Impact
/tmpon tmpfs consumes RAM: ~17 GiB already; ENOSPC is reachable within hours of agent use.Failed to open library "/$bunfs/root/libopentui-*.so"error (see tui: leaks ~21MB .so per launch into /tmp; fills tmpfs and breaks TUI startup #42700).opencode <script>(plugin hooks, agent orchestrators, watchers) leaks proportionally to its event rate.Root cause / attribution
bun:ffidlopen()of embedded native libs in compiled binaries names each copy viatmpname(nanoTimestamp + per-VM counter)and never reuses/unlinks it. Fixed by Dedupe extracted embedded native modules in compiled binaries oven-sh/bun#29587 (content-hashed.bun-{uid}-{hash}.{ext}reuse, shipped in Bun 1.4.0); tracked in Compiled binary: Workers leak extracted native .so/.dylib files in /tmp (never cleaned up) oven-sh/bun#29585, fix(ui): avoid blocking on large file diffs #30962, fix(core): expand AWS_REGION in Bedrock Mantle base URL #40076.packageManagerin the rootpackage.json). The upgrade is already tracked: [FEATURE]: Upgrade bundled Bun from 1.3.14 to 1.4.2 #44945 (open) and PR chore: bump embedded Bun to 1.4.2 #44946 (open). This report is direct evidence that the V1 pin is the remaining source of the leak on stable.@opentui/coreeagerly resolves anddlopen()s its embeddedtype: "file"native lib at module init, so merely importing the TUI code materializes the library — in a--compilebinary that materialization goes through the buggy Bun path above.Workaround
.bcddef7ff5a7b7ee-00000000.so(a different embedded lib, held open byopencode serve) is not touched:find /tmp -maxdepth 1 -type f -regextype posix-extended \ -regex '.*/\.[0-9a-f]{16}-00000000\.so' -size 13745312c -mmin +60 -deleteRelated issues
opencode run --format jsonextracts libopentui.so to /tmp on every invocation, causing unbounded disk growth #21427, Headless opencode serve still extracts libopentui.so into /tmp on every start, causing temp artifact buildup #20043, Runaway /tmp .589*-00000000.so artifacts can exhaust disk during long-running usage #16996, opencode serve leaks ~14GB/hour of .so files in /tmp due to non-pooled ripgrep Workers #23804, v2 cli: headless commands load OpenTUI and leak native temp files #37671