# PtyCreateResult.fresh in Nodeterm: The Key to Cold Restore and Scrollback Replay

> Discover how PtyCreateResult.fresh enables Nodeterm's cold restore by differentiating new sessions from existing ones. Essential for seamless terminal state recovery and scrollback replay.

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

---

**`PtyCreateResult.fresh` is a boolean flag that indicates whether a tmux session was newly created (`true`) or already existed (`false`), determining whether Nodeterm must replay saved scrollback history to restore terminal state during a cold restore.**

Nodeterm is an open-source terminal emulator that maintains persistent sessions through tmux. When the application initializes a PTY (pseudo-terminal) session via `createPty()`, it returns a `PtyCreateResult` object defined in [`src/shared/types.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/shared/types.ts) (lines 148-170). The `fresh` property within this result serves as the critical decision point for whether the terminal performs a **cold restore** with scrollback replay or a **warm attach** to an existing session.

## Understanding the Fresh Flag in PtyCreateResult

In the type definitions located at [`src/shared/types.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/shared/types.ts), the `PtyCreateResult` interface includes the `fresh: boolean` field. This property communicates the state of the tmux session backend to the renderer process.

- **When `fresh` is `true`**: The tmux server did not have an existing session with the requested ID. Nodeterm created a new tmux session from scratch, meaning the terminal screen starts blank unless historical output is restored from disk.
- **When `fresh` is `false`**: The session already existed in the tmux server. This occurs when another client is connected, or the session survived a previous disconnect.

This distinction directly impacts how the terminal UI initializes the xterm instance and whether it loads historical scrollback data from `<userData>/terminal-scrollback/`.

## Cold Restore vs. Warm Attach Behavior

The renderer uses the `fresh` flag to choose between two distinct initialization paths. The behavior differs significantly depending on whether the session is truly new or being reused.

### Warm Attach (fresh: false)

When `fresh` is `false`, the terminal connects to an already-running tmux session. In this scenario:

- The **tmux server retains the full scrollback history** and active screen buffer.
- The renderer simply attaches the xterm to the live PTY stream via `attachPtyStream()`.
- **No scrollback replay occurs** because tmux itself redraws the screen with existing content when the client connects.

This path applies to joiner clients (co-attached sessions) or reconnections where the tmux server never terminated. A joiner client always receives `fresh: false` and therefore does not redo the replay.

### Cold Restore (fresh: true)

When `fresh` is `true`, indicating a cold start (tmux server died or first-time launch):

- The application must **re-populate the terminal's scrollback** to provide seamless continuity.
- Nodeterm loads a previously saved snapshot from `<userData>/terminal-scrollback/<sessionId>.snapshot` via [`src/core/scrollback-store.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/core/scrollback-store.ts).
- The renderer injects this historical output into the freshly created xterm **before any live output arrives**.
- This gives users the appearance of an uninterrupted session despite the tmux process being recreated.

The original client that experiences a cold start receives `fresh: true` and triggers this restoration logic, while joiners skip it.

## Implementation Across the Codebase

The `fresh` flag flows through three critical components that coordinate the restore process:

- **[`src/core/pty-manager.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/core/pty-manager.ts)**: Contains the core logic that spawns PTY sessions, checks for existing tmux sessions, and sets the `fresh` boolean accordingly in the returned `PtyCreateResult`.
- **[`src/core/scrollback-store.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/core/scrollback-store.ts)**: Persists terminal output to disk during normal operation and retrieves snapshots during cold restore when requested by the renderer.
- **[`src/renderer/nodes/TerminalNode.tsx`](https://github.com/eneskirca/nodeterm/blob/main/src/renderer/nodes/TerminalNode.tsx)**: Consumes the `PtyCreateResult` and implements the conditional logic to either replay scrollback (when `fresh` is `true`) or attach directly to the live stream (when `fresh` is `false`).

## Practical Implementation Example

The following pattern demonstrates how to handle the `fresh` flag when initializing a terminal in Nodeterm:

```typescript
import { createPty } from '@shared/pty-manager';
import { PtyCreateResult } from '@shared/types';
import fs from 'fs/promises';
import path from 'path';

async function launchTerminal(sessionId: string, userDataDir: string) {
  const result: PtyCreateResult = await createPty({ sessionId });

  if (result.fresh) {
    // Cold restore: replay saved scrollback into the new xterm
    const scrollbackPath = path.join(
      userDataDir, 
      'terminal-scrollback', 
      `${sessionId}.snapshot`
    );
    const scrollback = await fs.readFile(scallbackPath, 'utf8');
    xterm.write(scrollback);
  } else {
    // Warm attach: tmux redraws the screen; attach to live stream only
    attachPtyStream(result.sessionId);
  }
}

```

In this implementation, the `fresh` check prevents unnecessary disk I/O during warm attaches while ensuring historical context is available during cold starts. The scrollback is injected via `xterm.write()` before the live PTY stream begins pumping data.

## Summary

- **`PtyCreateResult.fresh`** signals whether a tmux session was created anew (`true`) or reused (`false`) in [`src/shared/types.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/shared/types.ts).
- **Cold restore** (`fresh: true`) requires loading scrollback snapshots from `<userData>/terminal-scrollback/` via [`src/core/scrollback-store.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/core/scrollback-store.ts) to restore terminal history.
- **Warm attach** (`fresh: false`) skips scrollback replay because the existing tmux session maintains the screen buffer and handles redraws automatically.
- Joiner clients always receive `fresh: false`, while the original client experiencing a cold start receives `fresh: true` and restores the terminal history.

## Frequently Asked Questions

### What triggers a cold restore versus a warm attach?

A cold restore occurs when the tmux server has died, been killed, or is starting for the first time, forcing Nodeterm to create a fresh session (`fresh: true`). A warm attach happens when connecting to an existing tmux session that survived the disconnect or when a second client joins the same session (`fresh: false`).

### Where does Nodeterm store scrollback data for cold restores?

Scrollback snapshots are stored in the user's data directory under `terminal-scrollback/` as individual snapshot files (e.g., `<sessionId>.snapshot`), managed by [`src/core/scrollback-store.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/core/scrollback-store.ts). These files are read during cold restore and written continuously during normal operation.

### Why does the renderer skip scrollback replay during warm attach?

During a warm attach, the tmux server still holds the complete scrollback history and screen state. When the renderer connects, tmux automatically redraws the entire screen content, making manual scrollback injection redundant and potentially conflicting with the live session state.

### How does PtyCreateResult.fresh affect performance?

When `fresh` is `true`, the renderer performs file system I/O to load scrollback history, introducing a brief initialization delay. When `fresh` is `false`, the terminal connects immediately to the live stream without disk access, resulting in faster attachment times and lower resource usage.