Difference Between destroy and recycle in TerminalTransport: Session Lifecycle Management

In the TerminalTransport interface, destroy permanently terminates a PTY session when a terminal node is deleted, while recycle temporarily ends a session to allow the same node ID to be respawned in a new working directory.

The TerminalTransport interface in the eneskirca/nodeterm repository defines the contract for managing terminal sessions across the application. Located in src/renderer/terminal/transport.ts, this abstraction handles session creation, resizing, and termination. Understanding the difference between destroy and recycle is essential for developers working with session persistence or implementing custom transport layers.

Understanding TerminalTransport Session Lifecycle

Both methods terminate a PTY (pseudo-terminal) session, but they serve distinct lifecycle intents. The interface defines these methods to handle two scenarios: permanent node removal and temporary session turnover. While the underlying tmux kill operation may be identical in the concrete implementation, the semantic difference determines how co-viewers and the canvas state respond to the action.

The destroy Method: Permanent Session Termination

The destroy(persistKey, opts?) method is invoked when a terminal node is permanently removed from the canvas. This occurs when a user clicks the × button or invokes a Delete action.

Key characteristics of destroy:

  • Permanent removal: The session ends definitively because the node itself is being deleted from the workspace.
  • everySocket option: The optional opts.everySocket flag extends the kill operation to every local tmux socket that may hold the session name. This is specifically used by the speculative "kill all" action in the Session-Memory panel to ensure complete cleanup of stray sockets.
  • Co-viewer notification: Peer viewers receive a closed by <peer> notification and are explicitly prohibited from respawning the session.

According to the interface definition in src/renderer/terminal/transport.ts, this method represents the final lifecycle event for a terminal session associated with a specific node.

The recycle Method: Session Turnover Without Node Deletion

The recycle(persistKey) method temporarily ends a node's session so that the same node ID can be respawned, typically when the node is moved into a worktree or changes its underlying working directory.

Key characteristics of recycle:

  • Session turnover: While the underlying tmux kill matches destroy, the intent is opposite—the node remains on the canvas, and a replacement session will be created immediately after.
  • Worktree migration: This is used when a node stays visually present but its underlying directory changes, requiring a fresh shell in the new location.
  • Co-viewer handling: Peers receive an onRecycled event. If a replacement session is already live (ready: true), the terminal automatically recreates and re-attaches; if not (ready: false), the user must manually reopen the node.

This method preserves the node's identity and position while refreshing its underlying shell session.

destroy vs recycle: A Direct Comparison

Understanding the semantic differences helps prevent accidental data loss or session desynchronization:

  • destroy(persistKey, opts?) – Use this for permanent removal when the terminal node is deleted from the canvas. Prevents session resurrection and optionally clears all related tmux sockets via the everySocket flag.

  • recycle(persistKey) – Use this for temporary session turnover when the node persists but requires a new shell (e.g., directory changes). Allows seamless respawning with the same node ID and notifies peers to reattach or wait.

The critical distinction is that destroy treats the session as dead and unrecoverable, while recycle treats it as transiently paused with an imminent replacement.

Implementation in LocalTransport

The concrete LocalTransport implementation follows the TerminalTransport interface contract defined in src/renderer/terminal/transport.ts. Both methods execute similar tmux kill commands, but the surrounding logic differs:

  • destroy updates session metadata to mark the session as permanently closed.
  • recycle triggers the onRecycled event pipeline and maintains the node's registry entry for immediate respawning.

Practical Code Examples

When deleting a terminal node permanently:

// Permanent deletion of a terminal node
await transport.destroy(nodeId);

// Optional: Clear all stray tmux sockets (Session-Memory panel usage)
await transport.destroy(nodeId, { everySocket: true });

When moving a terminal node into a worktree (same node ID, new directory):

// Temporary recycle for worktree migration
await transport.recycle(nodeId);
// The renderer listens for onRecycled and automatically creates a fresh
// session attached to the new worktree directory.

Summary

  • destroy permanently terminates a PTY session when the terminal node is deleted from the canvas, with optional socket cleanup via the everySocket parameter.
  • recycle temporarily ends a session to allow the same node ID to be respawned with a new working directory, triggering onRecycled events for co-viewers.
  • Both methods use similar underlying tmux kill operations, but destroy prohibits session resurrection while recycle expects immediate replacement.
  • Co-viewers receive closed by <peer> notifications for destroyed sessions and onRecycled events for recycled sessions, with different reattachment behaviors for each.

Frequently Asked Questions

What happens to co-viewers when a terminal session is destroyed?

Co-viewers receive a closed by <peer> notification and are prohibited from respawning the session. The session is marked as permanently terminated across all connected clients, ensuring no ghost sessions remain active on peer machines.

Can a recycled terminal session be automatically restored?

Yes. If the replacement session is already live (ready: true) when the onRecycled event fires, the terminal automatically recreates and re-attaches the session for all viewers. If the session is not ready (ready: false), the user must manually reopen the node to establish the new connection in the updated working directory.

When should I use the everySocket option with destroy?

Use the everySocket flag when you need to ensure complete cleanup of any stray tmux sockets that might hold the session name. This is specifically designed for the "kill all" action in the Session-Memory panel to prevent ghost sessions from consuming resources after bulk deletion operations.

Is the underlying tmux kill operation different between destroy and recycle?

No. In the LocalTransport implementation, the underlying tmux kill command is identical. The difference lies in the lifecycle intent and post-kill behavior: destroy treats the session as permanently dead and removes the node from the canvas, while recycle treats it as transiently paused with an imminent replacement session using the same node ID.

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 →