Warm Reattach vs Cold Restore in Nodeterm Tmux Sessions: A Technical Deep Dive
Warm reattach connects to an existing tmux session without replaying data, while cold restore recreates the tmux session and replays persisted scrollback after a host reboot.
Nodeterm persists every terminal inside a named tmux session (nt-<nodeId>) to survive application restarts and system crashes. When the Electron renderer reconnects, it must determine whether the underlying tmux server survived or was killed by a reboot, choosing between a warm reattach or a cold restore strategy.
How Nodeterm Manages Tmux Session Persistence
Nodeterm wraps every terminal node in a persistent tmux session identified by the pattern nt-<nodeId>. This architecture ensures that terminal processes survive even when the Electron application is closed. However, when the renderer restarts, the code must detect whether the tmux session is still alive or was destroyed by a system reboot.
Warm Reattach: Attaching to Live Tmux Sessions
A warm reattach occurs when the tmux session survived the application restart and remains active on the host. In this scenario, the new xterm client simply attaches to the existing session, and tmux immediately redraws the pane using its internal scrollback buffer.
According to the source code in src/renderer/terminal/terminal-config.ts, the attachReplay function returns warm-attach when the session exists (lines 555-557). Subsequently, seedPaint resolves to none (lines 80-94), meaning the renderer writes no initial data into the xterm because tmux handles all drawing independently.
Cold Restore: Recovering After System Reboots
A cold restore happens when the tmux server was killed—typically after a machine reboot—and the session no longer exists. Nodeterm must create a fresh tmux session and manually replay the persisted scrollback that was saved before the shutdown, including a "session restored" separator.
In src/renderer/terminal/terminal-config.ts, the attachReplay function returns cold-snapshot when the node is not a parked terminal and has no initialCommand. The seedPaint helper then selects snapshot (lines 90-92), writing the saved scrollback data directly into the xterm buffer so users see their previous output.
The Decision Logic: Code Implementation
The distinction between warm and cold recovery is implemented in the terminal spawn continuation. The system uses two key helper functions to classify the attachment type and determine the seeding strategy.
// Decide which seeding strategy to use when a terminal node is (re)created.
const replay = attachReplay({
parked: false, // not a parked terminal – we need a fresh buffer
fresh: !sessionExists, // true if tmux died (e.g. after a reboot)
hasInitialCommand: false // no one‑shot launch command
});
// → 'warm-attach' (tmux still alive) or 'cold‑snapshot' (tmux died)
// Choose what to actually write into the xterm.
const paint = seedPaint({
replay, // result from above
superseded: false, // no `pty:resync` arrived while we were waiting
snapshot: savedScrollback, // string from `<userData>/terminal-scrollback/…`
screen: undefined // only used for co‑attach joiners
});
// → 'none' (warm‑attach) or 'snapshot' (cold‑restore)
These helpers are invoked in src/renderer/nodes/TerminalNode.tsx during the PTY creation flow. The fresh boolean originates in src/core/pty-manager.ts via PtyCreateResult.fresh, documented in docs/ios-protocol-migration.md as indicating a cold start (true) versus a warm reattach (false).
Summary
- Warm reattach leverages existing tmux sessions where
freshis false, requiring no scrollback replay because tmux redraws the interface automatically. - Cold restore handles post-reboot scenarios where tmux died, requiring session recreation and replay of persisted scrollback via the
snapshotseeding strategy. - The classification logic resides in
src/renderer/terminal/terminal-config.ts, specifically within theattachReplayandseedPaintfunctions. - Unit tests in
src/core/pty-single-user.test.tsvalidate both scenarios using thefreshflag.
Frequently Asked Questions
What triggers a cold restore instead of a warm reattach?
A cold restore is triggered when the tmux server no longer exists, typically after a system reboot. The fresh flag in PtyCreateResult evaluates to true, causing attachReplay to return cold-snapshot and prompting Nodeterm to replay saved scrollback into the new terminal session.
Where is the scrollback data stored during a cold restore?
Nodeterm persists scrollback data to the user's local storage at <userData>/terminal-scrollback/ before the application closes. During a cold restore, this snapshot is retrieved and written into the xterm buffer via the seedPaint function with the snapshot strategy.
Does warm reattach preserve scrollback history?
Yes. During a warm reattach, the tmux session remains alive and retains its internal scrollback buffer. The seedPaint function returns none, meaning Nodeterm injects no external data, and users continue scrolling through tmux's native history using the mouse wheel or keyboard shortcuts.
How does the code differentiate between parked terminals and regular sessions?
The attachReplay function checks the parked parameter to distinguish between parked terminals (which have special handling) and active sessions. Non-parked terminals with no initialCommand and a fresh state of true are classified as cold-snapshot, while existing sessions attach via warm-attach.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →