ctl
Every Terminal Delight window listens on its own control socket, and the same binary is the client. terminal-delight ctl lets a script, a keybinding, a status bar or an agent's own shell change a running window without touching any terminal in it.
terminal-delight ctl tab name "deploy"
terminal-delight ctl mcp on
terminal-delight ctl doc beside /home/you/notes/plan.md
It names and groups tabs, turns panes to their workbench, opens documents, switches the MCP server, picks a skin, and hands a new terminal to a window. Each command gets one line back, ok or err with the reason. By default it talks to the windows on your active Hyprland workspace, or the window you're running in for tab commands; --all or --pid choose others.
Technical lists every command and its reply.
The control socket
Each window, scratch windows included, listens at $XDG_RUNTIME_DIR/terminal-delight/ctl-<pid>.sock, in a directory kept at 0700. The client sends one line and reads one line back, then the connection closes. Effects are queued to the window, so ok means the command was accepted. The CLI checks your command against the window's grammar before sending, so a typo fails at once with the usage line.1
Which windows#
| Flag | Targets |
|---|---|
| none | Every window on the active Hyprland workspace. For tabs: the window you're running in. |
--workspace active|<name-or-id> | The windows on that workspace. |
--all | Every window with a socket. |
--pid <N> | One window. |
tab … always means your own tab and refuses a scope flag. adopt and tabs go to the first target only; everything else goes to every target. Each reply prints as <pid> <reply>. A window with no socket prints err no control socket (older build — reopen this terminal).
Exit codes: 0 when at least one window answered with something other than err; 2 when nothing matched or every reply was err; 1 for a usage error.
The client waits 800 ms for a reply. If a window takes longer, the client prints err unreachable … — swept stale socket and deletes that window's socket, although the window is alive. Until the window restarts, neither ctl nor terminal-delight mcp can reach it. The bench and doc commands and mcp rpc can take longer than that on a busy window. It's tracked in issue 796.
Commands#
After terminal-delight ctl | Reply | Does |
|---|---|---|
ping | pong | Is it there. |
whoami | ok <session> <window-pid> | Which session a window holds. |
paint on|off|toggle | ok | The palette overlay over every pane. |
paint status | on or off | |
skin <name>, skin theme | ok <name> | Pick a skin, or follow the theme's. |
skin status | active=<id> known=<ids> | |
bench on|off|toggle | ok | Every pane to its workbench, or its terminal. |
bench choose <n> | e.g. ok pane 3 | Answer the question waiting on the bench with option n (1 to 20). |
bench submit | Send the open round of answers. | |
bench say <text> | Type a line to the focused pane's agent through the bench, and send it. | |
bench type <text> | The same without sending. | |
doc here <path> | Float a document over the focused pane. The path must be absolute. | |
doc beside <path> | Open it in a pane beside the focused one. | |
doc close, doc scroll <pixels> | Close the floating document; scroll a document pane. | |
mcp status | enabled=on writes=off expose=agents events=on | |
mcp on|off, mcp writes on|off, mcp expose agents|all | ok | The MCP switches, saved with the session. |
mcp rpc <json> | the JSON-RPC answer | One MCP call. mcp-none for a notification. |
adopt --cwd <dir> [--run <cmd>] | ok | Open a new pane in a directory, running a command. Used by SUPER+ALT+T on Omarchy. |
tab name [<text>] | ok 1 | Name your own tab; no text clears it. |
tab group <name>, tab ungroup | ok 1 | Put your own tab in a group, or take it out. |
tabs <json> | ok <n> | Several tab operations at once; see below. |
Tab operations#
tabs takes a JSON array, or {"ops": […]}. Each operation has an op:
op | Fields |
|---|---|
name | name, a string or null |
group | group, and optionally color and text_color for a new group |
ungroup | none |
color | color and/or text_color; null clears |
group_color | group, color, text_color |
collapse | group, collapsed |
A tab operation names its tab with exactly one of tab (its index, which changes when tabs move) or pane (a shell pid in it, which doesn't). Colours are #rrggbb. An error says which operation failed: tabs: op 2: ….
terminal-delight ctl tabs '[{"op":"name","pane":4121,"name":"api"},{"op":"group","pane":4121,"group":"backend","color":"#3ec6d1"}]'
What would prove this wrong#
No ctl command writes bytes into a terminal's input except bench say and bench type, which go to the agent through the bench on purpose. Any other command that does is a bug.
Sources
- The grammar, the client and the replies: ctl.rs.