# How Nodeterm Ensures Terminal Session Continuity After Application Restart

> Discover how Nodeterm ensures terminal session continuity after application restarts. Learn about persistent tmux sessions and scrollback history preservation for uninterrupted workflow.

- Repository: [eneskirca/nodeterm](https://github.com/eneskirca/nodeterm)
- Tags: internals
- Published: 2026-08-25

---

**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`](https://github.com/eneskirca/nodeterm/blob/main/src/core/pty-manager.ts), the `spawnNew()` method executes:

```bash
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`](https://github.com/eneskirca/nodeterm/blob/main/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`](https://github.com/eneskirca/nodeterm/blob/main/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.

```ts
// 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`](https://github.com/eneskirca/nodeterm/blob/main/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`](https://github.com/eneskirca/nodeterm/blob/main/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.

```tsx
// 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:

```tsx
// 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`](https://github.com/eneskirca/nodeterm/blob/main/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`](https://github.com/eneskirca/nodeterm/blob/main/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`](https://github.com/eneskirca/nodeterm/blob/main/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`](https://github.com/eneskirca/nodeterm/blob/main/src/core/scrollback-store.ts) and persists across system reboots, ensuring that terminal history remains available for cold restarts.