All features

Two named slots, canary and dev

Try the real interface

Explore this workspace.

Real Torbie UI · mock sessions
Tab bar
Loading Torbie…
Technical background

One script cuts a frozen, self-contained copy of the fork into a slot that runs beside your real Tabby: its own portable profile, shared plugins, no global hotkey and no MCP port to fight over. Exactly two slots — canary is disposable and every build replaces it; dev changes only by promoting the canary you actually tried.

The problem

Testing a change means running a build beside the Tabby holding your live sessions. Doing that from a checkout means the two fight over the global hotkey, the MCP port and the config directory — and a build cut from a moving tree cannot be trusted to still be the thing you tested.

How it works

scripts/make-slot.mjs builds a frozen, self-contained copy into ~\Tabby\builds\: its own portable data\, plugins shared through a junction, app files marked read-only so a slot cannot drift after it is cut. There are exactly two — canary is disposable and every build replaces it; dev is the one you work in and changes only by promoting the canary you actually tried.

Try it
  1. node scripts/make-slot.mjs — build and install canary.
  2. Use it. When it is good: node scripts/make-slot.mjs --promote — copy canary into dev.
  3. --dry-run --skip-build prints what it would do, including which profile it would seed from.
Details
  • Promotion copies the canary that was built and tried, never a fresh compile. Otherwise "promote what I verified" would quietly mean "build something new and call it verified". Dev's BUILD-INFO.txt is canary's with a Promoted: line, so dev can never claim a commit that was not in its binaries.
  • A slot that is running is never replaced, and the check is on that slot's own path rather than "any Tabby" — the point of two slots is that the other one keeps running while you rebuild this one.
  • Rebuilding a slot keeps its data\. A genuinely new slot seeds from the other slot, and from the installed app's profile only when there is no other slot at all. The choice is printed.
  • The seeded profile drops the global toggle hotkey and blacklists the MCP server, because a slot runs beside your Tabby: otherwise whichever instance starts first takes both and the other silently half-works.
  • Anything under ~\Tabby\builds\ that is neither slot is pruned on every run — unless it is running, in which case it is reported and left. That is what makes "only ever two" structural rather than a habit.
What this does not claim
  • The first version of freeze() froze data\config.yaml too, and a read-only config file makes a slot lose every settings change in silence: the config write is an atomic rename, which is EPERM over a read-only file on Windows, so the save throws before the change event fires. Nothing persists, and nothing driven by that event re-applies either — so theme, spaciness and docking appear to do nothing at all while you are still in the window. freeze() now skips data by name and the script asserts the config is writable before reporting success.
  • The naming scheme was replaced. Slots used to be <version>-<MMDD>-<HHmm>-<sha> directories, one per build, which accumulated until somebody noticed the disk — and every slot on the machine at the time was stale enough to hang, so what piled up was three copies of a trap.
  • cpSync carries the read-only bit, so promoting a frozen canary lands frozen files in dev and the very next write fails EPERM. Attributes are cleared after the copy as well as before it.
Source commits
BuildsAdded 2026-08-1012 files+850 / −155 lines