Skip to content

feat(tui): hidden experiments section with per-tab prompt drafts - #41862

Draft
kitlangton wants to merge 2 commits into
v2from
experiments-section
Draft

feat(tui): hidden experiments section with per-tab prompt drafts#41862
kitlangton wants to merge 2 commits into
v2from
experiments-section

Conversation

@kitlangton

Copy link
Copy Markdown
Contributor

What

Adds a hidden Experiments surface to the TUI: an opt-in home for in-flight features on any channel, reachable only by typing /experiments (it is deliberately absent from the ctrl+p command palette). Each experiment is a registry entry with a title and description; toggling writes experimental.<id> to the TUI config. Graduating or killing an experiment means deleting one registry entry plus its gated branch.

Ships one experiment to give the surface a real tenant:

Per-tab prompt drafts (tab_drafts) — today an unsent prompt draft is a single global slot that follows focus across session tabs. With the experiment on, drafts stay on the tab where they were written, and <leader>n (new session) moves the current draft into the new session instead of leaving a copy behind.

1. Draft on tab two

[Session one]  [Session two]
                active
> WIP draft: notes for session two_

2. Switch to tab one — draft stays behind

[Session one]  [Session two]
 active
> _

3. Switch back — draft restored

[Session one]  [Session two]
                active
> WIP draft: notes for session two_

4. <leader>n — draft moves to the new session

[Session one]  [Session two]  [New session]
                               active
> WIP draft: notes for session two_

Tab two's composer is now empty (moved, not copied).

How

  • packages/tui/src/config/index.tsx — adds an experimental struct to the TUI config schema (experimental.tab_drafts).
  • packages/tui/src/component/dialog-experiments.tsx — new experiment registry + DialogExperiments (a DialogSelect that toggles experimental.<id> via config.update).
  • packages/tui/src/app.tsx — registers opencode.experiments with palette: undefined + slash: { name: "experiments" }, so it is typeable but not listed; session.new moves the in-progress draft into the home route's prompt seed when the experiment is on.
  • packages/tui/src/component/prompt/index.tsx — the module-level draft stash gains a Map keyed by tab (sessionID, or home) when the experiment is on. Two subtleties:
    • the session ID is captured once at Prompt setup; reading props.sessionID lazily would observe the next route during onCleanup and stash the draft under the wrong tab (the draft would follow you, one tab behind)
    • the carried draft is shallow-copied before reset(), because reset() merges an empty prompt into the same underlying store object that unwrap exposes

Default behavior (experiment off) is byte-identical to today: one global stash slot.

Scope

  • No experiments UI in /settings — the section is intentionally separate and unlisted. Happy to surface it differently if we want more/less discoverability.
  • The stash map is unbounded across closed tabs (entries are consumed on restore; abandoned drafts of closed sessions linger in memory for the process lifetime). Trivial to cap if we care.
  • No tests yet — the stash is module-level state inside the Prompt component; testing it well probably wants a small fixture harness. Will add if we like the direction.

Testing

  • bun typecheck in packages/tui — clean.
  • End-to-end via opencode-drive against this branch (--dev): created two sessions, enabled the experiment through /experiments, verified the draft stays on its tab, restores on return, moves on <leader>n, and the source tab's composer is empty afterwards. Also verified experimental.tab_drafts: true lands in the config file.

Demo

Real end-to-end run recorded with opencode-drive (simulated model, real TUI from this branch): creates two sessions, opens /experiments, toggles the experiment on, writes a draft on tab two, clicks between tabs to show the draft staying put, then ctrl+x n moving it into a new session.

experiments-demo.mp4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant