Repository navigation
Description
Summary
TUI plugins have no supported way to pin or unpin sessions. The pin list (ctrl+f "Pin or unpin session in the session list", exposed as session.pin.toggle) lives in the TUI's own store at ~/.local/state/opencode/session.json, and context.storage.store("session", …) — the documented storage that "synchronizes across TUI instances" — is a different backing store: plugin-side pins never reach the UI, and pins written directly to the file are silently dropped the next time the TUI toggles any pin (it writes its whole startup-snapshot array back).
Environment
- opencode version: 2.0.18
- OS: Ubuntu, Linux 5.15.0-191-generic x86_64
- Terminal: xterm-256color / truecolor (inside a terminal multiplexer)
- Shell: /bin/bash
- Install/channel: npm global install of
@opencode/cli@2.0.18(release) - Active plugins: several local package-directory plugins under
~/.config/opencode/plugins/(a tab/session mirror, a launcher, credits sidebar); the plugin below is a minimal probe of the same shape
Reproduction
-
In a TUI plugin's
setup, join the documented storage and add a pin-shaped entry:const [state, update] = context.storage.store("session", { initial: { pinned: [] } }) await update((draft) => { const pinned = Array.isArray(draft.pinned) ? [...draft.pinned] : [] pinned.push("ses_existingSessionId") draft.pinned = pinned })
-
Read
~/.local/state/opencode/session.jsonand open the session list. -
Separately, add the id to
session.jsonby hand (read-modify-write), open the session list in a running TUI, then toggle any pin with ctrl+f and re-read the file.
Expected Behavior
- Step 1–2: the session appears in the pinned section (and
session.jsonreflects it) — i.e. plugin storage and the TUI's pin state are the same synchronized store, or there is a supported session-pin API for plugins (client.session.pin({sessionID})/unpin, or the pin store exposed as a data surface with events). - Step 3: the plugin-written pin survives the TUI's own pin toggle.
Actual Behavior
- Step 1–2:
state.pinnedinside the plugin shows the entry, but~/.local/state/opencode/session.jsonis unchanged and the session list never shows the pin. The plugin storage store and the pin store are separate. - Step 3: the pin shows in the file (a restarted TUI displays it), but the running TUI's in-memory store never sees it — and its next ctrl+f toggle writes the whole pinned array from its startup snapshot back to the file, silently dropping the plugin-written entry.
Additional Context
- Deterministic on 2.0.18, probed live 2026-10-01 with a minimal TUI plugin that read and wrote both stores and recorded both files.
- Use case: a TUI plugin mirroring session pinning onto an external tab bar (terminal multiplexer tabs), where "pinned" is the user's explicit "keep this open" signal. We now treat
session.jsonas the only channel (plugin-side read-modify-write) and design around the clobbering: tabs kept for sessions a plugin pins are additionally tracked plugin-side and are not dropped when the pin vanishes from the file (mpj/holmes-telephoning-journal#1774if the details help). - The plugin docs phrase
storage.storeas "persists JSON across restarts and synchronizes across TUI instances", which reads as if app-managed lists like pins participate. A one-line clarification — or better, a real pin surface for plugins — would close the trap. - Secondary observation while probing: the session list's pin command is
session.pin.toggle(bound to ctrl+f), and pin state is pruned to top-level sessions — if a pin API is added, its semantics should match that pruning.
Activity
github-actions commentedon Oct 1, 2026
This issue doesn't fully meet our contributing guidelines.
What needs to be fixed:
[FEATURE]:and include the verification checkbox. The issue already provides useful reproduction and environment details.Please edit this issue to address the above within 72 hours, or it will be automatically closed.
This issue might be a duplicate of existing issues. Please check:
session.json; Pinned sessions can be lost when multiple TUI instances write session.json #44736 covers stale writes between TUI instances, while this issue covers plugin/direct-file writes and the missing plugin pin API.For keybind-related issues, please also check our pinned keybinds documentation: #4997
If you believe this was flagged incorrectly, please let a maintainer know.
github-actions commentedon Oct 4, 2026
This issue has been automatically closed because it was not updated to meet our contributing guidelines within the 72-hour window.
Feel free to open a new issue that follows our issue templates.