Workspaces
A workspace is a named set of tabs and splits — a tmux session, kept inside one window. Pin one and its whole shape comes back the next time you launch; give its panes startup commands and the session comes back too.
The panel
Workspaces live in the bottom half of the drawer, under the file tree. ctrl-w p focuses it from anywhere; tab hops between the two panels once the drawer has focus. The active workspace also shows as a chip at the left of the status bar.
| j k / ↓ ↑ | move the selection |
| enter / o | switch to the selected workspace |
| a | add one — type a name, enter creates it |
| r | rename the selected workspace |
| d | delete it — y confirms, anything else cancels |
| p | pin / unpin — pinned workspaces survive a restart |
| e | edit the startup commands of every pane in the workspace |
| esc | dismiss the input line, then hand focus back to the terminal |
The same operations are on the panel's right-click menu and the
+ in its header, and
File → New Workspace creates one without naming it.
How they behave
Each workspace carries its own tabs, its own splits, and its own active tab. Switching between them swaps the whole terminal area at once; the shells keep running in the background, so a build you left in another workspace is still going when you come back.
A new workspace always starts at ~/ rather than
inheriting the focused pane's directory — it's a fresh context, not a
continuation. Unnamed ones are called
workspace 1, workspace 2, and so on.
Closing the last pane of the last tab of a workspace closes the workspace; closing the last workspace closes the window.
Pinning
Workspaces are temporary by default. Press p to pin one,
and Oxide writes it to
~/.cache/oxide/workspaces.json: the name, the tabs and
any names you gave them, the split tree, which pane was focused,
and each pane's working directory. On the next launch those workspaces are rebuilt in that
shape, with fresh shells started in those directories.
Running programs don't come back. Layout and directories are restored; processes are not. tmux only manages that because its server never exits — a quit is a quit here. What can come back is the command: see startup commands.
The state file is rewritten atomically, and a file that fails to
parse is moved aside to workspaces.json.corrupt rather
than being overwritten, so a bad write can't quietly erase your
layouts. When the file's format changes between releases, the old
file is copied once to workspaces.json.v2.bak (or
whichever version it was) before the first write in the new one.
Startup commands
Nobody needs the same cargo watch process to
survive a quit — they need cargo watch to be running in
the top-right pane when they come back. So a pane can declare what
it runs, and a pinned workspace re-runs it on restore. It's the
tmuxinator model, kept inside the workspace you already have.
ctrl-w r (or File → Set Startup Command…, or the palette) opens a small input for the focused pane. It's prefilled with the pane's current startup command — or, if it has none, with the last command that ran there, so most of the time you just press enter. An empty input clears it. tab cycles what happens when the command exits:
shell |
drop back to the prompt. The default, and almost always what you want. |
close |
close the pane on a clean exit, exactly as if you'd typed exit. A non-zero status keeps the pane so the failure stays readable. |
restart |
run it again. Exponential backoff from one second, and a breaker: five exits inside a minute stops the restarts with a toast. A run that lasts over a minute resets the count. |
To see or edit the whole workspace at once, press e in
the workspaces panel or pick Edit Startup Commands…
from a row's right-click menu. Every pane is listed as
tab 1 · pane 2 — ~/dev/api with its command; arrows
move between rows, typing edits, tab cycles on-exit,
enter saves the lot. Rows with a startup command show a
▸ in the panel.
Startup commands are saved with a pinned workspace, and only then — set one on a temporary workspace and Oxide reminds you to pin it. Reopening a closed tab (cmd-shift-t) also brings its commands back.
How they run
Each pane waits for its own shell to be ready before firing — the
first prompt the shell integration reports, not a fixed delay — so a
slow .zshrc doesn't lose the command and four panes
restoring at once don't race. If a shell never shows a prompt
(a broken [shell] program, say) the pane gives up after
workspaces.startup_timeout and says so, rather than
firing into a void.
With shell integration on and zsh or bash, the command goes through
the same silent-run channel as "open in $EDITOR":
it isn't echoed at the prompt and never enters shell history. It
does appear in the
command log, so
the status bar shows it running and its exit status is known —
which is what close and restart key off.
Without integration, or on another shell, the command is typed
in visibly followed by enter; that works, but it lands
in history and the pane can't see it finish, so on_exit
behaves as shell.
Before a command fires, its pane shows a dimmed
▸ cargo watch -x check chip in the corner, replaced by
real output once it runs (and ↻ while a restart is
waiting on its backoff).
Turning them off
A startup command that wedges the app needs an out that isn't editing JSON by hand. Any of these restores the layout without running anything:
- hold shift while Oxide launches;
oxide --no-startup-commandsfrom the CLI shim;run_startup_commands = falseunder[workspaces]in config.toml, to turn the feature off for good.
workspaces.json now contains commands.
Anything that can write that file gets a shell command run on your
next launch. It lives in your own ~/.cache and is
written owner-only (0600), and Oxide will never run a
command from anywhere but that file — a per-repository project
file is a possible later feature, and it would have to ask first.