Repository navigation
Description
Feature hasn't been suggested before.
- I have verified this feature I'm about to request hasn't been suggested before.
Describe the enhancement you want to request
Summary
Typing during the Starting background server... window is not captured. The terminal is still in cooked mode, so keys are echoed as raw text over the loading message, and when the TUI takes over the tty those characters are flushed and never reach the prompt. Request: buffer keystrokes typed during startup and pre-fill them into the prompt of the session that appears once loading finishes. Nothing should be submitted on its own.
Environment
- opencode version: 2.2.0 (an update to 2.2.5 was offered in the footer)
- OS: Darwin 27.0.0 (macOS, arm64)
- Terminal: TERM_PROGRAM=ghostty, TERM=xterm-256color, COLORTERM=truecolor
- Shell: /bin/zsh
- Install/channel: release,
latest - Active plugins:
./plugins/caveman/plugin.js
Reproduced on 2.2.0; the startup path in packages/cli/src/commands/handlers/default.ts on main (2.2.0, commit 94cd7af) still starts the server before run() from @opencode/tui, and nothing reads stdin in between.
Reproduction
- Use a cold environment so the background service has to start (fresh
XDG_DATA_HOME/XDG_CONFIG_HOME, oropencode service stopafter a first run). On a normal warm start the window is short and easy to miss. - Run
opencodein a terminal. - While
Starting background server...is on screen, typehello world from before the promptand do not press Enter. - Wait for the home screen to appear.
Minimal pty harness used for verification (writes at t=0.5 s, then snapshots the raw output):
pid, fd = pty.fork()
if pid == 0:
os.environ["XDG_DATA_HOME"] = f"{sand}/data"
os.environ["XDG_CONFIG_HOME"] = f"{sand}/config"
os.environ["XDG_STATE_HOME"] = f"{sand}/state"
os.environ["XDG_CACHE_HOME"] = f"{sand}/cache"
os.execvp("opencode", ["opencode"])
fcntl.ioctl(fd, termios.TIOCSWINSZ, struct.pack("HHHH", 40, 120, 0, 0))
drain(0.5); os.write(fd, b"hello world from before the prompt"); drain(13.5)Observed output positions in that run:
Starting background server...at byte 0- the typed text echoed by the tty at byte 31 (t=0.5 s)
- first TUI paint with
Ask anything...at byte 8880
The typed string occurs exactly once in the whole capture, at the echo position. It is never repainted inside the prompt box, which renders empty.
Expected Behavior
- Keys typed while the background service is starting, restarting (
Restarting background server (version mismatch)...), or otherwise before the TUI is ready are kept, not dropped. - Once the session view appears, the buffered text is in the chat input field, editable, and not sent.
hello world from before the promptshould be visible in the prompt after step 4 and should stay there until the user edits or sends it. - Paste during startup is kept the same way, including multi-line text.
- Keys that must stay meaningful (
ctrl+c,esc,ctrl+d) should be handled by the loading screen rather than dumped into the field as control bytes. - If the startup fails, the buffer should not silently disappear; at minimum it should not be lost before the user gets a usable input (for example, keep it for the retry, or print it).
Actual Behavior
- Characters are echoed by the tty in cooked mode on top of the loading line, so the screen shows
Starting background server...hello world from before the prompt. - When the TUI enables raw mode, pending input is discarded. The prompt appears empty and the text is gone. Pressing Enter during startup does not submit anything either, because the line never reaches the application.
- This is deterministic, not intermittent; it is only noticeable when startup is slow (cold service, version-mismatch restart, first run with migrations, many plugins, slow disk or network).
Additional Context
- Related but not the same as [FEATURE]: Paint an editable home prompt before the TUI finishes loading #53696 (
[FEATURE]: Paint an editable home prompt before the TUI finishes loading). That proposal paints a real prompt early and, per its description, also captures early keys; it is a larger change and its early-input behavior is described as astartup.early_inputfallback. This request is narrower: even without an early interactive prompt, no keystroke typed during server setup should be lost, and the text should land in the prompt of the session that opens. - Related: server: v2 removed /tui/append-prompt — external clients can no longer pre-fill the TUI input #54681 (
server: v2 removed /tui/append-prompt) means there is currently no supported way for a second process to inject text into the TUI prompt, so this has to be handled inside the CLI startup path. - Suggested implementation: switch the tty to raw mode (or at least start reading stdin) in the CLI entrypoint before
ServerConnection.resolve, accumulate bytes in a small buffer, and pass the decoded text torun()inpackages/cli/src/commands/handlers/default.tsas initial prompt content for the new or resumed session. The TUI already receives an initialpromptthroughargs.prompt, so the buffer can follow that same path and be rendered as editable text instead of being submitted. - Also worth covering
--miniand non-tty/stdiomodes, where "no prompt yet" can last longer. - Workaround today: wait for the prompt before typing, or start opencode twice (the second start reuses the running service and loads fast).
Activity
opencodejr commentedon Nov 4, 2026
Thanks for the detailed request and the pty harness. As I understand it, you'd like any text typed or pasted while
Starting background server...(or the version-mismatch restart) is on screen to be kept, and to show up as editable, unsent text in the prompt once the TUI loads.ctrl+c,escandctrl+dwould still act on the loading screen.The current code matches what you describe: the CLI waits for the background server before handing the terminal to the TUI, and nothing reads input in between. So keys typed in that window are lost by design today rather than through a bug, which makes this a feature request. Maintainers will consider it.
Related issues:
This can't be done as a plugin, because plugins only load after startup, which is after the keystrokes are already gone.