All features

A pane comes back running what it was running

Try the real interface

Explore this workspace.

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

Upstream restores the furniture — the tabs, the splits, the profiles, a picture of what was on screen — but every pane comes back as a fresh shell, so the agent you had a two-hour conversation with and the multiplexer holding six sessions are simply not running any more. Each pane is asked what it is running, the answer is persisted with the layout, and it is typed back into the restored pane.

The problem

Upstream restores the furniture — the tabs, the splits, the profiles, and via the serialized scrollback a picture of what was on screen. Every pane still comes back as a fresh shell, so the agent you had a two-hour conversation with, the multiplexer holding six sessions and the dev server are all simply not running any more. Restoring the furniture is not restoring the work.

How it works

Each pane is asked what it is running, the answer is persisted alongside the layout, and on the next start it is typed back into the restored pane. A native pane is read from the process tree — the shallowest non-shell descendant of the pane's own shell, not the deepest, because an agent spawns a child per MCP server. A WSL pane cannot be read that way at all, so tabby-local now mints a TABBY_SESSION per pane and appends it to WSLENV, and one probe per distro greps every /proc/*/environ at once.

Try it
  1. Turn on Restore tabs under Settings → Startup — resume rides on the persisted layout.
  2. Leave resume.agents and resume.multiplexers on. Anything else goes in resume.extraPrograms by name.
  3. Open a pane and start something: an agent, or tmux new-session -s demo.
  4. Close the window, or kill it outright.
  5. Reopen. The pane comes back on its own profile, in its own directory, running what it was running.
Settings
  • resume.agents: true

    Reopen a known agent's conversation, keeping the options it was launched with.

  • resume.multiplexers: true

    Reattach to shefrd, herdr, tmux, screen or zellij.

  • resume.extraPrograms: []

    Extra program names, re-run exactly as they were found.

  • resume.excludedPrograms: []

    Never resume these. Beats every setting above.

  • resume.notification: 'toast'

    silent, toast, or confirm — which lists what it would do and waits.

  • resume.inputDelayMs: 1200

    How long a restored pane's shell gets to draw a prompt before the command is typed.

  • resume.refreshIntervalSec: 30

    How often each pane is asked what it is running — i.e. how stale a recorded command can be.

  • resume.wslProbeTimeoutMs: 5000

    How long a distro gets to answer before its panes go unmeasured.

Details
  • Typed into the pane, never launched as it. Putting the command in the profile's command line would make it the pane's root process, so the pane would close the moment the program exited. The Enter goes as its own write — many TUIs read one write containing text and newline as a bulk paste and never submit it.
  • tpgid describes the terminal, not the process. Every process sharing a controlling terminal reports the same value, so "the topmost process's tpgid" is not that process's opinion about its children. The port read it the first way and reported nothing at all for a pane with anything between it and its shell. The rule is now pid === pgrp === tpgid, with a parent inside the pane.
  • One wsl.exe probe per distro, never per pane. The obvious loop reads each /proc/*/environ and forks four helpers per process, which on this machine's 1531-process distro measured 3.5s against about 250ms for a single grep.
  • A restored pane does not start its shell until it is first rendered, and only the tab that ends up selected is rendered at startup. The first version gave up after ten seconds and every restored pane but the active one silently lost its resume — measured, two panes, hours later. The wait now has no deadline and ends when the tab does.
  • "Open in new window" is excluded by identity, not by heuristic. That flow reuses the running PTY, so the pane's agent never stopped.
  • It rests on one new generic extension point in tabby-core, an add-only file: TabRecoveryAugmentor runs for every recovery token whatever its type, so a plugin can persist something about a tab without owning that tab or editing the provider that does.
  • Nothing on the save path. Measured live: augment 0.002–0.010 ms per tab, saveTabs under 0.01 ms, worst event-loop gap during a full capture 11 ms — against the 250 ms the diagnostics call a stall.
What this does not claim
  • A recorded command is up to one refreshIntervalSec stale. There is no flush-before-quit seam to hang a probe on: upstream's own closeWindow disables tab recovery before its final save, so that save does nothing. Same guarantee Tabby already gives the scrollback saved beside it.
  • Only agents whose resume syntax is actually known are in the table. Guessing a flag produces a command that fails at restore, which is worse than getting a shell — anything unlisted can still be named in resume.extraPrograms.
  • A pane that reopens an agent conversation does not repaint its scrollback. The agent redraws its own history and both would show the same transcript twice.
  • Multiplexer-owned processes are skipped on purpose: they belong to the daemon, which restores them itself.
In upstream Tabby

Restoring the layout and the buffer contents is upstream's. Restoring the running process is not, in Tabby or in Windows Terminal — Microsoft closed the equivalent thread with "restoring the actual state of the running executable might be impossible" and stopped at the text.

Source commits
SessionsAdded 2026-09-0629 files+3,487 / −9 lines