Skip to content

Commands

Command Description
jailbee init First-time setup: create Incus profiles, ACLs, shared directories
jailbee apply [-y] [--no-restart] Re-apply current config (profiles, ACL, /etc/hosts, dockerd proxy); prompt to restart containers if profiles changed, and dockerd if the proxy config changed
jailbee new <name> [<base>] [opts] Create container, clone repo, run autostart. <name> names the environment (used as the branch inside the container, slugified into the container name). <base> sets the container's base branch: it is branched off when <name> is new, and used purely as the comparison anchor when <name> already exists (that branch is cloned as-is for review, after a confirmation). Without <base> the base is the repo's default branch. --current, --pr <N>, --mount, --background, --tmux, --shell, --attach shell|tmux|none, --no-clone, --no-autostart, --yes, --name <container>, --net strict|loose, --memory <size>, --cpu <n>, --claude-group <g>, --from-base <image> (create from an image other than the golden one), --wait/--no-wait (override a detach: true autostart stage for this run — see below). See jailbee new --help for what each does
jailbee ls [--all] [-o json] [--fields …] List managed containers + their git status (own repo by default; --all for every repo). LOCAL ±/L↑ — the diff vs the host's currently checked-out branch, as opposed to AHEAD ±'s pinned base — are off by default; opt in with --fields or the ls: config block (table output only; -o json always keeps its built-in field set unless --fields is passed). See Configuration
jailbee job ls [--all-repos] [-o json] [--fields …] List in-flight and failed background jobs with phase, pid, age, error and log path
jailbee job log <name> [--follow] Print (or follow) the worker log of a background job — including a detached autostart run's supervisor; there is no separate jailbee autostart log
jailbee job clear [<name>] [--all] Acknowledge a dead background job — clears the failed/stale record without touching the container. Refuses a job whose worker is still alive. Leftover boot records need no acknowledging: a jailbee start/jailbee restart that completes clears its own
jailbee dashboard (alias: jailbee tui) Live, auto-refreshing TUI of containers across all repos; navigate + act (Enter). The action menu carries the workflow commands too — pr, git push, git push --pr ("refresh from PR head", review containers only), git pull, git diff, job log — each shown only when it would do something. Quick keys: t/s tmux/shell, i/c IDE/Chrome, p open the PR, P create/update it, u update from base, d show the diff, Space fold the repo group under the cursor, F2/S settings overlay (columns + folding), h/? help, e/E edit the selected row's repo config (E: the global one), n create a container in the selected row's repo (asks for a branch and a base branch, then runs jailbee new in the terminal)
jailbee shell <name> Interactive shell (lands in the in-container clone)
jailbee tmux <name> Attach to the autostart tmux session inside the container
jailbee exec <name> [--cwd repo\|home\|<path>] [--detach\|-d] -- <cmd> Run a command in the container as the dev user (e.g. jailbee exec smoke -- pnpm test). --detach/-d runs it in the background — it survives jailbee returning and its output goes to a log file inside the container (/tmp/jailbee-exec-<timestamp>-<uuid>.log); needed for a GUI app (jailbee exec smoke -d -- firefox), useful for anything long-running
jailbee start/stop/restart <name> [--wait\|--no-wait] Lifecycle: start/restart re-run autostart, and take --wait (run every stage in the foreground, ignoring detach: true) / --no-wait (hand off after the first stage regardless of config), mutually exclusive. stop refuses while a detached autostart run is in flight (--force skips the check and cuts it off); restart refuses too, with no --force — cancel the run first (jailbee autostart cancel)
jailbee autostart status <name> Show how far a container's detached autostart stages have got: one row per step, grouped by stage, plus notes (an interrupted step, or a leftover record to jailbee job clear)
jailbee autostart cancel <name> Stop the worker running a container's detached autostart stages (SIGTERM): it unwinds the stage in flight — interrupts the running step (best-effort, doesn't wait), detaches the stage's mounts, restores the network (compare-and-swap, so a jailbee net run since then stands), and marks the job row failed. Refuses when the worker is already gone, pointing at jailbee job clear
jailbee destroy [<name>] [--all] [--force] [--background] Destroy one container, --all for the whole repo, or no-arg interactive checkbox. Before the usual confirmation, JailBee assesses what would be lost (dirty tree, changed submodule, commits held nowhere else) and, if anything is at risk, shows a summary and a second confirmation defaulting to No; --force skips both prompts and the assessment
jailbee git fetch <name> [-b <branch>] [--as <name>] [--force] [--tags\|--follow-tags\|--no-tags] Fetch into refs/jailbee/<short>/<branch>, transport submodule objects, then point the host branch and every submodule's branch of the same name at the container's state — without switching the working tree. -b picks which branch to read from the container; --as names the host branch written. A diverged host branch is left alone with a warning; --force overwrites it, except when it is the branch currently checked out. --tags/--follow-tags/--no-tags override pull.tags for this run (see Tags). Switch the tree with jailbee branch <branch> afterwards
jailbee git checkout <name> [-b <branch>] [--as <name>] [--confirm\|--no-confirm] [--tags\|--follow-tags\|--no-tags] Fetch + check out the container's branch on the host (ff-only). -b picks which branch to read from the container, --as names the branch written on the host (default: the container branch, or its PR head when set). With one eligible container and no name, confirms first (confirm.auto_target). --tags/--follow-tags/--no-tags override pull.tags for this run.
jailbee git pull [<name>] [--into <b>\|--current] [--ff\|--no-ff] [--checkout] [--cleanup\|--no-cleanup] [--confirm\|--no-confirm] [--tags\|--follow-tags\|--no-tags] Fetch + merge the container's branch into its base branch (alias: jailbee pull). --current merges into the host's checked-out branch instead (mutually exclusive with --into). No name → multi-select picker. With one eligible container and no name, confirms first (confirm.auto_target). --ff/--no-ff override pull.ff (default auto: fast-forward when possible, merge commit otherwise) for this run; --tags/--follow-tags/--no-tags override pull.tags. See Fast-forward policy and Tags.
jailbee git retarget <name> <base> [--merge] Re-point a container's base branch (stacked-PR maintenance). --merge does not honour push.tags — it never sends tags, and there is no flag to change that
jailbee git push [<name>] [--merge\|--rebase\|--plain\|--force] [--ff\|--no-ff] [--from <b>\|--current] [--from-origin\|--from-local] [--fetch\|--no-fetch] [--confirm\|--no-confirm] [--tags\|--follow-tags\|--no-tags] Send a host branch into a container (alias: jailbee push). No name → multi-select picker. By default the host fetches and pushes origin/<source>, not the local branch — a local refs/heads/<base> only advances on git pull (push.push_from / push.autofetch). --from-local sends the host's local branch instead; --current always resolves locally, and --pr pushes refs/jailbee/pr/<N>/head verbatim (so --from-local/--from-origin are rejected with it). With one eligible container and no name, confirms first (confirm.auto_target). --ff/--no-ff pick how --merge merges: by default a fast-forward when the container is already on the pushed branch and a merge commit otherwise, with a prompt when that fast-forward is impossible. --tags/--follow-tags/--no-tags override push.tags (default none), including with --merge/--rebase/--force.
jailbee git push <name> --pr For jailbee new --pr containers, re-fetch the PR head from GitHub and push it in (pull in commits the author pushed since you started). Requires an explicit container name — there is no picker for it. Without --merge/--rebase/--plain the merge/rebase/plain choice follows push.default_action, which is ask: a prompt on a TTY, an error off one. Both dashboards offer it as "Refresh from PR head"
jailbee git merge <source…> --into <target> [--into <target>…] [-b <branch>] [--plain] Merge one container's branch into another without a host checkout — objects travel source → host → target, no host branch, index or superproject working tree is touched (a host sub-repo can still be created, for a submodule born in the source container). Both ends take several containers: every source is merged into every target (repeat --into). --into is never inferred, but either end may be omitted on a TTY and is then asked for — the sources first (a checkbox that merges in listed order), the targets second (a checkbox too); off a TTY both must be given. A container may not be named at both ends: each prompt hides the rows the other end holds, and a typed collision is exit 2 before anything is merged. Several sources are merged into each target one at a time, in order given, stopping at that target's first conflict — the targets after it are still attempted; the summary always names what landed, what stopped it, what remains, and the resume command, and a run with several targets closes with a roll-up of every target's state. Conflicts are resolved inside the target with jailbee shell <target>. Each source that lands prints its own ── Submodules block, read inside the target container. -b is not submodule-safe — the transport enumerates the source's checked-out state, not the branch being read. --plain transports the refs only and reports "transported", not "merged". Alias: jailbee merge
jailbee pr <name> [--ready\|--draft] [--description] [--title <t>] [--body <t>] [--as <name>] [--pr N] [--stacked] [--retarget\|--no-retarget] [--force] [--web] [--no-ai] [--yes] Create a draft PR or update an existing one. Opens a new PR when the container has none yet; when one exists, pushes new commits and optionally regenerates the description (--description) / toggles draft state. When claude.enabled, the new PR's head branch name and description are AI-generated (convention-aware, confirmed on a TTY). --as <name> sets the head name explicitly on a new PR (exit 2 once the container has one — the PR's head is fixed); --force force-pushes a rebased/amended branch with --force-with-lease (requires explicit container name). --no-ai opts out of AI generation entirely (top-level command; hidden alias: jailbee git pr). On a jailbee new --pr container JailBee asks once — an arrow-key menu — what to publish: the container's commits into that PR's head branch, or a new PR based on it (a stacked PR). The answer is remembered; --yes picks the first non-interactively and --stacked the second, and off a TTY one of them is required. After adopting that PR — one JailBee did not create — --force also asks before overwriting the head and the description is never regenerated unless you pass --description/--title/--body. Fork PRs are refused with a manual-push recipe. --stacked opens a PR whose base is the reviewed PR's head: it needs a head branch of its own (--as, or Claude's proposal — publishing under the reviewed head is exit 2), records itself under user.jailbee.stacked_pr* so user.jailbee.pr keeps naming the reviewed PR (and with it jailbee ls's PR column and jailbee git push --pr), and offers to retarget the container's base branch onto that head so AHEAD counts only its own commits (--retarget/--no-retarget; the default asks on a TTY, otherwise prints the command). Refused on a fork PR (its head is not a branch in your origin, so it cannot be a base), on a container that already publishes to a PR's head, and on one never created from a PR. Later runs update the stacked PR without asking, and --open prefers it over the reviewed PR. --stacked with --pr N is exit 2. When a container has no PR but its branch already has an open one, JailBee offers to push to that PR instead of opening a duplicate (same recorded labels and hands-off rules; closed/merged and fork PRs fall through to a new PR, and --as skips the check). --pr N names that PR outright, for the common case where the container's branch is not named like the PR's head branch: same confirmation and same labels, but a closed/merged or fork PR is refused rather than falling through to a new PR, and retargeting from another number asks first. --pr with --as is exit 2.
jailbee git diff <name> [--wt\|--all\|--stat] [--color\|--no-color] Show the diff between a container and the host (alias: jailbee diff). Colour follows stdout; --color forces it on for a consumer that pipes the output into a pager (as jailbee dashboard does), --no-color forces it off
jailbee branch [<branch>] [--container <name>] [--submodules-only] Put the tree on one branch locally — host repo by default, or a named container; no host↔container transport. On the host, a BRANCH argument checks it out in the superproject too, then aligns the submodules to it; --submodules-only leaves the superproject alone (detached HEAD, deliberate mismatch). A container's branch is never switched — there BRANCH is pure submodule placement, and --submodules-only is rejected. jailbee submodule checkout is a hidden deprecated alias
jailbee submodule pr [<name>] [<path>] [--title <t>] [--body <t>] [--base <b>] [--ready\|--draft] [--description] [--as <name>] [--pr N] [--force] [--web] [--no-ai] [-b <branch>] [--yes] [--open] Create or update a GitHub PR in a submodule's own repository from commits made inside it — a separate repo from the superproject, so a separate PR from jailbee pr (one PR per run, independent of it). Off a TTY, without <path>, the submodule ahead of its own base is targeted automatically; several ahead are listed and <path> is required; none ahead is reported as a fact and exits 0. On a TTY, without <path>, a container picker runs first (even with only one container), then a submodule picker offers every submodule — not only the ones ahead of base — instead of erroring on ambiguity; either picker is skipped when its target is unambiguous from the arguments given. A plan block (container/submodule/source/base/remote/action) is then shown and must be confirmed before anything is transported or published; --yes skips that confirmation but not the pickers. The signal is the submodule's own refs/jailbee/base/<super-base> anchor, not the superproject's gitlink diff — commits can show here before the gitlink bump is even committed (reported as information, not an error). Base branch: --base > submodule.<name>.branch declared in .gitmodules (found by descending from repo root, unless .) > the sub-repo's <remote>/HEAD > main. Head branch: --as > Claude's proposal > the branch the commits came from; the chosen head is remembered so a re-run updates the same PR. --branch/-b here selects which branch is read from the submodule, not the superproject branch. --open reads the recorded PR and opens it, requiring <path> when more than one is recorded. On success, if the container also has a superproject PR, JailBee notes the merge order (submodule PR first) as information only. --pr N targets the submodule's existing PR N, resolved against the submodule's own repo and remote
jailbee net strict <name> Switch to the egress allowlist; clears any loose TTL
jailbee net loose <name> [--for <dur>\|--no-revert] Switch to full NAT. --for sets the auto-revert TTL for this switch only (30s, 45m, 4h; max 24h; never = no auto-revert, same as --no-revert). With neither flag on a TTY, JailBee asks; otherwise loose_auto_revert.after applies. See Configuration
jailbee net refresh/status/unregister/install Egress-pool refresh timer + allowlist management. status also lists every egress override on the host
jailbee net egress ls/add/rm/export [<entry>] [<name>] [--repo] Widen a strict allowlist without editing committed config (short alias: jailbee egress …). add/rm default to container scope — the entry lives in that container's own label and dies with it; --repo scopes to every container of the repo on this host (host-local state, not in git) and is pushed by the next jailbee apply, while a container-scoped add/rm takes effect at once. Either way the entry materialises against the container's current network mode: adding to a loose container stores it but changes no ACL until the container returns to strict. Overrides are additive only — rm refuses an entry that exists only in config.yaml and points at the file, but does remove one that is also stored as an override. ls shows every applicable entry with its source; export prints a complete replacement for the config's egress_allow: key — paste it over the whole key, since a second egress_allow: would silently win. See Egress overrides
jailbee snapshot create/restore/ls/delete <name> [tag] Snapshots
jailbee port ls [NAME] List port forwards; with no NAME, every container of the repo (includes forwards added with incus directly, shown as source other)
jailbee port to-container PORT [NAME] [--host-port N] [--proto tcp\|udp] [--host-address IP] [--container-address IP] Make a host service reachable inside the container. PORT is always the container-side port; --host-port names the host side (default: PORT)
jailbee port to-host PORT [NAME] [--host-port N\|auto] [--proto tcp\|udp] [--host-address IP] [--container-address IP] Make a container service reachable on the host. PORT is always the container-side port; --host-port auto picks a free host port not already claimed by another container (stopped ones included)
jailbee port rm HANDLE [NAME] Remove one port forward. HANDLE is a device name, a host_ports name, or a container-side port
jailbee claude ls [-o json] [--fields …] [-g <group>] Every Claude login on this host and which holder each is live in: one row per credential group with the account it holds, per repo keeping its own login, and per parked login. USED BY names the repos and containers reading each holder — container names when no repo resolves to it, which is how a group used only by a claude group use override is discoverable. -g narrows the table to one group
jailbee claude group ls [-o json] [--fields …] The credential groups on this host and what each holds — the same rows as claude ls, narrowed to the groups themselves (no parked logins, no repo keeping its own)
jailbee claude group create <name> Create an empty credential group before anything is assigned to it (set, use and claude use -g create one on demand too)
jailbee claude group rm <name> [--yes] Remove a credential group nothing uses. Refuses while a repo resolves to it, while it is the host default, or while a container has been moved into it; a login it still holds is parked into the host-wide store first, never deleted
jailbee claude group set <name>\|none [--force] / unset [--force] This repo's permanent group, written to global.yaml. Every container follows, and an override the change makes redundant is dropped
jailbee claude group use <name>\|none [<container>] [--force] / reset [<container>] [--force] One container's group, for its lifetime. Naming the repo's own group clears the override instead of writing one
jailbee claude use [<email\|slot>] [-g <group>] Switch this repo's holder to a stored login. Omit the account to pick from a menu of the stored logins (the live one is not offered — it is already active); without a TTY the error names the candidates instead. Holder-wide: every repo sharing the credential group moves with it. A running Claude session adopts the new credential on its next turn — no restart. <email> is enough unless two stored accounts share it, in which case pass the full slot name (<email>[#<org8>][~<disambiguator>] — the ~ part appears when one account has two independent logins stored). -g <group> activates it into that group's holder instead — a group this repo is not a member of, so nothing about this repo's own login changes
jailbee claude park [-g <group>] Store the login in use and leave the holder empty, so the next claude in a container of this holder prompts /login. This is how a new account enters the pool — there is no add, because only a browser login creates a credential. -g parks that group's login instead of this repo's
jailbee claude rm [<email\|slot>] [--yes] Delete a stored login permanently. Omit the account to pick from a menu. Refuses the live one (park it first). JailBee never contacts Anthropic, so a deleted login only comes back through /login
jailbee mount <kind> <name> / jailbee unmount <kind> <name> Optional mounts
jailbee apps ls [<name>] [-o json] [--fields …] [--force] List the GUI apps this repo's containers can launch — builtins (browsers, JetBrains IDE) plus apps: entries, in registry order. Without a container this is config only; name one to add a STATUS column that actually probes each app (present/missing)
jailbee apps run <app> [<args>…] [--container <name>] [--force] Launch a GUI app by name. <app> is required and comes first — see jailbee apps ls; the container is named with --container, not a second positional (three positionals with an optional middle one can't be told apart)
jailbee ide <name> [--app idea\|webstorm] Launch JetBrains IDE. Needs jetbrains.enabled
jailbee chrome <name> [URL] Launch Chrome. Needs browsers.chrome.enabled (or the deprecated top-level chrome.enabled); URL falls back to browsers.chrome.url
jailbee firefox <name> [URL] Launch Firefox. Needs browsers.firefox.enabled; URL falls back to browsers.firefox.url. Firefox defaults to source: image (the host's Firefox is a snap on Ubuntu, so there's nothing useful to mount)
jailbee browser [<name>] [URL] Launch the default browser: browsers.default when set, or the single enabled browser when exactly one is. Otherwise it errors and names what to set
jailbee pool ls/prune [NAME] Inspect or clean per-container cache pool slots (Gradle, Maven, Chrome and Firefox by default — see pooled_caches); omit NAME for every pool. jailbee chrome-pool ls/prune still works as a deprecated alias for jailbee pool ls/prune chrome-profile; Firefox has no such alias — use jailbee pool ls/prune firefox-profile
jailbee base build Build the golden image
jailbee base prune [--all] [--days N] [--yes-to-all] Remove superseded dated golden-image archives (<alias>-YYYY-MM-DD). Lists all candidates and confirms once (a single batch confirmation, not per-archive); the live base image is always kept; in-use archives are skipped (batch continues). --all prunes archives for every registered repo, not just the current one; --days N only removes archives older than N days (default: all dated archives are candidates); --yes-to-all skips the confirmation prompt
jailbee base usage [--all] Show disk usage of golden base images: each live base and dated archive with its size, per-repo subtotals, a prunable (archives-only) figure, and a grand total. --all includes every registered repo, not just the current one
jailbee registry up [--recreate] / down / status / verify [--purge] Docker registry mirror control. up repairs a half-provisioned mirror in place (reinstalls the proxy when its Quadlet unit is missing, and once more if the service never starts); --recreate deletes the container and rebuilds it from the image, preserving the host-side cache and CA. verify hashes every cache entry stored under a digest against that digest — a corrupt one makes every pull that needs it fail with unexpected commit digest — lists mismatches and offers to remove them (--purge: without asking); the next pull fetches a removed entry from upstream again
jailbee setup [--yes] [--status] [--only STEP] [--shell SHELL] Post-install steps for this machine: shell completions (jailbee and jb), the jailbee-net-refresh user timer, and the bundled Claude skills in ~/.claude/skills. Interactive by default and idempotent — re-run after upgrading. --status reports what is in place without installing anything. Needs no repo config
jailbee doctor Diagnostics
jailbee dismiss [KEYS…] [--all] [--clear] Mark repeating advisory warnings read, so they stop appearing on jailbee ls / new / shell. Keys are base-build and apply (an owed action — see Troubleshooting), update (a newer release on PyPI — see update_check) and legacy-config-dir / legacy-chrome-block (a deprecated config spelling). With no arguments, lists what applies here and what has been dismissed. An owed action returns when a later release adds a new reason for it — upgrading alone does not bring it back; a dismissed update returns when a release newer than the dismissed one appears; a deprecation stays dismissed until the config changes. jailbee doctor reports them either way, marked with when they were dismissed, so nothing is ever hidden from it. KEY@scope targets one of several files raising the same notice; --clear undoes a dismissal
jailbee disk-usage Disk usage breakdown
jailbee prune Interactive cleanup of stale containers
jailbee config show/validate/init Configuration. show's effective layer includes an agents: section with every configured agent fully resolved (preset fields included) — see Generic agent support
jailbee config edit [--global] [--write patch\|regenerate] Interactive editor for either config layer, with each field's own help text, its origin (default/global/repo) and a validated, backed-up save. --global edits ~/.config/jailbee/global.yaml; --write overrides config_edit.write_policy for one run. Structured lists (host_mounts, agents, autostart steps, …) open a drill-down screen — n new, x delete, J/K reorder, Enter to open an entry. github.api_tokens can be set but is never displayed
jailbee version / jailbee --version Print the JailBee version

Top-level app promotion

An apps: entry with top_level: true also runs as a bare jailbee <name> [args…] — equivalent to jailbee apps run <name> [args…], just without the apps run. Everything after the name is passed through unchanged, so another container is named exactly the way apps run names one: jailbee <name> --container <container> [args…], and an argument that starts with a dash needs a -- separator (jailbee <name> -- --some-flag). A bare jailbee <name> <container> does not work — apps run takes the container as an option, so the name is appended to the app's own arguments and the app starts in the default container instead. A built-in command of the same name always wins, and jailbee config validate reports the collision as a config error (it is checked in validate_runtime, so only that command reports it — jailbee doctor and ordinary commands do not) rather than the app silently never being reachable that way. See apps.

jailbee gui / jailbee dashboard --gui

The graphical (Qt) counterpart to the terminal dashboard — the same live, cross-repo container view with per-container actions via right-click / popup menus. Requires the optional PySide6 extra:

uv tool install 'jailbee[gui]'     # or: pipx install 'jailbee[gui]'

(from a checkout of the JailBee repo: make install, or uv tool install -e '.[gui]')

By default the GUI detaches to the background: the command prints a "Launched jailbee dashboard GUI in the background" message and returns immediately, with the window's stdout/stderr logged to /tmp/jailbee-gui.log (useful if the window fails to appear — e.g. missing PySide6 platform plugins). Pass --foreground to run it attached to the current terminal instead (blocks until the window closes; errors surface directly).

Interactive actions (shell, tmux) open in a host terminal emulator. Set $JAILBEE_TERMINAL to force a specific emulator; otherwise JailBee auto-detects one (x-terminal-emulator, ptyxis, gnome-terminal, konsole, foot, alacritty, kitty, xterm). IDE, Chrome and Firefox launches reuse the same jailbee ide / jailbee chrome / jailbee firefox behaviour; the action menu also lists every other apps: entry as a "Launch <name>" item — dispatched as jailbee apps run <name> --container <container> regardless of top_level, so it launches in the highlighted row's own container whether or not the entry is promoted to a top-level command.

The commands that exist for the text they print — pr, git push, git pull, git diff, job log — get no terminal emulator: they run inside the GUI and stream their output into a JailBee window with Stop and Copy buttons and the exit code on its status line. The window is non-modal, so the dashboard keeps refreshing behind it and several commands can be watched at once. Stop matters for job log on a live job, which follows the worker's log until it is stopped.

Because that child process has no stdin, whatever the CLI would prompt for is collected in a dialog first and passed as a flag — and only where the CLI would ask: git push's merge/rebase/plain choice when the repo's push.default_action is ask, its source when push.default_source is ask (see Configuration), pr's draft/ready, description and existing-PR-head choices, and a confirmation for git pull, which merges into the host's own branch. Cancelling a dialog dispatches nothing.

Options mirror the TUI: --interval, --git-interval, --no-git, plus --foreground (GUI-only).

Layouts: Table vs Cards

A View menu switches the container list between two layouts:

  • Table — the original wide, sortable columns view.
  • Cards — a width-adaptive card grid; cards re-wrap to fill the window (one column when narrow, several side by side when wide).

Both layouts share the same right-click action menu and selection behaviour. Fresh installs (no prior GUI session) open in Cards.

Persisted state

Between sessions the GUI remembers, per-machine, in the same SQLite state DB used for other JailBee state (state.sqlite):

  • the selected layout (Table or Cards),
  • the table layout's column widths and order,
  • the refresh cadence and whether auto-refresh is paused (set via the Refresh menu).

Not persisted: window size and position — that's left to the window manager.

--interval precedence when the GUI starts: an explicit --interval/-i flag wins, otherwise the persisted refresh cadence from the last session is used, otherwise the default of 3s. --git-interval is never persisted — pass it each time it should differ from the default.


For full flag-level detail without jailbee <cmd> --help, the jailbee-usage skill (docs/skills/jailbee-usage/) and its references/commands.md document every command and option.