How Nodeterm Ensures Terminal Session Continuity After Application Restart

Nodeterm maintains terminal session continuity by running all terminal nodes on top of persistent tmux sessions that survive Electron process termination, then re-attaches to these sessions on restart while preserving scrollback history through periodic disk snapshots.

Nodeterm is an Electron-based terminal workspace that solves the persistence problem inherent to most terminal emulators. Unlike standard PTY implementations that die when the renderer process exits, Nodeterm leverages tmux as an external session server to keep shell processes and AI agents alive across application restarts, accidental crashes, and even full system reboots.

The Tmux-Based Persistence Architecture

At the core of Nodeterm's continuity strategy is the decoupling of the terminal process from the Electron application lifecycle. While the UI runs inside an Electron renderer process, the actual shell or AI-agent executes within a tmux session that operates as an independent server process.

This architecture ensures that shell processes keep running even when the user quits the application completely. When Nodeterm launches, it does not create new shell instances blindly; instead, it queries the tmux server to determine whether a session already exists for a given node ID.

Warm Attach vs. Cold Restore

The system distinguishes between two resumption scenarios based on the state of the underlying tmux server and the fresh flag returned by PtyManager.spawnNew().

Detecting Existing Tmux Sessions

Before spawning any new terminal, Nodeterm checks for existing sessions using tmux's native introspection capabilities. In src/core/pty-manager.ts, the spawnNew() method executes:

tmux has-session -t nt-<nodeId>

If the session exists, the returned PtyCreateResult object contains fresh: false, signaling a warm attach scenario. If the tmux server is unreachable or the session is absent, fresh is set to true, triggering a cold restore pathway.

Warm Attach on Application Restart

When fresh === false, Nodeterm performs a warm attachment to the existing tmux pane. The renderer does not inject any saved scrollback because tmux automatically redraws the current screen content upon attachment. The existing PTY client connects via transport.create(), and the terminal UI displays the live pane instantly with zero data loss.

This mechanism handles the most common case: a user quits Nodeterm and relaunches it moments later. The shell history, running processes, and current working directory remain exactly as they were left.

Cold Restore After System Reboot

If the tmux server has terminated—due to a system reboot, tmux server crash, or first-time launch—the cold restore protocol activates. This three-step process ensures that no session starts completely empty:

  1. Scrollback Recovery: The system reads the last saved snapshot from <userData>/terminal-scrollback/ using the ScrollbackStore utility.
  2. UI Seeding: In src/renderer/nodes/TerminalNode.tsx, the component watches the fresh flag. For cold restores, it calls pty.readScrollback() and injects the saved output into the xterm instance with a "session restored" separator before mounting.
  3. Agent Resumption: If the node represents an AI agent, Nodeterm re-issues the original launch command (such as claude --resume <sessionId> or codex resume) so the agent picks up its conversation history where it left off.

Scrollback Preservation Mechanism

To prevent data loss during cold starts, Nodeterm implements a proactive snapshotting system that periodically persists terminal buffer contents to disk.

Periodic Snapshots

The ScrollbackStore in src/core/scrollback-store.ts manages a background task that captures the tmux pane output at intervals defined by SCROLLBACK_SNAPSHOT_MS. These binary snapshots are written to the user's data directory under terminal-scrollback/<nodeId>.bin, ensuring that even if the tmux server is killed, the recent terminal history survives.

// Manual trigger to force a scrollback snapshot (useful for scripts)
import { captureScrollback } from '@/core/scrollback-store';
await captureScrollback('nt-1234abcd');   // writes <userData>/terminal-scrollback/nt-1234abcd.bin

UI Seeding on Restore

When TerminalNode.tsx detects a cold restore (fresh === true), it bypasses the warm-attach optimization and instead seeds the xterm instance with the disk-persisted scrollback. This gives users immediate context about their previous session state, even though the underlying process has restarted.

AI Agent Resumption

Nodeterm extends session continuity to AI coding agents through a specialized resumption protocol defined in src/shared/agents/config.ts. The system maintains a list of RESUMABLE_AGENTS and their specific CLI resume semantics.

When a terminal node carries an agentId property and undergoes a cold restore, the renderer automatically calls resumeCommand(agentId, sessionId) after mounting. This injects the appropriate resume CLI—such as claude --resume <id> for Anthropic's Claude or codex resume for OpenAI's Codex—ensuring that the AI agent reloads its previous conversation context and file state without manual intervention.

// For an AI-agent node, the resume command is injected automatically on cold-restore.
<TerminalNode
  data={{
    id: 'nt-agent-01',
    agentId: 'claude',
    // …other node data
  }}
/>

Implementation Example

Creating a terminal node implicitly establishes the tmux session infrastructure that enables continuity. The node ID becomes the tmux session name, allowing the system to locate and re-attach to it later:

// Example: creating a terminal node (the node id becomes the tmux session name)
import { createTerminalNode } from '@/renderer/state/workspace';
const nodeId = 'nt-1234abcd';
workspace.addNode(createTerminalNode({ id: nodeId, cwd: '/my/project' }));

// After quitting the app, restarting will trigger a warm-attach.
// No extra code is needed – the pty manager checks tmux automatically.

Summary

  • Tmux as External Server: Terminal sessions run outside the Electron process in tmux, ensuring survival across application quits and crashes.
  • Warm Attach Protocol: On restart, PtyManager.spawnNew() detects existing sessions via tmux has-session and re-attaches instantly without scrollback injection.
  • Cold Restore Mechanism: When tmux is unavailable, ScrollbackStore replays saved snapshots from disk, and TerminalNode.tsx seeds the UI with historical output.
  • AI Agent Persistence: The system automatically resumes supported agents using CLI-specific resume commands defined in src/shared/agents/config.ts.
  • Zero-Configuration Continuity: Users experience seamless session persistence without manual save or restore commands.

Frequently Asked Questions

How does nodeterm keep terminal sessions alive when the application crashes?

Nodeterm delegates process management to tmux, which runs as an independent system service. Because tmux sessions exist outside the Electron renderer process, they persist even if nodeterm crashes or is force-quit. When the app restarts, it simply re-attaches to these existing sessions rather than creating new ones.

What happens to my terminal scrollback if I restart my computer?

Nodeterm periodically snapshots scrollback content to disk using ScrollbackStore at intervals defined by SCROLLBACK_SNAPSHOT_MS. Upon detecting a cold start (when the tmux server is gone), the application loads the latest snapshot from <userData>/terminal-scrollback/ and injects it into the terminal UI before connecting to the new shell instance.

Can nodeterm resume AI coding agents like Claude or Codex after a restart?

Yes. Nodeterm maintains a registry of resumable agents in src/shared/agents/config.ts. When a node with a valid agentId undergoes a cold restore, the system automatically executes the appropriate resume command—such as claude --resume <sessionId> or codex resume—after the terminal mounts, restoring the agent's conversation context.

Where does nodeterm store the scrollback snapshots?

Scrollback snapshots are stored as binary files in the user's application data directory under terminal-scrollback/<nodeId>.bin. This location is managed by src/core/scrollback-store.ts and persists across system reboots, ensuring that terminal history remains available for cold restarts.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →