# How Nodeterm Implements Session ID Minting for Resumable Agent Sessions

> Discover how nodeterm implements session ID minting for resumable agent sessions. Learn how Nodeterm uses uuid to create unique session IDs for seamless resumption across restarts.

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

---

**Nodeterm mints a unique session ID using `uuid()` only during the initial creation of a Claude agent node when the underlying CLI advertises `--session-id` support, persisting this identifier in the node state to enable seamless session resumption across restarts.**

The `eneskirca/nodeterm` project enables persistent agent sessions by implementing a sophisticated **session ID minting** system that bridges the gap between the Electron-based UI and CLI-based AI agents. This mechanism ensures that agents like Claude can resume interrupted conversations after the application restarts or the terminal node is reopened. Understanding how nodeterm generates, stores, and retrieves these identifiers requires examining the capability detection logic, workspace state management, and launch sequence coordination.

## Understanding Session ID Capability Detection

Before minting any identifiers, nodeterm verifies that the target agent CLI actually supports session resumption. This capability check prevents incompatible flag injection and ensures backward compatibility.

### The SESSION_ID_CAPABLE Flag

In [`src/shared/agents/config.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/shared/agents/config.ts), the system defines which agents can handle session IDs. Lines 281-285 declare the `SESSION_ID_CAPABLE` constant and the `mintsSessionId(id)` helper function, which returns `true` only for Claude-based agents:

```typescript
// src/shared/agents/config.ts (lines 281-285)
export const SESSION_ID_CAPABLE = ['claude'];
export const mintsSessionId = (id: string) => SESSION_ID_CAPABLE.includes(id);

```

This strict whitelist ensures that session IDs are only generated for agents that explicitly advertise resumption support.

### Caching CLI Capabilities

The capability probe `claudeFlagSupported` executes once and caches the result in the core process, exposing it through `window.nodeTerminal.claude.cliCaps()`. This cached value determines whether the workspace state manager should generate a UUID during node creation.

## How Nodeterm Mints New Session IDs

Session ID generation occurs within the workspace state initialization logic in [`src/renderer/state/workspace.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/renderer/state/workspace.ts). When constructing a new agent node, the system checks the cached capability flag before minting.

Around line 575, the code evaluates whether to generate a fresh identifier:

```typescript
// src/renderer/state/workspace.ts (approx. line 575)
const mintedSessionId = sessionIdFlagSupported ? uuid() : undefined;

// The minted ID is stored on the node so it survives reloads
{
  // ... other node properties
  sessionId: mintedSessionId,
}

// Later the node data is enriched:
...(mintedSessionId ? { agentSessionId: mintedSessionId } : {}),

```

The `uuid()` function generates a standard v4 UUID (e.g., `12f3e8d4-a1b2-4c3d-9e5f-6b7c8d9e0f12`), which persists in the node's data structure. This identifier remains stable across application restarts, serving as the anchor for session resumption.

## Injecting the Session ID into the Launch Command

After minting, the session ID must reach the CLI process. The launch sequence in [`src/shared/agents/launch.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/shared/agents/launch.ts) handles this injection dynamically.

Around lines 179-182, the code constructs the final command arguments:

```typescript
// src/shared/agents/launch.ts (lines 179-182)
if (inputs.sessionId && mintsSessionId(capId) && inputs.sessionIdFlagSupported) {
  return withAgentModel(
    withSessionId(withMode, capId, inputs.sessionId),
    capId,
    inputs.model
  );
}

```

The `withSessionId` utility appends the `--session-id` flag (or equivalent syntax for the specific agent) to the CLI invocation. This ensures the external agent process receives the persistent identifier, allowing it to associate its internal state with the specific nodeterm node.

## Resuming Sessions with Live Hook IDs

The minted ID serves as a fallback mechanism. When a node restarts, the agent may supply a different session identifier through its `/session-start` hook, which takes precedence over the originally minted UUID.

The resolution logic lives in [`src/renderer/terminal/agent-restart.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/renderer/terminal/agent-restart.ts):

```typescript
import { restartSessionId } from 'src/renderer/terminal/agent-restart';

// During node restart:
const idToUse = restartSessionId(liveHookId, node.data.agentSessionId);
// Returns: liveHookId if present, otherwise falls back to the minted ID

```

This prioritization ensures that if the agent generates its own session identifier during runtime, nodeterm respects that live ID while retaining the minted value as a persistent fallback for true cold starts.

## Reading the Session Display Name

While the minted UUID maintains the technical session continuity, the user-facing title displayed in the node header derives from a different source. [`src/core/agent-session-name.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/core/agent-session-name.ts) extracts the readable session name from the transcript associated with the provider's session ID (whether live or minted), ensuring the UI reflects the actual conversation content rather than the raw UUID.

## Summary

- **Capability-gated generation**: Nodeterm only mints session IDs in [`src/renderer/state/workspace.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/renderer/state/workspace.ts) when `sessionIdFlagSupported` is true and the agent appears in the `SESSION_ID_CAPABLE` whitelist.
- **UUID persistence**: The minted identifier is generated once using `uuid()` and stored in the node's `agentSessionId` property to survive application reloads.
- **Conditional CLI injection**: [`src/shared/agents/launch.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/shared/agents/launch.ts) appends `--session-id` only when the node carries a minted ID and the CLI supports the flag.
- **Live ID precedence**: During restarts, [`src/renderer/terminal/agent-restart.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/renderer/terminal/agent-restart.ts) prioritizes hook-supplied session IDs over the originally minted UUID.
- **Display abstraction**: Session titles are resolved separately from the technical ID via [`src/core/agent-session-name.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/core/agent-session-name.ts).

## Frequently Asked Questions

### Which agents support session ID minting in nodeterm?

Currently, only Claude-based agents support session ID minting. The `SESSION_ID_CAPABLE` array in [`src/shared/agents/config.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/shared/agents/config.ts) explicitly whitelists `'claude'`, and the `mintsSessionId(id)` helper returns `true` only for these agent types. Other agents skip the minting process entirely and launch without persistent session identifiers.

### When is a session ID generated versus reused?

A new UUID is generated exactly once during the initial creation of the agent node in [`src/renderer/state/workspace.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/renderer/state/workspace.ts) if `sessionIdFlagSupported` is true. On subsequent launches or restarts, nodeterm reuses the existing `agentSessionId` stored in the node data. If the agent's `/session-start` hook returns a live session ID during restart, that live identifier takes precedence for the runtime session while the minted ID remains in persistent storage.

### What happens if the CLI doesn't support the --session-id flag?

If the capability probe fails or the cached `sessionIdFlagSupported` flag is false, [`src/renderer/state/workspace.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/renderer/state/workspace.ts) sets `mintedSessionId` to `undefined`. Consequently, [`src/shared/agents/launch.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/shared/agents/launch.ts) skips the `withSessionId` wrapper, launching the agent without the flag. The session operates in ephemeral mode without resumption capabilities across restarts.

### How does nodeterm handle session IDs after a restart?

During restart, [`src/renderer/terminal/agent-restart.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/renderer/terminal/agent-restart.ts) calls `restartSessionId(liveId, mintedId)`, which implements a fallback strategy: if the agent provided a `liveId` through its startup hook, that value is used; otherwise, the function returns the originally `mintedId`. This ensures continuity when possible while gracefully degrading to the persistent minted identifier when the agent doesn't supply a runtime session ID.