How Desktop Commander Implements Process Output Pagination
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.
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 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 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. 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:
// 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 - The
readOutputPaginatedmethod supports three modes: new output (offset 0), absolute positioning (offset > 0), and tail reads (offset < 0) - Pagination state is maintained via
lastReadIndexin 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.tsprovide 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, 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 (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 (lines 42-45 and 314-318), with parameter schemas in src/tools/schemas.ts (lines 37-42).
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →