Provide means to disable Ctrl-C #2999
Description
Maybe it's just me, but using opencode under windos in WezTerm or Microsofts Terminal App is nearly impossible for me if I cannot stop opencode from crashing whenever I press Ctrl+C. I can live with this not doing what its supposed to do (Copy to clipboard), but simply quitting the program is really bad. Now, I have read about keybindings and the possibility to set an action to "none", (default for "quit" is Ctrl+C), but this does not help because (I guess) Ctrl+C is captured somewhere before it even reaches the keyboard handler. This is what I see in the terminal:
panic: close of closed channel
goroutine 1 [running]:
github.com/sst/opencode/internal/components/status.(*statusComponent).Cleanup(0xc00020a1e0)
/home/runner/work/opencode/opencode/packages/tui/internal/components/status/status.go:319 +0x25
github.com/sst/opencode/internal/tui.Model.Cleanup(...)
/home/runner/work/opencode/opencode/packages/tui/internal/tui/tui.go:948
main.main()
/home/runner/work/opencode/opencode/packages/tui/cmd/opencode/main.go:166 +0xce9
Activity
github-actions commentedon Oct 6, 2025
This issue might be a duplicate of existing issues. Please check:
Feel free to ignore if none of these address your specific case.
rekram1-node commentedon Oct 6, 2025
hm isn't ctrl+c used to stop programs? It shouldn't be causing a panic we will need to check that out but when doing a ctrl + c on a running program, doesn't the kernel send a SIGINT or whatever the windows equivalent is?
rekram1-node commentedon Oct 6, 2025
to copy things you should be able to drag select with your cursor to copy user & assistant messages, in next version of tui the copy behavior will be better right now it is poor
hwacookie commentedon Oct 7, 2025
Thanks for the hints, I know that Ctrl+C is used to interrupt applications (especially CLI apps) in the Linux/Unix world.
However, having that behaviour is very unusual for a Windows user, especially since the Ctrl+C, Ctrl+V keystrokes are "hardwired" for copy/paste operations. Having this abort the app is a real bad UX, especially since the session is not automatically continued upon restart. Two other things: e.g. nano does NOT simply "die" when pressing Ctrl+C. Heck, not even opencode itself simply dies upon Ctrl+C - but only when I use it under WSL. The "drop-dead" behaviour only occurs when being used in Windows Terminal (or WezTerm, and probably others as well)
@sageil : No, I think this is not correct: Yes, Ctrl+C is one of the keybindings that is used to exit the applications, but the documentation also mentions that it is possible to redefine that key to something else, so Ctrl+C should then NOT exit the application anymore. I think, opencode does not even "handle" or "see" the Ctrl+C at all, at least thats what I'd guess from the stacktrace that I get when the app terminates. I suppose they'd need to integrate a "Break" handler or something like that, I remember I had to do something like that for my Java-apps as well: https://stackoverflow.com/questions/1611931/catching-ctrlc-in-java
I suppose the same applies to go programs as well?!
Thorium commentedon Oct 29, 2025
Ok, half an hour of waiting opencode work done, and here we have the results... Let me copy the file answer with default Windows copy short-cut "Ctrl+C", oops, it terminated opencode... how do I now restore the session to recovered the lost job?
Thorium commentedon Oct 29, 2025
I do know the old MS-DOS Ctrl+Shift+Insert and Shift+Insert works, it's just that last 25 years have rewired my brain to try first the Windows standard.
Edit: It works if you press it quickly, it asks for confirm, but pressing long and hard, then it dies immediately
rekram1-node commentedon Oct 29, 2025
@Thorium you can use /sessions to navigate to previous sessions all the work is persisted to disk
pmarreck commentedon Oct 29, 2025
I've configured my Wezterm to behave in 1 of 2 ways when control-C is pressed:
When any text is selected, it copies it.
If no text is selected, it does the normal ctrl-C, which on linux distros stops the current process (sends SIGTERM to it).
Here is the part of my wezterm config that makes this work:
https://github.com/pmarreck/dotconfig/blob/yolo/wezterm/wezterm.lua#L133
Thorium commentedon Nov 1, 2025
I'd love this to be the default behaviour config.
Hona commentedon Nov 16, 2025
Agreed on those 2 for natural feeling Windows defaults
u-dadashek commentedon Dec 1, 2025
Seriously? We are the data, not your brain. I do not use opencode because this quirk makes me think if you can't figure this out what else is really wrong with your thinking.
u-dadashek commentedon Dec 1, 2025
This product has a reasonable chance of adoption by me if the folks running the software do not overlay. You may spend time in rabbit holes, I prefer not to. Ctrl-C is just a very large domain on the keyboard to start fighting over when opencode's adoption might be part of the mission. If not, whatever keep the charm - lose the user.
19 remaining items
ADiv0viDA commentedon May 19, 2026
Windows Terminal, WSL1, i also find it absolutely annoying, i keep using my 40-years-usual shortcuts and most of all don't work or even worse :
I love the app but, in its current state, shortcuts UX is a real messy PITA.
Would it be possible to have presets of shortcuts or at least to switch from Linux to Win shortcuts in settings ?
rossdonald commentedon May 21, 2026
I had all the same issue with ctrl+c and home keys. This is what I'm using in my setup and it seems to work ok So give this a try. Shift+Enter adds a new line, you might have to add this https://opencode.ai/docs/keybinds/#shiftenter
~/.config/opencode/tui.json
{ "$schema": "https://opencode.ai/tui.json", "keybinds": { "terminal_suspend": "none", "app_exit": "ctrl+d,<leader>q", "input_clear": "none", "session_interrupt": "escape", "messages_first": "ctrl+g", "messages_last": "ctrl+alt+g", "input_line_home": "home", "input_line_end": "end", "input_select_line_home": "ctrl+shift+home", "input_select_line_end": "ctrl+shift+end", "input_buffer_home": "ctrl+home", "input_buffer_end": "ctrl+end" } }liangweidonggood commentedon May 21, 2026
Adding another data point from WezTerm on Windows 11:
exit/exitEnvironment: WezTerm (latest) + pwsh 7 + Windows 11 Pro, opencode via scoop.
The fact that Windows Terminal handles all three exit methods fine but WezTerm doesn't suggests the issue is at the intersection of bun/openTUI and WezTerm's ConPTY implementation, not a general Windows SIGINT problem. Both
/exitand Ctrl+C trigger the same bun-level process termination path that WezTerm's ConPTY doesn't handle correctly. Theterminal_suspend: nonetui.json workaround doesn't help.Exit code shown by WezTerm:
2148734499(0x80131523, .NET runtime exception).liangweidonggood commentedon May 21, 2026
Correction to my earlier comment — after further testing in Windows Terminal, all three terminals behave consistently:
exit/exitSo this is purely an opencode issue —
/exitand Ctrl+C both kill the parent process across all Windows terminals, not just WezTerm. Only the plainexitcommand exits cleanly and returns to the shell. WezTerm shows the error message (exit code 2148734499) while Windows Terminal closes silently, but the root cause is the same: the bun/openTUI process termination path is taking the parent process with it.liangweidonggood commentedon May 21, 2026
Confirmed this is a regression. Tested across versions:
/exitand Ctrl+C both exit cleanly, pwsh stays alive ✓/exitand Ctrl+C kill the parent process ✗Consistent with #25677 which reports the same regression starting from 1.14.25. Rolling back to 1.14.21 (via scoop) is a working workaround on Windows.
liangweidonggood commentedon May 21, 2026
Bisected this down to the exact commit:
4877ecc(PR #24215 — "Fix shell cwd after login startup")./exitand Ctrl+C exit cleanly, shell stays alive ✓/exitand Ctrl+C kill the parent terminal/process ✗The PR changed
packages/opencode/src/session/prompt.ts— refactored how the working directory is passed to shell commands (from$PWDcapture to$1positional parameter). This altered the shell process invocation signature for zsh/bash, and appears to have a side effect on how opencode spawns/terminates the TUI shell process on Windows, causing the parent terminal process to be killed when exiting via/exitor Ctrl+C.liangweidonggood commentedon May 21, 2026
Update: Found the actual root cause, not PR #24215.
The real change that introduced this regression is the OpenTUI version bump in v1.14.25:
@opentui/core@opentui/solidPR #24215 (shell cwd fix) was coincidental — the OpenTUI bump from 0.1.99 to 0.1.103 changed how the TUI process terminates on Windows, causing the parent terminal process to be killed on
/exitand Ctrl+C. This aligns with @Hona's earlier comment about it being a bun-level issue.The move from pinned versions (
"0.1.99") to workspace catalog references ("catalog:") in packages/opencode/package.json is what allowed this version jump to land unnoticed.hondrytravis commentedon May 28, 2026
same
DustinX commentedon Jul 22, 2026
Ctrl + C should not be changed.
Anyone who uses the terminal on Windows knows that that stops the running script.
It is a last resort escape hatch for a runaway or hanging script.
There are other ways to trigger a copy: select alone, right click, shift + insert
feat(tui): require double ctrl+c to exit — guard both keybind and SIG…
alextutor commentedon Sep 4, 2026
https://www.unidadvirtual.com/opencode-cli-deseo-anular-la-combinacion-de-teclas-crl-c
Solucion:
Crear el archivo tui.json con app_exit deshabilitado:
Podemos crearlo en forma global o solo para el proyecto:
Opción A) Forma Global > Archivo: C:\Users\tu_usuario.config\opencode\tui.json
Opción B) En el Proyecto > ./tui.json , El archivo lo creamos en la raiz del Proyecto.
{
"$schema": "https://opencode.ai/tui.json",
"keybinds": {
"app_exit": "none"
}
}
Esto deshabilita Ctrl+C como atajo para salir. El valor "none" anula la combinación por defecto (ctrl+c, ctrl+d, q).
Después de crear el archivo, reiniciar opencode para que los cambios tomen efecto.
Elvin-zhujunde commentedon Sep 14, 2026
If you are PowerShell, before starting, try setting $env:OTUI_USE_ALTERNATE_SCREEN=0 and then restart. The same applies to other terminals.
fix(session): the range accounting names the machinery it omits inste…