cmdq
Type the next command while one is still running.
cmdq is a small terminal wrapper that hosts your shell in a pseudo-terminal
and gives you a separate "queue input" region below a separator. While a
command is running you can type the next command — review it, edit it,
reorder, cancel, or chain it conditionally — and it dispatches automatically
when the current one finishes.
Works best with zsh, bash, and fish. Plain POSIX sh can run inside cmdq,
but shells without prompt/preexec hooks have limited queue lifecycle detection.
Why
In a normal terminal, when a command is running:
- You can't see what you're typing for the next command.
- You can't cancel or edit a typed-but-not-yet-executed command.
- You can't queue more than one.
cmdq fixes all three.
Installation
Shell (macOS & Linux) — recommended
|
Detects your OS / CPU, downloads the matching pre-built binary, and drops it
in ~/.cargo/bin (or wherever CARGO_HOME points). No Rust toolchain
required.
Homebrew (macOS & Linux)
From crates.io
Requires Rust 1.88+ (edition 2024).
Manual download
Grab the platform tarball from the
latest release
and put cmdq somewhere on your PATH.
From source
Quick start
The first run auto-loads OSC 133 prompt-marker hooks for zsh, bash, and fish
inside the cmdq session. To make the integration permanent in your normal
shell sessions too, run:
CLI options
Shell setup
Pick the section for your shell. Each one shows how to install the OSC 133
integration and (optionally) auto-start cmdq whenever you open a terminal.
Why the
CMDQ_ACTIVEguard?cmdqitself spawns a child shell which sources your rc. Without the guard, that child would re-launchcmdqand loop forever.execthen replaces (rather than nests inside) your shell.
Install the integration into ~/.zshrc:
Auto-start in every terminal — append to ~/.zshrc:
[ &&
Reload:
macOS users: custom
ZDOTDIRsetups are supported. The auto-injected shim sources your real zsh startup files, then appends cmdq's prompt markers.
Install the integration into ~/.bashrc:
Auto-start in every terminal — append to your bash rc:
[ &&
Reload:
Install the integration into ~/.config/fish/config.fish:
cmdq --install-integration
Auto-start in every terminal — append to ~/.config/fish/config.fish:
if not set -q CMDQ_ACTIVE
exec cmdq
end
Reload:
source ~/.config/fish/config.fish
POSIX shells can run inside cmdq, but they do not expose reliable prompt
and preexec hooks. Full queue automation requires zsh, bash, or fish.
You can still auto-start cmdq from a POSIX shell if you want the wrapper
available:
[ &&
Reload your profile:
If you'd rather paste the integration snippet yourself (e.g. you manage your dotfiles via a tool that doesn't like generated edits), print it and copy into your rc:
Keybindings
cmdq starts in passthrough mode — keystrokes go directly to your shell. The
queue panel only appears once a command has been running for 1.5 seconds,
so quick commands (ls, cd) don't flash UI. Press F1 or ? any time
the panel is visible for a full help overlay.
Note: while the queue panel is open, ↑ recalls items from the queue, not your shell history. Double-tap
Escto enter raw input mode if you need shell history or want to scroll a pager (git diff,less).
Add to queue
| Key | Action |
|---|---|
| (any printable) | type into the input buffer |
| Enter | add the typed command to the queue |
| Tab | chain — only run if the previous command succeeded |
| Esc | clear the input buffer |
Edit a queued item
| Key | Action |
|---|---|
| ↑ / ↓ | open previous / next queued item for edit |
| Enter | save the edit |
| Esc | cancel the edit (item unchanged) |
| Ctrl-D | delete the item being edited |
| Alt-↑ / Alt-↓ | reorder the item being edited |
Queue control
| Key | Action |
|---|---|
| Ctrl-X | pause / resume auto-dispatch |
| Ctrl-K | clear the entire queue |
Modes
| Key | Action |
|---|---|
| Ctrl-Q | force the panel open even at the shell prompt |
| Esc Esc | raw input — keys go straight to the running app; double-tap again to return |
| Ctrl-\ | send SIGQUIT to a running command; exits raw input when already raw |
Misc
| Key | Action |
|---|---|
| Ctrl-C | forward SIGINT to the running command (auto-pauses the queue) |
| Ctrl-Z | suspend the running command |
| Ctrl-D | quit cmdq (twice if the queue is non-empty) |
| Ctrl-A / Ctrl-E | beginning / end of input line |
| Ctrl-B / Ctrl-F | move one character left / right |
| Alt-B / Alt-F | move one word left / right |
| Alt-Left / Alt-Right | move one word left / right |
| Ctrl-H | backspace |
| Ctrl-U | kill back to start |
| Ctrl-W | delete previous word |
| F1 / ? | show / dismiss the help overlay |
Smart behaviors
- Panel only appears for long commands. Anything finishing in under 1.5s
runs without UI getting in the way.
Ctrl-Qforces the panel open at the shell prompt if you want to queue ahead of time. - Auto-passthrough on alt-screen. When the running program enters
alt-screen mode (vim, htop, less, fzf, btop, …),
cmdqautomatically forwards keystrokes verbatim and hides the queue panel. - SIGINT auto-pauses the queue. Ctrl-C on a running command (or exit status 130) pauses the queue instead of dispatching the next item.
- Bracketed paste. Pasting a multi-line snippet keeps heredocs, loops, and scripts intact while still landing as one queue item.
- Quit-confirm. Ctrl-D with a non-empty queue requires a second press.
- Persistence. The queue lives in
$XDG_DATA_HOME/cmdq/queue.jsonwhen$XDG_DATA_HOMEis set to an absolute path, otherwise your platform data directory, so a restart mid-session doesn't lose pending work. If a restored queue was saved from another working directory,cmdqkeeps it paused and asks for an extra Ctrl-X before running it in the current shell. Corrupt queue files are backed up asqueue.json.corrupt-*instead of overwritten.
How it works
The shell emits \e]133;A, \e]133;C, \e]133;D[;exitcode] markers around
prompts and command execution. cmdq watches the PTY output stream for these
to decide whether keystrokes should pass through to the shell (at a prompt)
or be captured into the queue (when a command is running).
When the shell finishes a command (\e]133;D), cmdq writes the next queued
command's bytes back into the PTY master — same as if you'd typed it.
Development
Caveats
cmdqforwards shell output directly to your terminal instead of emulating a terminal. Colors, hyperlinks, scrollback, selection, OSC 52, and image protocols stay owned by the terminal.- The auto-injected ZDOTDIR shim sources your real zsh startup files before
appending the integration. If your zsh startup mutates global terminal state,
test a fresh
cmdq --shell /bin/zshsession before auto-starting it. - POSIX
shsupport is best-effort because portable shells do not expose a reliable preexec hook. Use zsh, bash, or fish for full queue automation.