Repository navigation
[FEATURE]: Session pinning support for Desktop/Web (shared backend) #28813
Description
Feature hasn't been suggested before.
- I have verified this feature I'm about to request hasn't been suggested before.
Note on possible duplicates
- [FEATURE]: Chat pinning and projects #18330 requests chat pinning generally but is scoped to web UI and doesn't address architecture.
- [FEATURE]: Pinned session tabs in the TUI sidebar #24451 proposes pinned session tabs in the TUI sidebar (PR feat(tui): pinned session tabs in the right sidebar #24452).
- feat(tui): pin, quick-switch, and cycle recent sessions #26858 (merged) implemented pinning for the TUI only, using a client-side JSON file (
~/.local/state/opencode/session.json).
This issue is specifically about bringing the same pinning capability to the Desktop app and Web app, and proposes making pin state a shared backend concern rather than duplicating the client-side approach in each UI.
Problem
Session pinning is currently a TUI-only feature (landed in #26858). The implementation stores pinned/recent state in a client-side JSON file (session.json) managed by the TUI's SolidJS store (packages/opencode/src/cli/cmd/tui/context/local.tsx). The Desktop app (packages/desktop) and Web app (packages/app) have no equivalent functionality.
Because the pin state lives purely in TUI-local storage:
- Pins set in the TUI are invisible to Desktop/Web.
- There is no pin/unpin UI in Desktop or Web.
- Each UI would need to independently re-implement the same logic if we follow the current pattern.
Proposed enhancement
We'd like to add session pinning support that works across all three UIs (TUI, Desktop, Web). Two approaches seem viable, and we're opening this issue to get maintainer guidance on the preferred direction before starting implementation.
Option A: Backend-persisted pin state (recommended)
Add a pinned_at column to the session table (or a separate session_pin table) and expose pin/unpin via the existing session HTTP API. All three UIs would read/write pin state through the same backend endpoints.
Pros:
- Pin state is shared across all UIs — pin in TUI, see it pinned in Desktop.
- Single source of truth; no sync issues.
- Natural fit for the existing server-driven architecture (session list already comes from the API).
- Desktop already embeds the opencode server via sidecar, so no new infrastructure.
Cons:
- Requires a database migration.
- Slightly more work upfront.
Option B: Client-side JSON file (lighter alternative)
Desktop/Web could use a session.json file similar to the TUI implementation, stored per-project via Global.Path.state. Each UI manages its own pin state file.
Pros:
- No backend changes or migrations.
- Quick to implement — directly mirrors the proven TUI pattern.
- May be perfectly reasonable since pin state is UI-level preference.
Cons:
- Pin state is not shared between UIs.
- Duplicated logic across three UI codebases.
- TUI already uses
session.json; would need to decide if Desktop/Web share the same file or use separate ones.
What we plan to contribute
Once the approach is confirmed, we are ready to implement the full feature including:
- Backend changes (if Option A): schema migration, API endpoints, and tests.
- Desktop app UI: right-click context menu or button to pin/unpin sessions in the sidebar.
- Web app UI: equivalent pin/unpin interaction.
- TUI migration: update to use the new backend API instead of the local
session.json(if Option A).
We'd love to hear which direction the maintainers prefer before we start coding. Happy to adjust the plan based on feedback.
References
- TUI pin implementation: PR feat(tui): pin, quick-switch, and cycle recent sessions #26858 (
feat(tui): pin, quick-switch, and cycle recent sessions) - Related issues: [FEATURE]: Chat pinning and projects #18330, [FEATURE]: Pinned session tabs in the TUI sidebar #24451
- TUI local state:
packages/opencode/src/cli/cmd/tui/context/local.tsx - Desktop architecture:
packages/desktop/src/main/sidecar.ts(embedded server),packages/app/(shared web UI)
Activity
github-actions commentedon Jul 22, 2026
To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.