Tutorial
Run a throwaway Linux in a tab
Sometimes you want a clean machine: try a package without polluting your host, check a script against a distro you don't run, or poke at something sketchy in a room you can burn down afterwards. Sinclair opens a fresh OS userland as a regular tab — a container is the tab's backing process, so it scrolls, records, themes, and closes like any other pane. This walkthrough opens one, makes one persistent, attaches to containers you already have running, and adds your own images to the picker.
OS tabs need Docker or Podman installed. Sinclair detects
whichever is on your PATH (Docker preferred when both are present); pin
one explicitly with "container-engine": "docker" or
"podman" in your settings. On macOS, ⌘ is the modifier —
on Linux, read it as ⌃ (Ctrl).
1. Open one
Press ⌘⇧T (new_os_tab, also in the File menu as
OS Tabs…). A small picker window opens with the built-in profiles —
Debian, Ubuntu, Alpine, Fedora, and Arch Linux, each shown with the
image it runs — plus a text field. Pick one and you're dropped at a root shell
inside a brand-new container, in a brand-new tab.
The text field does three things: leave it empty and enter launches the
first profile; type a profile's name to pick it by label; or type any OCI
image reference — say node:22-slim — and Sinclair runs that image as a
one-off, no configuration required. The engine pulls an image the first time you use
it, so a first launch can take a moment; after that it's effectively instant.
Alpine ships without bash, so its profile drops you into sh. Every
other built-in runs bash.
2. It's a real tab — and it's disposable
Under the hood the tab's process is simply
docker run --rm -it <image> <shell> on a pty — the same seam
every tab uses. Scrollback, search, copy mode, recording, themes: everything you know
works inside it. There's no special "container mode" to learn.
By default containers are ephemeral: that --rm means
exiting the shell or closing the tab removes the container and everything you did in
it. Install packages, make a mess, close the tab — gone. That's the point.
3. Keep one around
When you do want your changes to survive — a tools image you've set up just
right, a long-running experiment — flip the default lifecycle in
~/.config/sinclair/settings.json:
{
// keep containers when their tab closes (default: remove them)
"container-persist": true
}
Persistent containers are launched with a name, so they can be found and re-entered later. You can also set the lifecycle per profile, which usually reads better than flipping the global default — see step 5.
4. Attach to what's already running
Fresh containers aren't the only thing you can open in a tab — you can drop a shell
into a container that's already running: your compose stack's database, a
long-lived dev box, anything the engine reports. Press ⌘⇧C
(attach_container, also in the File menu as Attach to Container…)
to open the Attach to Container picker. It lists every running
Docker/Podman container by name, image, and uptime — click one to attach a shell in a
new tab. The text field also takes a container name or id directly, for one that
isn't listed.
Prefer to browse? The Containers sidebar panel shows the same list.
Open it with sidebar:left:containers from the command palette
(⌘⇧P) or by clicking through the sidebar (⌘B), then
double-click a row to attach. Either way, if a tab is already
attached to a container Sinclair focuses that tab instead of opening a second one; a
refresh row at the bottom of the panel re-lists.
Attaching uses the engine's exec, so you get a fresh shell inside
the running container without disturbing its main process. With nothing running the
picker shows No running containers; with neither engine installed it shows
No container engine found — install Docker or Podman and reopen.
5. Add your own images to the picker
Repeatable container entries add profiles to the picker. Each is
label | image | command | lifecycle — only the label and image are
required; the command defaults to bash, and the lifecycle
(persist or ephemeral) defaults to the global
container-persist setting:
{
"container": [
"Tools | ghcr.io/me/tools:latest | zsh | persist",
"Node | node:22-slim | bash",
"Debian | debian:12 | bash"
]
}
A profile whose label matches a built-in (case-insensitively) replaces
it — the Debian entry above pins that picker row to
debian:12 instead of debian:latest. Anything else is
appended below the built-ins. A malformed entry never breaks the picker: it's
skipped, and the settings diagnostics tell you what's wrong with it.