# How Desktop Commander Implements Process Output Pagination

> Discover how Desktop Commander implements process output pagination using line-buffered files and the readOutputPaginated method. Learn about absolute, relative, and tail-based reads for efficient output management.

- Repository: [Eduard Ruzga/DesktopCommanderMCP](https://github.com/wonderwhy-er/DesktopCommanderMCP)
- Tags: internals
- Published: 2026-08-03

---

**Desktop Commander implements process output pagination by treating running process streams as line-buffered files that support absolute, relative, and tail-based reads through the `readOutputPaginated` method in [`terminal-manager.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/terminal-manager.ts).**

Desktop Commander MCP provides a file-like interface for streaming process output, enabling precise process output pagination through the `read_process_output` tool. This system allows AI agents to read long-running process output in manageable chunks without losing context or missing new data. The implementation centers on a line-buffered storage mechanism that supports multiple read modes through careful index management.

## Pagination Architecture Overview

The pagination system spans three architectural layers: the tool definition layer that validates incoming requests, the schema layer that defines pagination parameters, and the terminal manager that executes the buffer operations. This separation ensures that the LLM-facing API remains simple while the underlying logic handles complex buffer management, eviction policies, and state tracking.

## Core Components

### Tool Definition and Routing

The `read_process_output` tool is defined in [`src/tools/improved-process-tools.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/improved-process-tools.ts) at lines 42-45. When invoked, it validates arguments and forwards the request to the terminal manager at line 314 through the `readOutputPaginated` method call (lines 314-318). This routing layer translates high-level tool calls into specific buffer operations while preserving the process ID and pagination parameters.

### Argument Schema

The pagination parameters are strictly defined in [`src/tools/schemas.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/schemas.ts) at lines 37-42. The schema accepts:

- **offset**: Number indicating the starting position (defaults to 0)
- **length**: Number controlling how many lines to retrieve (defaults to the configuration value)

These parameters drive the three distinct pagination modes supported by the system.

### Terminal Manager Implementation

The core logic resides in [`src/terminal-manager.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/terminal-manager.ts). The public method `readOutputPaginated(pid, offset, length)` at lines 514-528 serves as the entry point, delegating to the private helper `readFromLineBuffer` (lines 55-88) which performs the actual buffer slicing and index management. This helper maintains internal state through `lastReadIndex` to track which lines have been consumed.

## How Pagination Modes Work

Desktop Commander supports three distinct offset behaviors, each optimized for different access patterns:

**Offset = 0 (Default): Read New Output**

When offset is 0 or omitted, the system returns lines added since the last read. The `readFromLineBuffer` helper uses `lastReadIndex` as the start position and automatically updates it after reading via `updateLastRead`. This mode is ideal for streaming logs where you want to consume new data incrementally.

**Offset > 0: Absolute Line Number**

A positive offset specifies an absolute 0-based line number to start reading from. The start index is set to the supplied offset, and crucially, the read does not modify `lastReadIndex`. This allows random access to any section of the buffer without affecting the "new output" pointer.

**Offset < 0: Tail Read**

Negative offsets implement tail functionality, counting from the end of the buffer. For example, -50 reads the last 50 lines. The calculation uses `startIndex = totalLines - Math.abs(offset)`, and the read count is limited by the `length` parameter. Like absolute reads, tail reads do not update `lastReadIndex`.

## PaginatedOutputResult Structure

The `readFromLineBuffer` helper returns a `PaginatedOutputResult` object containing:

- **lines**: Array of the selected text lines
- **totalLines**: Total lines currently buffered for this process
- **readFrom**: Starting line number of this read operation
- **readCount**: Number of lines actually returned
- **remaining**: Lines left in buffer after this read
- **evictedLines**: Warning flag if buffer capacity was exceeded and old lines were removed

The tool layer constructs a human-readable status line (e.g., "`[Reading 20 new lines from line 105 (total: 500 lines, 380 remaining)]`") and appends process state information.

## Practical Usage Examples

Here are concrete TypeScript examples demonstrating each pagination mode:

```typescript
// 1. Start a long-running process (e.g., ping)
await startProcess({ command: "ping 8.8.8.8", timeout_ms: 0 });

// 2. Read the first 10 lines using absolute offset
await readProcessOutput({ pid: 42, offset: 0, length: 10 });

// 3. Read only new output that appeared since the previous call
await readProcessOutput({ pid: 42 }); // offset defaults to 0

// 4. Tail-read the last 20 lines of the buffer
await readProcessOutput({ pid: 42, offset: -20 });

```

Each call invokes the `read_process_output` tool, which routes to `terminalManager.readOutputPaginated` as implemented in the source files.

## Summary

- Desktop Commander treats process output as a line-buffered stream accessible through [`src/terminal-manager.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/terminal-manager.ts)
- The `readOutputPaginated` method supports three modes: new output (offset 0), absolute positioning (offset > 0), and tail reads (offset < 0)
- Pagination state is maintained via `lastReadIndex` in the terminal manager, updated only during default offset reads
- The system returns rich metadata including line counts, eviction warnings, and remaining buffer space
- Tool definitions in [`src/tools/improved-process-tools.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/improved-process-tools.ts) provide the LLM interface while delegating to the core manager

## Frequently Asked Questions

### What is the default behavior when calling read_process_output without specifying an offset?

When the offset parameter is omitted or set to 0, Desktop Commander returns only new lines that have been added to the buffer since the last read. The system tracks this using the `lastReadIndex` variable in [`terminal-manager.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/terminal-manager.ts), which updates automatically after each default read to prevent returning duplicate data.

### How does Desktop Commander handle very large process outputs?

The implementation includes a line buffer with a configurable capacity cap. When the buffer exceeds this limit, older lines are evicted and the `evictedLines` flag is set in the `PaginatedOutputResult`. This prevents memory exhaustion while alerting consumers that early output has been lost.

### Can I read from a specific line number without affecting the "new output" pointer?

Yes. When you specify a positive offset greater than 0, the `readFromLineBuffer` helper performs an absolute read starting at that 0-based line index without invoking `updateLastRead`. This leaves the `lastReadIndex` unchanged, so subsequent default reads still return only truly new output.

### What files contain the core pagination logic?

The primary implementation is in [`src/terminal-manager.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/terminal-manager.ts) (lines 514-528 for the public API and lines 55-88 for the buffer logic). The tool interface is defined in [`src/tools/improved-process-tools.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/improved-process-tools.ts) (lines 42-45 and 314-318), with parameter schemas in [`src/tools/schemas.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/schemas.ts) (lines 37-42).