{
  "@context": "https://schema.org",
  "@id": "https://aggr.aymericbeaumet.com/items/mariozechner-at/2025-08-15-mcp-vs-cli-benchmarking-tools-for-coding-agents/#webpage",
  "@type": [
    "WebPage",
    "ArchiveComponent"
  ],
  "articleBody": "![](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli/media/header.jpg)\\\nTerminal tools comparison\n\n- [MCPs as thin wrappers](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_0)\n- [Building a CLI and MCP server](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_1)\n- [Designing the evaluation](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_2)\n  - [Tool definitions](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_3)\n  - [Task definitions](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_4)\n  - [Example evaluation prompt](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_5)\n  - [Running the evaluation](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_6)\n  - [Statistics and judgments](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_7)\n- [The Results](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_8)\n  - [Token Usage](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_9)\n  - [Key Findings](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_10)\n- [Reproducing the Results](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_11)\n  - [Easy mode: Run individual prompts](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_12)\n  - [Full mode: Run the complete evaluation](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_13)\n- [So, MCP or CLI?](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_14)\n\n[MCP servers](https://modelcontextprotocol.io) (MCPs for short) are all the rage. However, practitioners using agentic coding tools are usually skeptical. Many MCPs flood the context window with unnecessary output or offer dozens of tools, degrading your agent's performance by [poisoning the context](https://mariozechner.at/posts/2025-06-02-prompts-are-code/#toc_0). Many practitioners (myself included) resort to letting coding agents directly call CLI tools instead. But what if we're wrong?\n\n## MCPs as thin wrappers\n\nJust like a lot of meetings could have been emails, a lot of MCPs could have been CLI invocations. For example, there's the [GitHub MCP Server](https://github.com/github/github-mcp-server), which reimplements functionality that's already available in the [GitHub CLI](https://cli.github.com/). There's little benefit of using that MCP compared to telling your coding agent to use its shell tool to run the GitHub CLI directly. In fact, most often the GitHub MCP Server will lead to much worse results than just letting the agent run the command line tool directly.\n\nAnother popular choice is [Context7](https://context7.com/), which provides code snippets to help agents use popular libraries. I found [some of my own libraries](https://context7.com/libgdx/libgdx) in there and the snippets are utterly useless. What works better is having Claude clone the dependency's repository, then let a sub-agent analyze it and generate a concise user manual for the task at hand.\n\nBut it depends on the MCP and available CLI tools. Sometimes there are no easy-to-use CLI tools, making MCPs sensible. Other times CLI tools are too verbose. MCP servers are also the only option for LLM clients without a built-in shell tool. And stateful tools are easier to implement as MCPs than CLIs since MCP servers are stateful by default.\n\nI wanted to quantify the difference by writing an MCP server and a corresponding CLI that can be used with Claude Code and for which there are equivalent standard CLI tools Claude encountered during training. I then wrote a hacky evaluation framework to assess:\n\n- what costs more\n- what takes more time\n- which approach has higher success rates\n- whether the inherent knowledge about standard tools beats in-context learning about a previously unseen tool\n\n## Building a CLI and MCP server\n\nI started by building a tool that's inherently useful to myself: [terminalcp](https://github.com/badlogic/terminalcp/tree/ac9272ed03a40e4d9666ded80667688b16a7a16a), a (less capable) tmux alternative with an MCP server that lets agents control terminal applications (debuggers, REPLs, vim, htop) like Playwright controls browsers.\n\nHere's a quick example of terminalcp in action using the CLI version to debug an executable with lldb and observing the session in a second terminal window:\n\nAnd here's the terminalcp MCP server version used by Claude Code to debug the same executable with lldb:\n\nNote how I can attach to the lldb session from another terminal instance and co-debug with Claude.\n\nYou can bore yourself to death by watching the [making of the v0 of terminalcp](https://www.youtube.com/live/Pd1kP9WJhEo) or check out the [source code](https://github.com/badlogic/terminalcp/tree/ac9272ed03a40e4d9666ded80667688b16a7a16a). Here's a quick rundown:\n\n- [TerminalManager](https://github.com/badlogic/terminalcp/blob/ac9272ed03a40e4d9666ded80667688b16a7a16a/src/terminal-manager.ts) is the core: uses [node-pty](https://github.com/microsoft/node-pty) to spawn processes in pseudo terminals and [xterm.js](https://xtermjs.org/) to render ANSI sequences.\n- [TerminalServer](https://github.com/badlogic/terminalcp/blob/ac9272ed03a40e4d9666ded80667688b16a7a16a/src/terminal-server.ts) runs as a persistent daemon, auto-spawned when needed. Talks to clients via Unix socket (works on Windows too, thanks Node.js).\n- [TerminalClient](https://github.com/badlogic/terminalcp/blob/ac9272ed03a40e4d9666ded80667688b16a7a16a/src/terminal-client.ts) handles communication between the MCP/CLI and the server.\n- The [MCP server](https://github.com/badlogic/terminalcp/blob/ac9272ed03a40e4d9666ded80667688b16a7a16a/src/mcp-server.ts) just forwards LLM tool calls to the terminal server. Dead simple.\n- [CLI logic](https://github.com/badlogic/terminalcp/blob/ac9272ed03a40e4d9666ded80667688b16a7a16a/src/index.ts) I stuffed into index.ts. Parses arguments, handles special keys (up, down, etc.) using tmux-style symbolic key names and control sequences.\n- [AttachClient](https://github.com/badlogic/terminalcp/blob/ac9272ed03a40e4d9666ded80667688b16a7a16a/src/attach-client.ts) lets users attach to running sessions as shown in the videos.\n\nI tried to keep terminalcp token-efficient. The server replies with plain text, not JSON (in case of the MCP server, that plain text still gets wrapped in JSON-RPC messages, whoop whoop). The MCP server exposes a single `terminalcp` tool instead of one per command. This is not just voodoo. In an older version of the Claude Code documentation, Anthropic actually mentioned that there's a limit to the number of tools you should expose to the LLM, otherwise it gets confused (I can no longer find that reference). You can also find this [old Claude Sonnet 3.7 cookbook](https://github.com/anthropics/anthropic-cookbook/blob/main/tool_use/parallel_tools_claude_3_7_sonnet.ipynb) where they introduce a batch tool so that Claude can call multiple tools in parallel.\n\nFinally, the commands let you pick only the output you need. `stdout` can return just the last N lines of the rendered terminal scrollback buffer. `stream` can strip ANSI codes and return only new output since the last call with `since_last`. Here are all the commands, both the MCP tool arguments as JSON and the corresponding CLI invocation:\n\n```bash\n# start - spawn a process with optional name and working directory\n{\"action\": \"start\", \"command\": \"python3 -i\", \"name\": \"repl\", \"cwd\": \"/home/user\"}\nterminalcp start repl \"python3 -i\"\n\n# stop - kill one or all processes\n{\"action\": \"stop\", \"id\": \"repl\"}  # or just {\"action\": \"stop\"} for all\nterminalcp stop repl  # or just terminalcp stop for all\n\n# stdin - send input to a process\n{\"action\": \"stdin\", \"id\": \"repl\", \"data\": \"print('hello')\\r\"}\nterminalcp stdin repl \"print('hello')\" ::Enter\n\n# stdout - get rendered terminal screen with optional line limit\n{\"action\": \"stdout\", \"id\": \"repl\", \"lines\": 50}\nterminalcp stdout repl 50\n\n# stream - get raw output, optionally incremental with since_last\n{\"action\": \"stream\", \"id\": \"repl\", \"since_last\": true, \"strip_ansi\": false}\nterminalcp stream repl --since-last --no-strip-ansi\n\n# list - list all sessions\n{\"action\": \"list\"}\nterminalcp ls\n\n# term-size - get terminal dimensions\n{\"action\": \"term-size\", \"id\": \"repl\"}\n# Not exposed in CLI\n\n# version - check compatibility\n{\"action\": \"version\"}\nterminalcp version\n\n# kill-server - shut everything down\n{\"action\": \"kill-server\"}\nterminalcp kill-server\n```\n\nFinally, here's the tool description that the MCP server reports to the MCP client like Claude Code:\n\n```markdown\nControl background processes with virtual terminals. IMPORTANT: Always clean up processes with \"stop\" action when done.\n\nExamples:\n  Start dev server: {\"action\": \"start\", \"command\": \"npm run dev\", \"cwd\": \"/path/to/project\"}\n  Send text with Enter: {\"action\": \"stdin\", \"id\": \"proc-123\", \"data\": \"npm test\\r\"}\n  Send arrow keys: {\"action\": \"stdin\", \"id\": \"proc-123\", \"data\": \"echo hello\\u001b[D\\u001b[D\\u001b[Dhi \\r\"}\n  Send Ctrl+C: {\"action\": \"stdin\", \"id\": \"proc-123\", \"data\": \"\\u0003\"}\n  Stop process: {\"action\": \"stop\", \"id\": \"proc-abc123\"}\n  Stop all processes: {\"action\": \"stop\"}\n\n  Get terminal screen: {\"action\": \"stdout\", \"id\": \"proc-123\"}  # Current view + scrollback\n  Get last 50 lines: {\"action\": \"stdout\", \"id\": \"proc-123\", \"lines\": 50}\n  Get all output ever: {\"action\": \"stream\", \"id\": \"proc-123\"}  # From process start\n  Get new output only: {\"action\": \"stream\", \"id\": \"proc-123\", \"since_last\": true}  # Since last stream call\n\nOutput modes:\n  stdout: Terminal emulator output - returns the rendered screen as user would see it.\n          Limited to 10K lines scrollback. Best for: interactive tools, TUIs, REPLs, debuggers.\n\n  stream: Raw process output - returns all text the process has written to stdout/stderr.\n          Strips ANSI codes by default (set strip_ansi: false to keep). No limit on history.\n          With since_last: true, returns only new output since last stream call on this process.\n          Best for: build logs, test output, monitoring long-running processes.\n\nCommon escape sequences for stdin:\n  Enter: \\r or \\u000d\n  Tab: \\t or \\u0009\n  Escape: \\u001b\n  Backspace: \\u007f\n  Ctrl+C: \\u0003\n  Ctrl+D: \\u0004\n  Ctrl+Z: \\u001a\n\n  Arrow keys: Up=\\u001b[A Down=\\u001b[B Right=\\u001b[C Left=\\u001b[D\n  Navigation: Home=\\u001b[H End=\\u001b[F PageUp=\\u001b[5~ PageDown=\\u001b[6~\n  Delete: \\u001b[3~ Insert: \\u001b[2~\n  Function keys: F1=\\u001bOP F2=\\u001bOQ F3=\\u001bOR F4=\\u001bOS\n  Meta/Alt: Alt+x=\\u001bx (ESC followed by character)\n\nInteractive examples:\n  Vim: stdin \"vim test.txt\\r\" → stdin \"iHello\\u001b:wq\\r\" → stdout\n  Python: start \"python3 -i\" → stdin \"2+2\\r\" → stdout\n  Build monitoring: start \"npm run build\" → stream (since_last: true) → repeat\n  Interrupt: stdin \"sleep 10\\r\" → stdin \"\\u0003\" (Ctrl+C)\n\nNote: Commands run via bash -c. Use absolute paths, not aliases.\n```\n\nThis isn't quite perfect yet. For example, `stdin` could let you specify a pattern to watch for in the output and wait for it with a timeout, then return the new output. This would save a round trip between client and server. But it works well enough for my evaluation.\n\n## Designing the evaluation\n\nMy aim wasn't to create a fully scientific evaluation. For that, you should check out [Eugene Yan's blog](https://eugeneyan.com/writing/llm-evaluators/), which has fantastic information. I just aim at getting some basic stats with which I can annoy people at a party.\n\nHere's the bird's eye view: I defined three tasks requiring terminal control (start process, send input, get output) and four tools to test: terminalcp MCP server, terminalcp CLI, tmux, and screen. The [task definitions](https://github.com/badlogic/terminalcp/tree/ac9272ed03a40e4d9666ded80667688b16a7a16a/test/eval/tasks) and [tool definitions](https://github.com/badlogic/terminalcp/tree/ac9272ed03a40e4d9666ded80667688b16a7a16a/test/eval/tools) are simple markdown files. Tool definitions include some frontmatter that defines how to add them to Claude Code's toolset if necessary, as well as how to clean up after a run that used this tool. These are the inputs to my evaluation framework.\n\nThe super hacky [evaluation framework](https://github.com/badlogic/terminalcp/tree/ac9272ed03a40e4d9666ded80667688b16a7a16a/test/eval) works like this:\n\n1. **Run the tests**: For each task and tool combination, the framework spawns a fresh Claude Code instance with a clean config (no custom MCPs, no CLAUDE.md files). Each task/tool combination is run 10 times since LLMs are non-deterministic. The framework combines the task and tool definitions into a single prompt with instructions to output TASK\\_COMPLETE or TASK\\_FAILED markers. The Claude Code instance is driven via TerminalManager so the test runner can nudge Claude if it stalls. At the end of each run, it issues `/cost` to capture time, tokens, and cost.\n\n2. **Capture everything**: Each run produces multiple output files:\n\n   - The prompt that was sent\n   - The terminal scrollback buffer (what you'd see on screen)\n   - The raw ANSI stream (with and without escape codes)\n3. **Extract statistics**: Parses outputs for success/failure markers, cost, time, and token usage by model.\n\n4. **Judge with Claude**: The framework uses Claude Code to judge each task/tool combination, reading outputs and assessing what worked, what failed, and why. It also suggests improvements for the task. In a second pass, Claude ranks all tools for each task with analysis, insights, and recommendations.\n\nThe framework can run evaluations in parallel, repeat them multiple times for consistency, and handles cleanup between runs. A full run produces a lot of files.\n\n![](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli/media/mdfiles.png)\n\nWhich is why I use Claude as a judge to give me some initial insights I can then use to navigate the files for manual analysis.\n\nLet's have a quick look at the tools and task definitions.\n\n### Tool definitions\n\nI try to make the tool definitions follow the exact same structure, so the comparison is fair. This includes instructions for special keys, multiline input, scrollback handling, and other operations the agent needs to perform with the tool to complete the tasks. The goal is to give each tool equal footing via in-context information.\n\nThe terminalcp MCP server already reports the tool description, so I only added a few more hints. Here's the full definition:\n\n```markdown\n---\n{\n  \"type\": \"mcp\",\n  \"mcpServers\": {\n    \"terminalcp\": {\n      \"type\": \"stdio\",\n      \"command\": \"npx\",\n      \"args\": [\"tsx\", \"src/index.ts\", \"--mcp\"]\n    }\n  }\n}\n---\n\n### Quick Start (Typical Workflow)\n1. Start session: `{\"action\": \"start\", \"command\": \"command args\", \"name\": \"NAME\"}`\n2. Send input: `{\"action\": \"stdin\", \"id\": \"NAME\", \"data\": \"input\\r\"}`\n3. Get current viewport: `{\"action\": \"stdout\", \"id\": \"NAME\"}`\n4. Clean up: `{\"action\": \"stop\", \"id\": \"NAME\"}`\n\n### Important Notes\n- **Only stop sessions you started by name**\n- **stdout = viewport + scrollback**: Shows clean rendered terminal\n- **stdout with lines**: `{\"action\": \"stdout\", \"id\": \"NAME\", \"lines\": N}` for last N lines\n- **stream = raw output**: Contains all output since start (avoid for TUIs)\n- Use `\\r` for Enter, `\\u001b[A/B/C/D` for arrows, `\\u0003` for Ctrl+C\n- **TIP**: For interactive programs, use stdout after operations complete for clean view\n```\n\nThe terminalcp CLI tool definition is bigger since I need to explain the command syntax:\n\n```markdown\n---\n{\n  \"type\": \"cli\",\n  \"cleanup\": \"npx tsx src/index.ts stop || true\"\n}\n---\n\n### Quick Start (Typical Workflow)\n1. `npx tsx src/index.ts start NAME command args` - Start session\n2. `npx tsx src/index.ts stdin NAME \"input\" ::Enter` - Send input\n3. `npx tsx src/index.ts stdout NAME` - Get current viewport (clean, rendered)\n4. `npx tsx src/index.ts stop NAME` - Clean up when done\n\n### Core Commands\n\n- **Start session**: `npx tsx src/index.ts start NAME command args`\n  - Returns session ID (the NAME you provided)\n  - Example: `npx tsx src/index.ts start repl python3 -i`\n\n- **List sessions**: `npx tsx src/index.ts ls`\n  - Shows: ID, status (running/stopped), working directory, command\n\n- **Send input**: `npx tsx src/index.ts stdin NAME \"input\" ::Enter`\n  - Batch multiple: `npx tsx src/index.ts stdin NAME \"cmd1\" ::Enter \"cmd2\" ::Enter \"cmd3\" ::Enter`\n  - Special keys: `::C-c` (Ctrl+C), `::Up`/`::Down`/`::Right`/`::Left` (arrows), `::PageUp`/`::PageDown`\n  - Example: `npx tsx src/index.ts stdin repl \"2+2\" ::Enter`\n  - **Multiline (Python auto-indents)**: `npx tsx src/index.ts stdin repl \"def greet(name):\" ::Enter \"return f'Hello {name}'\" ::Enter ::Enter`\n\n- **Get output**:\n  - **Current viewport** (RECOMMENDED - clean, rendered view): `npx tsx src/index.ts stdout NAME`\n  - **Last N lines**: `npx tsx src/index.ts stdout NAME N`\n  - **Full scrollback**: `npx tsx src/index.ts stdout NAME 10000` (up to 10,000 lines max)\n\n- **Stop session**: `npx tsx src/index.ts stop NAME`\n\n### Important Notes\n- **Only stop sessions you started by name**\n- **stdout = viewport + scrollback**: Shows clean rendered terminal (up to 10,000 lines)\n- **stdout N = last N lines**: Efficient for checking recent output\n- **TIP**: For interactive programs, use stdout after operations complete for clean view\n\nYou are free to run `npx tsx src/index.ts --help` if you require more information on the tool.\n```\n\nThe tmux tool definition follows the same structure, mapping each terminalcp operation to its tmux equivalent:\n\n```markdown\n---\n{\n  \"type\": \"cli\",\n  \"cleanup\": \"tmux kill-server || true\"\n}\n---\n\n### Quick Start (Typical Workflow)\n1. `tmux new-session -d -s NAME \"command\" \\; set remain-on-exit on` - Start session\n2. `tmux send-keys -t NAME \"input\" Enter` - Send input\n3. `tmux capture-pane -t NAME -p` - Get current viewport (clean, rendered)\n4. `tmux kill-session -t NAME` - Clean up when done\n\n### Core Commands\n\n- **Start session**: `tmux new-session -d -s NAME \"command args\" \\; set remain-on-exit on`\n  - `-d` detached mode, `-s` session name\n  - **IMPORTANT**: Use `remain-on-exit on` to capture output after process ends\n  - Example: `tmux new-session -d -s repl \"python3 -i\" \\; set remain-on-exit on`\n\n- **List sessions**: `tmux list-sessions` or `tmux ls`\n\n- **Send input**: `tmux send-keys -t NAME \"input\" Enter`\n  - Batch multiple: `tmux send-keys -t NAME \"cmd1\" Enter \"cmd2\" Enter \"cmd3\" Enter`\n  - Special keys: `C-c` (Ctrl+C), `Up`/`Down`/`Right`/`Left` (arrows), `PageUp`/`PageDown`\n  - Example: `tmux send-keys -t repl \"2+2\" Enter`\n  - **Multiline (Python auto-indents)**: `tmux send-keys -t repl \"def greet(name):\" Enter \"return f'Hello {name}'\" Enter Enter`\n\n- **Get output**:\n  - **Current viewport** (RECOMMENDED - clean, rendered view): `tmux capture-pane -t NAME -p`\n  - **Last N lines**: `tmux capture-pane -t NAME -p -S -N`\n  - **Full scrollback**: `tmux capture-pane -t NAME -p -S -`\n\n- **Check if alive**: `tmux list-panes -t NAME -F \"#{pane_dead}\"` (0=alive, 1=dead)\n\n- **Kill session**: `tmux kill-session -t NAME`\n\n### Important Notes\n- **Only kill sessions you started by name**\n- **capture-pane = viewport only**: Shows current screen (clean, rendered), perfect for TUIs/REPLs\n- **capture-pane -S - = full scrollback**: Clean rendered history\n- **remain-on-exit on**: Essential for capturing output after process ends\n- **TIP**: For interactive programs, use capture-pane after operations complete for clean view\n\nYou are free to run `tmux --help` if you require more information on the tool.\n```\n\nThe screen tool definition follows the same pattern, except there's a bug in screen v4.0.3 that requires a one-time workaround command to enable hardcopy:\n\n````markdown\n---\n{\n  \"type\": \"cli\",\n  \"cleanup\": \"for session in $(screen -ls | grep -o \\\"[0-9]*\\\\\\\\.[^ ]*\\\"); do screen -S \\\"$session\\\" -X quit; done || true\"\n}\n---\n\n### Quick Start (Typical Workflow)\n1. `rm -f screenlog.0 && screen -dmS NAME -L command args` - Start session\n2. `expect -c 'spawn screen -r NAME; send \"\\001d\"; expect eof' >/dev/null 2>&1` - Enable hardcopy (once per session)\n3. `screen -S NAME -X stuff $'input\\n'` - Send input\n4. `screen -S NAME -p 0 -X hardcopy output.txt && cat output.txt` - Get current viewport (clean, rendered)\n5. `screen -S NAME -X quit` - Clean up when done\n\n### Core Commands\n\n- **Start session**: `screen -dmS NAME -L program args`\n  - `-d` detached mode, `-m` force new session, `-S` session name, `-L` enable logging\n  - **IMPORTANT**: Remove old `screenlog.0` first: `rm -f screenlog.0`\n  - Example: `rm -f screenlog.0 && screen -dmS repl -L python3 -i`\n\n- **List sessions**: `screen -ls`\n\n- **Send input**: `screen -S NAME -X stuff $'input\\n'`\n  - REQUIRED: Use $'...' syntax for proper escape sequences\n  - Batch multiple: `screen -S NAME -X stuff $'cmd1\\ncmd2\\ncmd3\\n'`\n  - Special keys: `$'\\003'` (Ctrl+C), `$'\\e[A]'/`$'\\e[B]'/`$'\\e[C]'/`$'\\e[D]'` (Up/Down/Right/Left arrows)\n  - Example: `screen -S repl -X stuff $'2+2\\n'`\n  - **Multiline (Python auto-indents)**: `screen -S repl -X stuff $'def greet(name):\\nreturn f\\'Hello {name}\\'\\n\\n'`\n\n- **Get output**:\n  - **Current viewport** (RECOMMENDED - clean, rendered view):\n    ```bash\n    # First time per session (v4.0.3 bug workaround):\n    expect -c 'spawn screen -r NAME; send \"\\001d\"; expect eof' >/dev/null 2>&1\n    # Then use hardcopy normally:\n    screen -S NAME -p 0 -X hardcopy output.txt && cat output.txt\n    ```\n  - **Last N lines** (raw with ANSI codes): `tail -N screenlog.0`\n  - **Full scrollback** (raw with ANSI codes): `cat screenlog.0`\n\n- **Kill session**: `screen -S NAME -X quit`\n\n### Important Notes\n- **Only kill sessions you started by name**\n- **hardcopy = viewport only**: Shows current screen (clean, rendered), perfect for TUIs/REPLs\n- **screenlog.0 = full raw output**: Contains all ANSI codes since session start\n- **v4.0.3 hardcopy bug**: Run expect workaround once per session\n- **TIP**: For interactive programs, use hardcopy after operations complete for clean view\n\nYou are free to run `screen --help` if you require more information on the tool.\n````\n\n### Task definitions\n\nI created three tasks that exercise different aspects of terminal control. They should speak for themselves. Probably the most interesting one is the project analysis task where the agent needs to command OpenCode and navigate its TUI.\n\n**Task 1: Debug with LLDB (debug-lldb.md)**\n\n```markdown\nThe program `evaluation-results/demo-buggy` crashes when executed. Use LLDB to:\n- Start the program under the debugger\n- Identify where and why it crashes\n- Examine variables, memory, and call stack\n- Report the root cause of the crash\n```\n\n**Task 2: Python REPL (python-repl.md)**\n\n```markdown\nStart a Python REPL and complete these steps:\n\n1. Calculate 42 * 17 and verify the result appears\n2. Import math module and calculate math.factorial(10)\n3. Create list comprehension: [x**2 for x in range(10)]\n4. Define a function that checks if a number is prime (enter it line by line with proper indentation)\n5. Test your prime function with the number 97 and report whether it's prime\n6. Exit the REPL cleanly\n\nAfter each input, check the output to confirm your command executed correctly before proceeding to the next step.\n\nFinally, get all the output and summarize the results, including whether 97 is prime.\n```\n\n**Task 3: Project analysis (project-analysis.md)**\n\n````markdown\nStart opencode with the anthropic/claude-sonnet-4-20250514 model, switch to GPT OSS 120B using the /models command, and ask it to analyze the project. You MUST capture the COMPLETE response.\n\n1. Start opencode with the specified model:\n   ```\n   opencode --model anthropic/claude-sonnet-4-20250514\n   ```\n\n2. Once opencode is running, use the /models slash command to switch to GPT OSS 120B:\n   ```\n   /models\n   ```\n   When the models dialog opens, type \"GPT OSS 120B\" to filter the list, then select GPT OSS 120B by pressing enter.\n\n3. After successfully switching models, prompt it to analyze the project:\n   ```\n   Read README.md explain what this project does\n   ```\n\n4. Capture the model's COMPLETE response. This will require scrolling upwards to capture all output using stdout with sufficient lines parameter.\n\n5. Report the full summary provided by the model.\n\nIMPORTANT: If you cannot successfully switch to GPT OSS 120B, the task has failed. Report that the model switching failed and do not proceed with the analysis.\n````\n\n### Example evaluation prompt\n\nHere's what the evaluation framework actually sends to Claude Code when combining a task and tool definition. This is the prompt for the Python REPL task with tmux:\n\n```markdown\n## Task\n\nStart a Python REPL and complete these steps:\n\n1. Calculate 42 * 17 and verify the result appears\n2. Import math module and calculate math.factorial(10)\n3. Create list comprehension: [x**2 for x in range(10)]\n4. Define a function that checks if a number is prime (enter it line by line with proper indentation)\n5. Test your prime function with the number 97 and report whether it's prime\n6. Exit the REPL cleanly\n\nAfter each input, check the output to confirm your command executed correctly before proceeding to the next step.\n\nFinally, get all the output and summarize the results, including whether 97 is prime.\n\n## Tool\n\nYou must use **Tmux** to complete this task.\n\n### Quick Start (Typical Workflow)\n1. `tmux new-session -d -s NAME \"command\" \\; set remain-on-exit on` - Start session\n2. `tmux send-keys -t NAME \"input\" Enter` - Send input\n3. `tmux capture-pane -t NAME -p` - Get current viewport (clean, rendered)\n4. `tmux kill-session -t NAME` - Clean up when done\n\n### Core Commands\n\n- **Start session**: `tmux new-session -d -s NAME \"command args\" \\; set remain-on-exit on`\n  - `-d` detached mode, `-s` session name\n  - **IMPORTANT**: Use `remain-on-exit on` to capture output after process ends\n  - Example: `tmux new-session -d -s repl \"python3 -i\" \\; set remain-on-exit on`\n\n- **List sessions**: `tmux list-sessions` or `tmux ls`\n\n- **Send input**: `tmux send-keys -t NAME \"input\" Enter`\n  - Batch multiple: `tmux send-keys -t NAME \"cmd1\" Enter \"cmd2\" Enter \"cmd3\" Enter`\n  - Special keys: `C-c` (Ctrl+C), `Up`/`Down`/`Right`/`Left` (arrows), `PageUp`/`PageDown`\n  - Example: `tmux send-keys -t repl \"2+2\" Enter`\n  - **Multiline (Python auto-indents)**: `tmux send-keys -t repl \"def greet(name):\" Enter \"return f'Hello {name}'\" Enter Enter`\n\n- **Get output**:\n  - **Current viewport** (RECOMMENDED - clean, rendered view): `tmux capture-pane -t NAME -p`\n  - **Last N lines**: `tmux capture-pane -t NAME -p -S -N`\n  - **Full scrollback**: `tmux capture-pane -t NAME -p -S -`\n\n- **Check if alive**: `tmux list-panes -t NAME -F \"#{pane_dead}\"` (0=alive, 1=dead)\n\n- **Kill session**: `tmux kill-session -t NAME`\n\n### Important Notes\n- **Only kill sessions you started by name**\n- **capture-pane = viewport only**: Shows current screen (clean, rendered), perfect for TUIs/REPLs\n- **capture-pane -S - = full scrollback**: Clean rendered history\n- **remain-on-exit on**: Essential for capturing output after process ends\n- **TIP**: For interactive programs, use capture-pane after operations complete for clean view\n\nYou are free to run `tmux --help` if you require more information on the tool.\n\n## Completion\n\nComplete the task using only the tool specified above.\n- If successful, output: TASK_COMPLETE\n- If unsuccessful, output: TASK_FAILED and explain what went wrong\n```\n\n### Running the evaluation\n\nThe evaluation runs through a simple CLI where I specify which task/tool combinations to test and how many repetitions. The framework generates prompts for each combination, spawns Claude Code via TerminalManager, and monitors execution. If Claude stalls, it gets nudged to continue. Once complete, it captures costs and saves all outputs.\n\nHere's what that looks like:\n\nSince I'm evaluating terminal multiplexers, I can attach to the session and watch what Claude is doing.\n\n### Statistics and judgments\n\nAfter all runs complete, a second CLI command parses the outputs, extracts statistics, and has Claude judge each task/tool combination and rank the tools.\n\n![](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli/media/stats.png)\n\nAll of that gets written to a final evaluation-summary.json file which looks something like this:\n\n```json\n{\n  \"claude-code\": {\n    \"debug-lldb\": {\n      \"judgeNotes\": \"## Tool Comparison for debug-lldb\\n\\n### Rankings\\nRank the tools from best to worst based on:\\n1. Success rate: All tools tied at 100%\\n2. Efficiency (tokens/turns): \\n   - 1st: tmux (avg 0.3729 cost, 1m 28.7s)\\n   - 2nd: terminalcp-cli (avg 0.3865 cost, 1m 37.2s)  \\n   - 3rd: terminalcp (avg 0.4804 cost, 1m 22.2s)\\n   - 4th: screen (avg 0.6003 cost, 1m 46.2s)\\n3. Ease of use:\\n   - 1st: terminalcp\\n   - 2nd: tmux\\n   - 3rd: terminalcp-cli\\n   - 4th: screen\\n4. Overall effectiveness:\\n   - 1st: tmux\\n   - 2nd: terminalcp\\n   - 3rd: terminalcp-cli\\n   - 4th: screen\\n\\n### Best Tool: tmux\\nTmux performed best for this task due to its combination of lowest cost ($0.3729 avg), consistent clean execution, and efficient debugging workflow without unnecessary steps or workarounds.\\n\\n### Tool-by-Tool Analysis\\n- **screen**: Most expensive ($0.6003 avg) and required expect workaround for hardcopy bug, but provided reliable debugging with thorough analysis. Several runs unnecessarily examined source code before debugging, reducing efficiency.\\n- **terminalcp**: Simple and straightforward terminal interface with good efficiency, though some runs included unnecessary file reading. Second fastest average duration at 1m 22.2s despite higher token usage than tmux.\\n- **terminalcp-cli**: CLI-based approach had occasional session management issues (\\\"Process not found\\\" errors) and some inefficient multi-session runs. Middle-tier performance with reasonable cost but longest average duration.\\n- **tmux**: Most efficient with lowest cost and consistent clean execution across all runs. No workarounds needed and minimal unnecessary steps, with only one run setting an unneeded breakpoint.\\n\\n### Key Insights\\nAll tools achieved 100% success rate for this debugging task, showing that terminal multiplexers are reliable for LLDB integration. The main differentiators were efficiency and ease of use, with simpler interfaces (terminalcp, tmux) outperforming more complex ones (screen, terminalcp-cli) in terms of cost and execution time.\\n\\n### Recommendation\\nTmux should be preferred for LLDB debugging tasks due to its lowest cost, fastest average execution time, and cleanest implementation without requiring workarounds or experiencing session management issues.\",\n      \"screen\": {\n        \"judgeNotes\": \"Now I have read all the evaluation files for claude-code using screen on the debug-lldb task. Let me provide my assessment in the required format:\\n\\n## Overall Performance\\nThe agent consistently succeeded in all 10 runs, correctly identifying the NULL pointer dereference crash in the demo-buggy program using LLDB through Screen. Performance was reliable with thorough debugging analysis in each run.\\n\\n## What Went Well\\n- Successfully started LLDB sessions through Screen in all runs\\n- Correctly identified the crash location (demo-buggy.c:26 in add_score function)\\n- Accurately diagnosed the root cause (NULL pointer dereference of scores field)\\n- Properly examined variables, memory, and call stack as requested\\n- Consistently used the expect workaround for Screen's hardcopy bug\\n- Provided detailed technical analysis including memory addresses and variable states\\n- Properly cleaned up Screen sessions after completion\\n\\n## What Went Wrong\\n- Some runs unnecessarily examined the source code files before debugging (runs 3, 4, 8, 9)\\n- Occasional redundant tool calls when examining variables\\n- Minor inconsistency in debugging approach (some set breakpoints, others ran directly)\\n- Some runs were more verbose than necessary in their analysis\\n\\n## Run-by-Run Analysis\\n- Run 20250815220002898000: Pass - Clean execution with efficient debugging and clear root cause analysis\\n- Run 20250815220123424001: Pass - Thorough debugging with proper variable examination and detailed analysis\\n- Run 20250815220303961002: Pass - Good execution but included unnecessary file listing before debugging\\n- Run 20250815220434495003: Pass - Comprehensive analysis but unnecessarily read source code first\\n- Run 20250815220625079004: Pass - Very detailed debugging with breakpoints and step-by-step analysis\\n- Run 20250815220855669005: Pass - Efficient debugging with clear identification of the NULL pointer issue\\n- Run 20250815221016207006: Pass - Good execution with proper variable examination and concise analysis\\n- Run 20250815221141740007: Pass - Clean debugging session with thorough variable inspection\\n- Run 20250815221302275008: Pass - Most comprehensive run with breakpoints and detailed stepping through code\\n- Run 20250815221547848009: Pass - Efficient debugging with proper cleanup and comprehensive final analysis\\n\\n## Recommendations\\nFocus on directly debugging the binary without reading source code first unless specifically needed. Standardize the debugging approach to either use breakpoints consistently or run directly to the crash. Reduce verbosity in analysis while maintaining technical accuracy. Consider batching related debugging commands to reduce the number of tool calls needed.\",\n        \"runs\": [\n          {\n            \"agent\": \"claude-code\",\n            \"task\": \"debug-lldb\",\n            \"tool\": \"screen\",\n            \"timestamp\": \"20250815220002898000\",\n            \"success\": true,\n            \"totalCost\": 0.4039,\n            \"totalDurationWall\": \"1m 19.2s\",\n            \"models\": {\n              \"claude-3-5-haiku\": {\n                \"input\": 34100,\n                \"output\": 679,\n                \"cacheRead\": 0,\n                \"cacheWrite\": 0\n              },\n              \"claude-sonnet\": {\n                \"input\": 108,\n                \"output\": 2100,\n                \"cacheRead\": 637000,\n                \"cacheWrite\": 40300\n              }\n            }\n          },\n          ... 9 more runs ...\n      },\n      \"terminalcp\": {\n        \"judgeNotes\": \"Now I've read all the files as instructed. Let me provide my assessment in the exact format requested:\\n\\n## Overall Performance\\nThe agent successfully completed the LLDB debugging task in all 10 runs, consistently identifying the null pointer dereference crash in the add_score function. Performance was reliable with correct use of the terminalcp tool and appropriate LLDB commands to examine variables, memory, and call stack.\\n\\n## What Went Well\\n- Successfully started LLDB sessions using terminalcp in all runs\\n- Correctly identified the crash location (line 26, add_score function) in every run\\n- Properly examined the Student structure and identified the NULL scores pointer\\n- Used appropriate LLDB commands (run, print, bt, frame select) effectively\\n- Correctly cleaned up sessions with stop command in all runs\\n- Provided accurate root cause analysis identifying NULL pointer dereference\\n- Maintained consistent workflow: start → run → examine → analyze → stop\\n\\n## What Went Wrong\\n- Run 3 and 4 unnecessarily read source files before debugging (Read tool usage)\\n- Some runs used verbose list commands to view source code when not essential\\n- Run 4 stepped through create_student function unnecessarily, making session longer\\n- Minor inconsistencies in session naming (lldb_debug, lldb-debug, debug_session, lldb)\\n- Some runs included excessive detail in final analysis when conciseness would suffice\\n\\n## Run-by-Run Analysis\\n- Run 20250815222127742000: Pass - Clean execution with concise, accurate analysis\\n- Run 20250815222228204001: Pass - Good debugging, noted additional off-by-one bug in calculate_average\\n- Run 20250815222333672002: Pass - Thorough analysis including intentional bug comment discovery\\n- Run 20250815222509136003: Pass - Read source unnecessarily but completed task correctly\\n- Run 20250815222634596004: Pass - Read binary first, used breakpoints and stepping (overcomplicated)\\n- Run 20250815222855081005: Pass - Clean execution with good variable examination\\n- Run 20250815223010524006: Pass - Efficient debugging with clear root cause identification\\n- Run 20250815223125966007: Pass - Good use of list commands to view source context\\n- Run 20250815223251410008: Pass - Multiple list attempts but successfully completed task\\n- Run 20250815223426868009: Pass - Clean, efficient execution with proper analysis\\n\\n## Recommendations\\nFocus on using only LLDB through terminalcp as specified in the task requirements without additional file reading. Maintain consistent session naming conventions. Keep final analysis concise while covering all essential points. Avoid unnecessary stepping through code when the crash information is sufficient for root cause analysis.\",\n        \"runs\": [\n          {\n            \"agent\": \"claude-code\",\n            \"task\": \"debug-lldb\",\n            \"tool\": \"terminalcp\",\n            \"timestamp\": \"20250815222127742000\",\n            \"success\": true,\n            \"totalCost\": 0.3008,\n            \"totalDurationWall\": \"59.2s\",\n            \"models\": {\n              \"claude-3-5-haiku\": {\n                \"input\": 2000,\n                \"output\": 78,\n                \"cacheRead\": 0,\n                \"cacheWrite\": 0\n              },\n              \"claude-sonnet\": {\n                \"input\": 130,\n                \"output\": 1900,\n                \"cacheRead\": 555100,\n                \"cacheWrite\": 27400\n              }\n            }\n          },\n          ... 9 more runs ...\n```\n\nYou may have noticed that the structure would allow for evaluating other coding agents as well. I've started work on that because I'd really like to see how Gemini CLI and OpenCode fare. We'll see if I have time to do that.\n\n## The Results\n\nAfter 120 evaluation runs (3 tasks × 4 tools × 10 repetitions), here's what emerged:\n\nLoading evaluation results...\n\n### Token Usage\n\n### Key Findings\n\n1. **MCP vs CLI truly is a wash**: Both terminalcp MCP and CLI versions achieved 100% success rates. The MCP version was 23% faster (51m vs 66m) and 2.5% cheaper ($19.45 vs $19.95).\n\n2. **Screen completely failed on project analysis**: Screen had 0% success on the project analysis task - it couldn't switch models in OpenCode's TUI. This dropped its overall success rate to 67%.\n\n3. **MCP's hidden advantage: no security checks**: The lower Haiku token usage for terminalcp MCP (35k vs 1.3-2M) reveals that CLI tools trigger Claude Code's [malicious command detection](https://mariozechner.at/posts/2025-08-03-cchistory/#toc_1) on every bash invocation. MCP bypasses this overhead entirely. It also means fewer round trips to Anthropic's servers.\n\n4. **Task complexity determines the winner**: For simpler tasks (LLDB debugging, Python REPL), tmux actually beats terminalcp on cost by 10-22%. But for complex tasks requiring more back-and-forth (project analysis), terminalcp's cleaner output gives it a 39% cost advantage over tmux. Overall totals are close: terminalcp at $19-$20, tmux at $22.\n\n## Reproducing the Results\n\nYou can download the [full evaluation results](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli/media/evaluation-results.zip) if you want to dig into the details. The framework writes out the raw ANSI stream from each run. You can even playback the Claude Code sessions with cat:\n\n### Easy mode: Run individual prompts\n\nJust take any `-prompt.md` file from the evaluation results and feed it into Claude Code. Make sure you have the required tools installed:\n\n- **terminalcp**: Clone repo, run `npm install`, then run Claude Code in the cloned repo dir\n- **tmux**: Install via package manager (`brew install tmux`, `apt-get install tmux`, etc.)\n- **screen**: Usually pre-installed on Linux/macOS\n\n### Full mode: Run the complete evaluation\n\nClone the repo and run the evaluation framework:\n\n```bash\ngit clone https://github.com/badlogic/terminalcp\ncd terminalcp\ngit checkout ac9272ed03a40e4d9666ded80667688b16a7a16a\nnpm install\n\n# Run ALL evaluations (3 tasks × 4 tools × 10 repetitions)\nnpx tsx test/eval/run.ts\n\n# Or run specific combinations\nnpx tsx test/eval/run.ts --agents claude --tasks python-repl --tools tmux --repeat 10\n\n# Generate statistics after runs complete\nnpx tsx test/eval/stats.ts\n```\n\nAvailable options:\n\n- `--agents`: Agent to use (for now just: claude)\n- `--tasks`: Task names (debug-lldb, python-repl, project-analysis) or file paths\n- `--tools`: Tool names (terminalcp, terminalcp-cli, tmux, screen) or file paths\n- `--repeat`: Number of repetitions per combination (default: 1)\n- `--parallel`: Number of parallel evaluations (default: 1)\n\nFor the debug-lldb task you need to have LLDB installed. For the python-repl task, you need to have Python 3+ installed. For the project-analysis task, you need to install [opencode](https://opencode.ai) and you'll need `GROQ_API_KEY` set in your environment as the task uses GPT-OSS 120B through Groq in opencode.\n\n## So, MCP or CLI?\n\nThe answer is, at least for this specific case, it doesn't matter as much as you'd think. What actually matters:\n\n1. **Tool design**: A well-designed, token-efficient tool can beat standard tools. Terminalcp's clean output and simple interface outperformed tmux and screen despite their training data advantage.\n\n2. **Documentation quality**: Clear, concise instructions with examples can perform equally well as being in the training data. The terminalcp tool descriptions were enough to achieve 100% success rates.\n\n3. **Token efficiency**: Both MCP and CLI can be token-efficient if designed well. The problem with many MCPs isn't the protocol - it's that they're badly designed wrappers that dump unnecessary JSON everywhere.\n\nMy takeaway? Maybe instead of arguing about MCP vs CLI, we should start building better tools. The protocol is just plumbing. What matters is whether your tool helps or hinders the agent's ability to complete tasks.\n\nThat said, if you're building a tool from scratch and your users already have a shell tool available, just make a good CLI. It's simpler and more portable. Plus, the output of your CLI can be further filtered and massaged just by piping it into another CLI tool, which can increase token efficiency at the cost of additional instructions. That's not possible with MCPs.\n\nOnce you have a well-designed, token-efficient CLI tool, adding an MCP server on top of it is very straightforward.\n\nThis page respects your privacy by not using cookies or similar technologies and by not collecting any personally identifiable information.\n",
  "authors": [],
  "captured_at": "2026-09-27T19:29:15.293681927+00:00",
  "category": "programming",
  "content_html": "<figure class=\"article-figure\"><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://mariozechner.at/posts/2025-08-15-mcp-vs-cli/media/header.jpg\" alt=\"\" loading=\"eager\" decoding=\"async\" fetchpriority=\"high\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture><figcaption>Terminal tools comparison</figcaption></figure>\n<ul>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_0\">MCPs as thin wrappers</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_1\">Building a CLI and MCP server</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_2\">Designing the evaluation</a>\n<ul>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_3\">Tool definitions</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_4\">Task definitions</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_5\">Example evaluation prompt</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_6\">Running the evaluation</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_7\">Statistics and judgments</a></li>\n</ul>\n</li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_8\">The Results</a>\n<ul>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_9\">Token Usage</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_10\">Key Findings</a></li>\n</ul>\n</li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_11\">Reproducing the Results</a>\n<ul>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_12\">Easy mode: Run individual prompts</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_13\">Full mode: Run the complete evaluation</a></li>\n</ul>\n</li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_14\">So, MCP or CLI?</a></li>\n</ul>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://modelcontextprotocol.io\">MCP servers</a> (MCPs for short) are all the rage. However, practitioners using agentic coding tools are usually skeptical. Many MCPs flood the context window with unnecessary output or offer dozens of tools, degrading your agent's performance by <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://mariozechner.at/posts/2025-06-02-prompts-are-code/#toc_0\">poisoning the context</a>. Many practitioners (myself included) resort to letting coding agents directly call CLI tools instead. But what if we're wrong?</p>\n<h2>MCPs as thin wrappers</h2>\n<p>Just like a lot of meetings could have been emails, a lot of MCPs could have been CLI invocations. For example, there's the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/github/github-mcp-server\">GitHub MCP Server</a>, which reimplements functionality that's already available in the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://cli.github.com/\">GitHub CLI</a>. There's little benefit of using that MCP compared to telling your coding agent to use its shell tool to run the GitHub CLI directly. In fact, most often the GitHub MCP Server will lead to much worse results than just letting the agent run the command line tool directly.</p>\n<p>Another popular choice is <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://context7.com/\">Context7</a>, which provides code snippets to help agents use popular libraries. I found <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://context7.com/libgdx/libgdx\">some of my own libraries</a> in there and the snippets are utterly useless. What works better is having Claude clone the dependency's repository, then let a sub-agent analyze it and generate a concise user manual for the task at hand.</p>\n<p>But it depends on the MCP and available CLI tools. Sometimes there are no easy-to-use CLI tools, making MCPs sensible. Other times CLI tools are too verbose. MCP servers are also the only option for LLM clients without a built-in shell tool. And stateful tools are easier to implement as MCPs than CLIs since MCP servers are stateful by default.</p>\n<p>I wanted to quantify the difference by writing an MCP server and a corresponding CLI that can be used with Claude Code and for which there are equivalent standard CLI tools Claude encountered during training. I then wrote a hacky evaluation framework to assess:</p>\n<ul>\n<li>what costs more</li>\n<li>what takes more time</li>\n<li>which approach has higher success rates</li>\n<li>whether the inherent knowledge about standard tools beats in-context learning about a previously unseen tool</li>\n</ul>\n<h2>Building a CLI and MCP server</h2>\n<p>I started by building a tool that's inherently useful to myself: <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/badlogic/terminalcp/tree/ac9272ed03a40e4d9666ded80667688b16a7a16a\">terminalcp</a>, a (less capable) tmux alternative with an MCP server that lets agents control terminal applications (debuggers, REPLs, vim, htop) like Playwright controls browsers.</p>\n<p>Here's a quick example of terminalcp in action using the CLI version to debug an executable with lldb and observing the session in a second terminal window:</p>\n<p>And here's the terminalcp MCP server version used by Claude Code to debug the same executable with lldb:</p>\n<p>Note how I can attach to the lldb session from another terminal instance and co-debug with Claude.</p>\n<p>You can bore yourself to death by watching the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.youtube.com/live/Pd1kP9WJhEo\">making of the v0 of terminalcp</a> or check out the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/badlogic/terminalcp/tree/ac9272ed03a40e4d9666ded80667688b16a7a16a\">source code</a>. Here's a quick rundown:</p>\n<ul>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/badlogic/terminalcp/blob/ac9272ed03a40e4d9666ded80667688b16a7a16a/src/terminal-manager.ts\">TerminalManager</a> is the core: uses <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/microsoft/node-pty\">node-pty</a> to spawn processes in pseudo terminals and <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://xtermjs.org/\">xterm.js</a> to render ANSI sequences.</li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/badlogic/terminalcp/blob/ac9272ed03a40e4d9666ded80667688b16a7a16a/src/terminal-server.ts\">TerminalServer</a> runs as a persistent daemon, auto-spawned when needed. Talks to clients via Unix socket (works on Windows too, thanks Node.js).</li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/badlogic/terminalcp/blob/ac9272ed03a40e4d9666ded80667688b16a7a16a/src/terminal-client.ts\">TerminalClient</a> handles communication between the MCP/CLI and the server.</li>\n<li>The <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/badlogic/terminalcp/blob/ac9272ed03a40e4d9666ded80667688b16a7a16a/src/mcp-server.ts\">MCP server</a> just forwards LLM tool calls to the terminal server. Dead simple.</li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/badlogic/terminalcp/blob/ac9272ed03a40e4d9666ded80667688b16a7a16a/src/index.ts\">CLI logic</a> I stuffed into index.ts. Parses arguments, handles special keys (up, down, etc.) using tmux-style symbolic key names and control sequences.</li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/badlogic/terminalcp/blob/ac9272ed03a40e4d9666ded80667688b16a7a16a/src/attach-client.ts\">AttachClient</a> lets users attach to running sessions as shown in the videos.</li>\n</ul>\n<p>I tried to keep terminalcp token-efficient. The server replies with plain text, not JSON (in case of the MCP server, that plain text still gets wrapped in JSON-RPC messages, whoop whoop). The MCP server exposes a single <code>terminalcp</code> tool instead of one per command. This is not just voodoo. In an older version of the Claude Code documentation, Anthropic actually mentioned that there's a limit to the number of tools you should expose to the LLM, otherwise it gets confused (I can no longer find that reference). You can also find this <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/anthropics/anthropic-cookbook/blob/main/tool_use/parallel_tools_claude_3_7_sonnet.ipynb\">old Claude Sonnet 3.7 cookbook</a> where they introduce a batch tool so that Claude can call multiple tools in parallel.</p>\n<p>Finally, the commands let you pick only the output you need. <code>stdout</code> can return just the last N lines of the rendered terminal scrollback buffer. <code>stream</code> can strip ANSI codes and return only new output since the last call with <code>since_last</code>. Here are all the commands, both the MCP tool arguments as JSON and the corresponding CLI invocation:</p>\n<pre><code class=\"language-bash\"><span class=\"code-snippet\" data-language=\"Shell\"><span class=\"syntax-source syntax-shell syntax-bash\"><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-begin syntax-shell\">#</span></span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"> start - spawn a process with optional name and working directory</span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\">\n</span><span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">{<span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>action<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span>:</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> <span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>start<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span>, <span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>command<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span>: <span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>python3 -i<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span>, <span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>name<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span>: <span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>repl<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span>, <span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>cwd<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span>: <span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>/home/user<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span></span><span class=\"syntax-meta syntax-function-call syntax-shell\"></span><span class=\"syntax-meta syntax-post-cmd syntax-shell\">}</span>\n<span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">terminalcp</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> start repl <span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>python3 -i<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span></span>\n\n<span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-begin syntax-shell\">#</span></span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"> stop - kill one or all processes</span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\">\n</span><span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">{<span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>action<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span>:</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> <span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>stop<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span>, <span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>id<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span>: <span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>repl<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span></span><span class=\"syntax-meta syntax-function-call syntax-shell\"></span><span class=\"syntax-meta syntax-post-cmd syntax-shell\">}  <span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-begin syntax-shell\">#</span></span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"> or just {&quot;action&quot;: &quot;stop&quot;} for all</span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\">\n</span></span><span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">terminalcp</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> stop repl  <span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-begin syntax-shell\">#</span></span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"> or just terminalcp stop for all</span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\">\n</span></span>\n<span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-begin syntax-shell\">#</span></span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"> stdin - send input to a process</span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\">\n</span><span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">{<span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>action<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span>:</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> <span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>stdin<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span>, <span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>id<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span>: <span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>repl<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span>, <span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>data<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span>: <span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>print(&#39;hello&#39;)\\r<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span></span><span class=\"syntax-meta syntax-function-call syntax-shell\"></span><span class=\"syntax-meta syntax-post-cmd syntax-shell\">}</span>\n<span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">terminalcp</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> stdin repl <span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>print(&#39;hello&#39;)<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span> ::Enter</span>\n\n<span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-begin syntax-shell\">#</span></span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"> stdout - get rendered terminal screen with optional line limit</span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\">\n</span><span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">{<span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>action<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span>:</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> <span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>stdout<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span>, <span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>id<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span>: <span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>repl<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span>, <span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>lines<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span>: 50</span><span class=\"syntax-meta syntax-function-call syntax-shell\"></span><span class=\"syntax-meta syntax-post-cmd syntax-shell\">}</span>\n<span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">terminalcp</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> stdout repl 50</span>\n\n<span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-begin syntax-shell\">#</span></span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"> stream - get raw output, optionally incremental with since_last</span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\">\n</span><span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">{<span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>action<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span>:</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> <span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>stream<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span>, <span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>id<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span>: <span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>repl<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span>, <span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>since_last<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span>: true, <span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>strip_ansi<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span>: false</span><span class=\"syntax-meta syntax-function-call syntax-shell\"></span><span class=\"syntax-meta syntax-post-cmd syntax-shell\">}</span>\n<span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">terminalcp</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> stream repl<span class=\"syntax-variable syntax-parameter syntax-option syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-parameter syntax-shell\"> --</span>since-last</span><span class=\"syntax-variable syntax-parameter syntax-option syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-parameter syntax-shell\"> --</span>no-strip-ansi</span></span>\n\n<span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-begin syntax-shell\">#</span></span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"> list - list all sessions</span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\">\n</span><span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">{<span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>action<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span>:</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> <span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>list<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span></span><span class=\"syntax-meta syntax-function-call syntax-shell\"></span><span class=\"syntax-meta syntax-post-cmd syntax-shell\">}</span>\n<span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">terminalcp</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> ls</span>\n\n<span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-begin syntax-shell\">#</span></span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"> term-size - get terminal dimensions</span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\">\n</span><span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">{<span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>action<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span>:</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> <span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>term-size<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span>, <span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>id<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span>: <span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>repl<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span></span><span class=\"syntax-meta syntax-function-call syntax-shell\"></span><span class=\"syntax-meta syntax-post-cmd syntax-shell\">}</span>\n<span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-begin syntax-shell\">#</span></span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"> Not exposed in CLI</span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\">\n</span>\n<span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-begin syntax-shell\">#</span></span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"> version - check compatibility</span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\">\n</span><span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">{<span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>action<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span>:</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> <span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>version<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span></span><span class=\"syntax-meta syntax-function-call syntax-shell\"></span><span class=\"syntax-meta syntax-post-cmd syntax-shell\">}</span>\n<span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">terminalcp</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> version</span>\n\n<span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-begin syntax-shell\">#</span></span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"> kill-server - shut everything down</span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\">\n</span><span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">{<span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>action<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span>:</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> <span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>kill-server<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span></span><span class=\"syntax-meta syntax-function-call syntax-shell\"></span><span class=\"syntax-meta syntax-post-cmd syntax-shell\">}</span>\n<span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">terminalcp</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> kill-server</span>\n</span></span></code></pre>\n<p>Finally, here's the tool description that the MCP server reports to the MCP client like Claude Code:</p>\n<pre><code class=\"language-markdown\"><span class=\"code-snippet\" data-language=\"Markdown\"><span class=\"syntax-text syntax-html syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-markdown\">Control background processes with virtual terminals. IMPORTANT: Always clean up processes with &quot;stop&quot; action when done.\n\n</span><span class=\"syntax-meta syntax-paragraph syntax-markdown\">Examples:\n  Start dev server: {&quot;action&quot;: &quot;start&quot;, &quot;command&quot;: &quot;npm run dev&quot;, &quot;cwd&quot;: &quot;/path/to/project&quot;}\n  Send text with Enter: {&quot;action&quot;: &quot;stdin&quot;, &quot;id&quot;: &quot;proc-123&quot;, &quot;data&quot;: &quot;npm test\\r&quot;}\n  Send arrow keys: {&quot;action&quot;: &quot;stdin&quot;, &quot;id&quot;: &quot;proc-123&quot;, &quot;data&quot;: &quot;echo hello\\u001b[D\\u001b[D\\u001b[Dhi \\r&quot;}\n  Send Ctrl+C: {&quot;action&quot;: &quot;stdin&quot;, &quot;id&quot;: &quot;proc-123&quot;, &quot;data&quot;: &quot;\\u0003&quot;}\n  Stop process: {&quot;action&quot;: &quot;stop&quot;, &quot;id&quot;: &quot;proc-abc123&quot;}\n  Stop all processes: {&quot;action&quot;: &quot;stop&quot;}\n\n</span>  Get terminal screen: {&quot;action&quot;: &quot;stdout&quot;, &quot;id&quot;: &quot;proc-123&quot;}  # Current view + scrollback\n  Get last 50 lines: {&quot;action&quot;: &quot;stdout&quot;, &quot;id&quot;: &quot;proc-123&quot;, &quot;lines&quot;: 50}\n  Get all output ever: {&quot;action&quot;: &quot;stream&quot;, &quot;id&quot;: &quot;proc-123&quot;}  # From process start\n  Get new output only: {&quot;action&quot;: &quot;stream&quot;, &quot;id&quot;: &quot;proc-123&quot;, &quot;since_last&quot;: true}  # Since last stream call\n\n<span class=\"syntax-meta syntax-paragraph syntax-markdown\">Output modes:\n  stdout: Terminal emulator output - returns the rendered screen as user would see it.\n          Limited to 10K lines scrollback. Best for: interactive tools, TUIs, REPLs, debuggers.\n\n</span>  stream: Raw process output - returns all text the process has written to stdout/stderr.\n<span class=\"syntax-meta syntax-block-level syntax-markdown\"><span class=\"syntax-markup syntax-raw syntax-block syntax-markdown\">          Strips ANSI codes by default (set strip_ansi: false to keep). No limit on history.\n</span></span><span class=\"syntax-meta syntax-block-level syntax-markdown\"><span class=\"syntax-markup syntax-raw syntax-block syntax-markdown\">          With since_last: true, returns only new output since last stream call on this process.\n</span></span><span class=\"syntax-meta syntax-block-level syntax-markdown\"><span class=\"syntax-markup syntax-raw syntax-block syntax-markdown\">          Best for: build logs, test output, monitoring long-running processes.\n</span></span>\n<span class=\"syntax-meta syntax-paragraph syntax-markdown\">Common escape sequences for stdin:\n  Enter: \\r or \\u000d\n  Tab: \\t or \\u0009\n  Escape: \\u001b\n  Backspace: \\u007f\n  Ctrl+C: \\u0003\n  Ctrl+D: \\u0004\n  Ctrl+Z: \\u001a\n\n</span>  Arrow keys: Up=\\u001b[A Down=\\u001b[B Right=\\u001b[C Left=\\u001b[D\n  Navigation: Home=\\u001b[H End=\\u001b[F PageUp=\\u001b[5~ PageDown=\\u001b[6~\n  Delete: \\u001b[3~ Insert: \\u001b[2~\n  Function keys: F1=\\u001bOP F2=\\u001bOQ F3=\\u001bOR F4=\\u001bOS\n  Meta/Alt: Alt+x=\\u001bx (ESC followed by character)\n\n<span class=\"syntax-meta syntax-paragraph syntax-markdown\">Interactive examples:\n  Vim: stdin &quot;vim test.txt\\r&quot; → stdin &quot;iHello\\u001b:wq\\r&quot; → stdout\n  Python: start &quot;python3 -i&quot; → stdin &quot;2+2\\r&quot; → stdout\n  Build monitoring: start &quot;npm run build&quot; → stream (since_last: true) → repeat\n  Interrupt: stdin &quot;sleep 10\\r&quot; → stdin &quot;\\u0003&quot; (Ctrl+C)\n\n</span><span class=\"syntax-meta syntax-paragraph syntax-markdown\">Note: Commands run via bash -c. Use absolute paths, not aliases.\n</span></span></span></code></pre>\n<p>This isn't quite perfect yet. For example, <code>stdin</code> could let you specify a pattern to watch for in the output and wait for it with a timeout, then return the new output. This would save a round trip between client and server. But it works well enough for my evaluation.</p>\n<h2>Designing the evaluation</h2>\n<p>My aim wasn't to create a fully scientific evaluation. For that, you should check out <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://eugeneyan.com/writing/llm-evaluators/\">Eugene Yan's blog</a>, which has fantastic information. I just aim at getting some basic stats with which I can annoy people at a party.</p>\n<p>Here's the bird's eye view: I defined three tasks requiring terminal control (start process, send input, get output) and four tools to test: terminalcp MCP server, terminalcp CLI, tmux, and screen. The <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/badlogic/terminalcp/tree/ac9272ed03a40e4d9666ded80667688b16a7a16a/test/eval/tasks\">task definitions</a> and <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/badlogic/terminalcp/tree/ac9272ed03a40e4d9666ded80667688b16a7a16a/test/eval/tools\">tool definitions</a> are simple markdown files. Tool definitions include some frontmatter that defines how to add them to Claude Code's toolset if necessary, as well as how to clean up after a run that used this tool. These are the inputs to my evaluation framework.</p>\n<p>The super hacky <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/badlogic/terminalcp/tree/ac9272ed03a40e4d9666ded80667688b16a7a16a/test/eval\">evaluation framework</a> works like this:</p>\n<ol>\n<li>\n<p><strong>Run the tests</strong>: For each task and tool combination, the framework spawns a fresh Claude Code instance with a clean config (no custom MCPs, no CLAUDE.md files). Each task/tool combination is run 10 times since LLMs are non-deterministic. The framework combines the task and tool definitions into a single prompt with instructions to output TASK_COMPLETE or TASK_FAILED markers. The Claude Code instance is driven via TerminalManager so the test runner can nudge Claude if it stalls. At the end of each run, it issues <code>/cost</code> to capture time, tokens, and cost.</p>\n</li>\n<li>\n<p><strong>Capture everything</strong>: Each run produces multiple output files:</p>\n<ul>\n<li>The prompt that was sent</li>\n<li>The terminal scrollback buffer (what you'd see on screen)</li>\n<li>The raw ANSI stream (with and without escape codes)</li>\n</ul>\n</li>\n<li>\n<p><strong>Extract statistics</strong>: Parses outputs for success/failure markers, cost, time, and token usage by model.</p>\n</li>\n<li>\n<p><strong>Judge with Claude</strong>: The framework uses Claude Code to judge each task/tool combination, reading outputs and assessing what worked, what failed, and why. It also suggests improvements for the task. In a second pass, Claude ranks all tools for each task with analysis, insights, and recommendations.</p>\n</li>\n</ol>\n<p>The framework can run evaluations in parallel, repeat them multiple times for consistency, and handles cleanup between runs. A full run produces a lot of files.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://mariozechner.at/posts/2025-08-15-mcp-vs-cli/media/mdfiles.png\" alt=\"\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>Which is why I use Claude as a judge to give me some initial insights I can then use to navigate the files for manual analysis.</p>\n<p>Let's have a quick look at the tools and task definitions.</p>\n<h3>Tool definitions</h3>\n<p>I try to make the tool definitions follow the exact same structure, so the comparison is fair. This includes instructions for special keys, multiline input, scrollback handling, and other operations the agent needs to perform with the tool to complete the tasks. The goal is to give each tool equal footing via in-context information.</p>\n<p>The terminalcp MCP server already reports the tool description, so I only added a few more hints. Here's the full definition:</p>\n<pre><code class=\"language-markdown\"><span class=\"code-snippet\" data-language=\"Markdown\"><span class=\"syntax-text syntax-html syntax-markdown\"><span class=\"syntax-meta syntax-block-level syntax-markdown\"><span class=\"syntax-meta syntax-separator syntax-thematic-break syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-thematic-break syntax-markdown\">---</span>\n</span></span><span class=\"syntax-meta syntax-paragraph syntax-markdown\">{\n  &quot;type&quot;: &quot;mcp&quot;,\n  &quot;mcpServers&quot;: {\n    &quot;terminalcp&quot;: {\n      &quot;type&quot;: &quot;stdio&quot;,\n      &quot;command&quot;: &quot;npx&quot;,\n      &quot;args&quot;: [&quot;tsx&quot;, &quot;src/index.ts&quot;, &quot;--mcp&quot;]\n    }\n  }\n}\n<span class=\"syntax-markup syntax-heading syntax-2 syntax-setext syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-heading syntax-setext syntax-markdown\">---</span></span></span>\n\n<span class=\"syntax-meta syntax-block-level syntax-markdown\"><span class=\"syntax-markup syntax-heading syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-heading syntax-begin syntax-markdown\">###</span> </span><span class=\"syntax-markup syntax-heading syntax-markdown\"><span class=\"syntax-entity syntax-name syntax-section syntax-markdown\">Quick Start (Typical Workflow)</span><span class=\"syntax-meta syntax-whitespace syntax-newline syntax-markdown\">\n</span></span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">1<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\">Start session: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>{&quot;action&quot;: &quot;start&quot;, &quot;command&quot;: &quot;command args&quot;, &quot;name&quot;: &quot;NAME&quot;}<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">2<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> Send input: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>{&quot;action&quot;: &quot;stdin&quot;, &quot;id&quot;: &quot;NAME&quot;, &quot;data&quot;: &quot;input\\r&quot;}<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">3<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> Get current viewport: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>{&quot;action&quot;: &quot;stdout&quot;, &quot;id&quot;: &quot;NAME&quot;}<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">4<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> Clean up: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>{&quot;action&quot;: &quot;stop&quot;, &quot;id&quot;: &quot;NAME&quot;}<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\">\n</span><span class=\"syntax-meta syntax-block-level syntax-markdown\"><span class=\"syntax-markup syntax-heading syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-heading syntax-begin syntax-markdown\">###</span> </span><span class=\"syntax-markup syntax-heading syntax-markdown\"><span class=\"syntax-entity syntax-name syntax-section syntax-markdown\">Important Notes</span><span class=\"syntax-meta syntax-whitespace syntax-newline syntax-markdown\">\n</span></span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"><span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Only stop sessions you started by name<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>stdout = viewport + scrollback<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: Shows clean rendered terminal\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>stdout with lines<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>{&quot;action&quot;: &quot;stdout&quot;, &quot;id&quot;: &quot;NAME&quot;, &quot;lines&quot;: N}<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> for last N lines\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>stream = raw output<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: Contains all output since start (avoid for TUIs)\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> Use <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>\\r<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> for Enter, <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>\\u001b[A/B/C/D<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> for arrows, <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>\\u0003<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> for Ctrl+C\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>TIP<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: For interactive programs, use stdout after operations complete for clean view\n</span></span></span></span></code></pre>\n<p>The terminalcp CLI tool definition is bigger since I need to explain the command syntax:</p>\n<pre><code class=\"language-markdown\"><span class=\"code-snippet\" data-language=\"Markdown\"><span class=\"syntax-text syntax-html syntax-markdown\"><span class=\"syntax-meta syntax-block-level syntax-markdown\"><span class=\"syntax-meta syntax-separator syntax-thematic-break syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-thematic-break syntax-markdown\">---</span>\n</span></span><span class=\"syntax-meta syntax-paragraph syntax-markdown\">{\n  &quot;type&quot;: &quot;cli&quot;,\n  &quot;cleanup&quot;: &quot;npx tsx src/index.ts stop || true&quot;\n}\n<span class=\"syntax-markup syntax-heading syntax-2 syntax-setext syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-heading syntax-setext syntax-markdown\">---</span></span></span>\n\n<span class=\"syntax-meta syntax-block-level syntax-markdown\"><span class=\"syntax-markup syntax-heading syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-heading syntax-begin syntax-markdown\">###</span> </span><span class=\"syntax-markup syntax-heading syntax-markdown\"><span class=\"syntax-entity syntax-name syntax-section syntax-markdown\">Quick Start (Typical Workflow)</span><span class=\"syntax-meta syntax-whitespace syntax-newline syntax-markdown\">\n</span></span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">1<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"><span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>npx tsx src/index.ts start NAME command args<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> - Start session\n</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">2<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>npx tsx src/index.ts stdin NAME &quot;input&quot; ::Enter<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> - Send input\n</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">3<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>npx tsx src/index.ts stdout NAME<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> - Get current viewport (clean, rendered)\n</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">4<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>npx tsx src/index.ts stop NAME<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> - Clean up when done\n</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\">\n</span><span class=\"syntax-meta syntax-block-level syntax-markdown\"><span class=\"syntax-markup syntax-heading syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-heading syntax-begin syntax-markdown\">###</span> </span><span class=\"syntax-markup syntax-heading syntax-markdown\"><span class=\"syntax-entity syntax-name syntax-section syntax-markdown\">Core Commands</span><span class=\"syntax-meta syntax-whitespace syntax-newline syntax-markdown\">\n</span></span></span>\n<span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"><span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Start session<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>npx tsx src/index.ts start NAME command args<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> Returns session ID (the NAME you provided)\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> Example: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>npx tsx src/index.ts start repl python3 -i<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">\n</span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"><span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>List sessions<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>npx tsx src/index.ts ls<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> Shows: ID, status (running/stopped), working directory, command\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">\n</span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"><span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Send input<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>npx tsx src/index.ts stdin NAME &quot;input&quot; ::Enter<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> Batch multiple: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>npx tsx src/index.ts stdin NAME &quot;cmd1&quot; ::Enter &quot;cmd2&quot; ::Enter &quot;cmd3&quot; ::Enter<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> Special keys: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>::C-c<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> (Ctrl+C), <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>::Up<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>/<span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>::Down<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>/<span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>::Right<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>/<span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>::Left<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> (arrows), <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>::PageUp<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>/<span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>::PageDown<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> Example: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>npx tsx src/index.ts stdin repl &quot;2+2&quot; ::Enter<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Multiline (Python auto-indents)<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>npx tsx src/index.ts stdin repl &quot;def greet(name):&quot; ::Enter &quot;return f&#39;Hello {name}&#39;&quot; ::Enter ::Enter<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">\n</span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"><span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Get output<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>:\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Current viewport<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span> (RECOMMENDED - clean, rendered view): <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>npx tsx src/index.ts stdout NAME<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Last N lines<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>npx tsx src/index.ts stdout NAME N<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Full scrollback<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>npx tsx src/index.ts stdout NAME 10000<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> (up to 10,000 lines max)\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">\n</span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"><span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Stop session<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>npx tsx src/index.ts stop NAME<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span>\n</span><span class=\"syntax-meta syntax-block-level syntax-markdown\"><span class=\"syntax-markup syntax-heading syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-heading syntax-begin syntax-markdown\">###</span> </span><span class=\"syntax-markup syntax-heading syntax-markdown\"><span class=\"syntax-entity syntax-name syntax-section syntax-markdown\">Important Notes</span><span class=\"syntax-meta syntax-whitespace syntax-newline syntax-markdown\">\n</span></span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"><span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Only stop sessions you started by name<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>stdout = viewport + scrollback<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: Shows clean rendered terminal (up to 10,000 lines)\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>stdout N = last N lines<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: Efficient for checking recent output\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>TIP<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: For interactive programs, use stdout after operations complete for clean view\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">\n</span><span class=\"syntax-meta syntax-paragraph syntax-markdown\">You are free to run <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>npx tsx src/index.ts --help<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> if you require more information on the tool.\n</span></span></span></code></pre>\n<p>The tmux tool definition follows the same structure, mapping each terminalcp operation to its tmux equivalent:</p>\n<pre><code class=\"language-markdown\"><span class=\"code-snippet\" data-language=\"Markdown\"><span class=\"syntax-text syntax-html syntax-markdown\"><span class=\"syntax-meta syntax-block-level syntax-markdown\"><span class=\"syntax-meta syntax-separator syntax-thematic-break syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-thematic-break syntax-markdown\">---</span>\n</span></span><span class=\"syntax-meta syntax-paragraph syntax-markdown\">{\n  &quot;type&quot;: &quot;cli&quot;,\n  &quot;cleanup&quot;: &quot;tmux kill-server || true&quot;\n}\n<span class=\"syntax-markup syntax-heading syntax-2 syntax-setext syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-heading syntax-setext syntax-markdown\">---</span></span></span>\n\n<span class=\"syntax-meta syntax-block-level syntax-markdown\"><span class=\"syntax-markup syntax-heading syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-heading syntax-begin syntax-markdown\">###</span> </span><span class=\"syntax-markup syntax-heading syntax-markdown\"><span class=\"syntax-entity syntax-name syntax-section syntax-markdown\">Quick Start (Typical Workflow)</span><span class=\"syntax-meta syntax-whitespace syntax-newline syntax-markdown\">\n</span></span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">1<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"><span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>tmux new-session -d -s NAME &quot;command&quot; \\; set remain-on-exit on<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> - Start session\n</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">2<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>tmux send-keys -t NAME &quot;input&quot; Enter<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> - Send input\n</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">3<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>tmux capture-pane -t NAME -p<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> - Get current viewport (clean, rendered)\n</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">4<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>tmux kill-session -t NAME<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> - Clean up when done\n</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\">\n</span><span class=\"syntax-meta syntax-block-level syntax-markdown\"><span class=\"syntax-markup syntax-heading syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-heading syntax-begin syntax-markdown\">###</span> </span><span class=\"syntax-markup syntax-heading syntax-markdown\"><span class=\"syntax-entity syntax-name syntax-section syntax-markdown\">Core Commands</span><span class=\"syntax-meta syntax-whitespace syntax-newline syntax-markdown\">\n</span></span></span>\n<span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"><span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Start session<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>tmux new-session -d -s NAME &quot;command args&quot; \\; set remain-on-exit on<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>-d<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> detached mode, <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>-s<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> session name\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>IMPORTANT<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: Use <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>remain-on-exit on<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> to capture output after process ends\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> Example: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>tmux new-session -d -s repl &quot;python3 -i&quot; \\; set remain-on-exit on<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">\n</span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"><span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>List sessions<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>tmux list-sessions<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> or <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>tmux ls<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span>\n</span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"><span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Send input<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>tmux send-keys -t NAME &quot;input&quot; Enter<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> Batch multiple: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>tmux send-keys -t NAME &quot;cmd1&quot; Enter &quot;cmd2&quot; Enter &quot;cmd3&quot; Enter<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> Special keys: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>C-c<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> (Ctrl+C), <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>Up<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>/<span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>Down<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>/<span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>Right<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>/<span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>Left<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> (arrows), <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>PageUp<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>/<span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>PageDown<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> Example: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>tmux send-keys -t repl &quot;2+2&quot; Enter<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Multiline (Python auto-indents)<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>tmux send-keys -t repl &quot;def greet(name):&quot; Enter &quot;return f&#39;Hello {name}&#39;&quot; Enter Enter<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">\n</span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"><span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Get output<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>:\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Current viewport<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span> (RECOMMENDED - clean, rendered view): <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>tmux capture-pane -t NAME -p<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Last N lines<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>tmux capture-pane -t NAME -p -S -N<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Full scrollback<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>tmux capture-pane -t NAME -p -S -<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">\n</span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"><span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Check if alive<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>tmux list-panes -t NAME -F &quot;#{pane_dead}&quot;<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> (0=alive, 1=dead)\n</span>\n</span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"><span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Kill session<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>tmux kill-session -t NAME<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span>\n</span><span class=\"syntax-meta syntax-block-level syntax-markdown\"><span class=\"syntax-markup syntax-heading syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-heading syntax-begin syntax-markdown\">###</span> </span><span class=\"syntax-markup syntax-heading syntax-markdown\"><span class=\"syntax-entity syntax-name syntax-section syntax-markdown\">Important Notes</span><span class=\"syntax-meta syntax-whitespace syntax-newline syntax-markdown\">\n</span></span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"><span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Only kill sessions you started by name<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>capture-pane = viewport only<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: Shows current screen (clean, rendered), perfect for TUIs/REPLs\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>capture-pane -S - = full scrollback<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: Clean rendered history\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>remain-on-exit on<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: Essential for capturing output after process ends\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>TIP<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: For interactive programs, use capture-pane after operations complete for clean view\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">\n</span><span class=\"syntax-meta syntax-paragraph syntax-markdown\">You are free to run <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>tmux --help<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> if you require more information on the tool.\n</span></span></span></code></pre>\n<p>The screen tool definition follows the same pattern, except there's a bug in screen v4.0.3 that requires a one-time workaround command to enable hardcopy:</p>\n<pre><code class=\"language-markdown\"><span class=\"code-snippet\" data-language=\"Markdown\"><span class=\"syntax-text syntax-html syntax-markdown\"><span class=\"syntax-meta syntax-block-level syntax-markdown\"><span class=\"syntax-meta syntax-separator syntax-thematic-break syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-thematic-break syntax-markdown\">---</span>\n</span></span><span class=\"syntax-meta syntax-paragraph syntax-markdown\">{\n  &quot;type&quot;: &quot;cli&quot;,\n  &quot;cleanup&quot;: &quot;for session in $(screen -ls | grep -o \\&quot;[0-9]<span class=\"syntax-markup syntax-italic syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-italic syntax-begin syntax-markdown\">*</span><span class=\"syntax-constant syntax-character syntax-escape syntax-markdown\">\\\\</span><span class=\"syntax-constant syntax-character syntax-escape syntax-markdown\">\\\\</span>.[^ ]<span class=\"syntax-punctuation syntax-definition syntax-italic syntax-end syntax-markdown\">*</span></span>\\&quot;); do screen -S \\&quot;$session\\&quot; -X quit; done || true&quot;\n}\n<span class=\"syntax-markup syntax-heading syntax-2 syntax-setext syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-heading syntax-setext syntax-markdown\">---</span></span></span>\n\n<span class=\"syntax-meta syntax-block-level syntax-markdown\"><span class=\"syntax-markup syntax-heading syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-heading syntax-begin syntax-markdown\">###</span> </span><span class=\"syntax-markup syntax-heading syntax-markdown\"><span class=\"syntax-entity syntax-name syntax-section syntax-markdown\">Quick Start (Typical Workflow)</span><span class=\"syntax-meta syntax-whitespace syntax-newline syntax-markdown\">\n</span></span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">1<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"><span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>rm -f screenlog.0 &amp;&amp; screen -dmS NAME -L command args<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> - Start session\n</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">2<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>expect -c &#39;spawn screen -r NAME; send &quot;\\001d&quot;; expect eof&#39; &gt;/dev/null 2&gt;&amp;1<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> - Enable hardcopy (once per session)\n</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">3<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>screen -S NAME -X stuff $&#39;input\\n&#39;<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> - Send input\n</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">4<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>screen -S NAME -p 0 -X hardcopy output.txt &amp;&amp; cat output.txt<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> - Get current viewport (clean, rendered)\n</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">5<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>screen -S NAME -X quit<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> - Clean up when done\n</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\">\n</span><span class=\"syntax-meta syntax-block-level syntax-markdown\"><span class=\"syntax-markup syntax-heading syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-heading syntax-begin syntax-markdown\">###</span> </span><span class=\"syntax-markup syntax-heading syntax-markdown\"><span class=\"syntax-entity syntax-name syntax-section syntax-markdown\">Core Commands</span><span class=\"syntax-meta syntax-whitespace syntax-newline syntax-markdown\">\n</span></span></span>\n<span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"><span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Start session<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>screen -dmS NAME -L program args<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>-d<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> detached mode, <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>-m<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> force new session, <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>-S<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> session name, <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>-L<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> enable logging\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>IMPORTANT<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: Remove old <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>screenlog.0<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> first: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>rm -f screenlog.0<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> Example: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>rm -f screenlog.0 &amp;&amp; screen -dmS repl -L python3 -i<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">\n</span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"><span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>List sessions<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>screen -ls<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span>\n</span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"><span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Send input<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>screen -S NAME -X stuff $&#39;input\\n&#39;<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> REQUIRED: Use $&#39;...&#39; syntax for proper escape sequences\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> Batch multiple: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>screen -S NAME -X stuff $&#39;cmd1\\ncmd2\\ncmd3\\n&#39;<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> Special keys: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>$&#39;\\003&#39;<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> (Ctrl+C), <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>$&#39;\\e[A]&#39;/<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>$&#39;\\e[B]&#39;/<span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>$&#39;\\e[C]&#39;/<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>$&#39;\\e[D]&#39;<span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span> (Up/Down/Right/Left arrows)\n  - Example: <span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>screen -S repl -X stuff $&#39;2+2\\n&#39;<span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>\n  - **Multiline (Python auto-indents)**: <span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>screen -S repl -X stuff $&#39;def greet(name):\\nreturn f\\&#39;Hello {name}\\&#39;\\n\\n&#39;<span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>\n<span class=\"syntax-invalid syntax-illegal syntax-non-terminated syntax-raw syntax-markdown\">\n</span></span></span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Get output<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>:\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Current viewport<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span> (RECOMMENDED - clean, rendered view):\n    <span class=\"syntax-markup syntax-raw syntax-code-fence syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-code-fence syntax-begin syntax-markdown\">```</span><span class=\"syntax-constant syntax-other syntax-language-name syntax-markdown\">bash</span>\n    # First time per session (v4.0.3 bug workaround):\n    expect -c &#39;spawn screen -r NAME; send &quot;\\001d&quot;; expect eof&#39; &gt;/dev/null 2&gt;&amp;1\n    # Then use hardcopy normally:\n    screen -S NAME -p 0 -X hardcopy output.txt &amp;&amp; cat output.txt\n <span class=\"syntax-punctuation syntax-definition syntax-raw syntax-code-fence syntax-end syntax-markdown\">   ```\n</span></span></span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Last N lines<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span> (raw with ANSI codes): <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>tail -N screenlog.0<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Full scrollback<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span> (raw with ANSI codes): <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>cat screenlog.0<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">\n</span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"><span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Kill session<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>screen -S NAME -X quit<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span>\n</span><span class=\"syntax-meta syntax-block-level syntax-markdown\"><span class=\"syntax-markup syntax-heading syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-heading syntax-begin syntax-markdown\">###</span> </span><span class=\"syntax-markup syntax-heading syntax-markdown\"><span class=\"syntax-entity syntax-name syntax-section syntax-markdown\">Important Notes</span><span class=\"syntax-meta syntax-whitespace syntax-newline syntax-markdown\">\n</span></span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"><span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Only kill sessions you started by name<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>hardcopy = viewport only<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: Shows current screen (clean, rendered), perfect for TUIs/REPLs\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>screenlog.0 = full raw output<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: Contains all ANSI codes since session start\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>v4.0.3 hardcopy bug<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: Run expect workaround once per session\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>TIP<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: For interactive programs, use hardcopy after operations complete for clean view\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">\n</span><span class=\"syntax-meta syntax-paragraph syntax-markdown\">You are free to run <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>screen --help<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> if you require more information on the tool.\n</span></span></span></code></pre>\n<h3>Task definitions</h3>\n<p>I created three tasks that exercise different aspects of terminal control. They should speak for themselves. Probably the most interesting one is the project analysis task where the agent needs to command OpenCode and navigate its TUI.</p>\n<p><strong>Task 1: Debug with LLDB (debug-lldb.md)</strong></p>\n<pre><code class=\"language-markdown\"><span class=\"code-snippet\" data-language=\"Markdown\"><span class=\"syntax-text syntax-html syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-markdown\">The program <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>evaluation-results/demo-buggy<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> crashes when executed. Use LLDB to:\n</span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\">Start the program under the debugger\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> Identify where and why it crashes\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> Examine variables, memory, and call stack\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> Report the root cause of the crash\n</span></span></span></span></code></pre>\n<p><strong>Task 2: Python REPL (python-repl.md)</strong></p>\n<pre><code class=\"language-markdown\"><span class=\"code-snippet\" data-language=\"Markdown\"><span class=\"syntax-text syntax-html syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-markdown\">Start a Python REPL and complete these steps:\n\n</span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">1<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\">Calculate 42 * 17 and verify the result appears\n</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">2<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> Import math module and calculate math.factorial(10)\n</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">3<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> Create list comprehension: [x<span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>2 for x in range(10)]\n</span></span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">4<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> Define a function that checks if a number is prime (enter it line by line with proper indentation)\n</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">5<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> Test your prime function with the number 97 and report whether it&#39;s prime\n</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">6<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> Exit the REPL cleanly\n</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\">\n</span><span class=\"syntax-meta syntax-paragraph syntax-markdown\">After each input, check the output to confirm your command executed correctly before proceeding to the next step.\n\n</span><span class=\"syntax-meta syntax-paragraph syntax-markdown\">Finally, get all the output and summarize the results, including whether 97 is prime.\n</span></span></span></code></pre>\n<p><strong>Task 3: Project analysis (project-analysis.md)</strong></p>\n<pre><code class=\"language-markdown\"><span class=\"code-snippet\" data-language=\"Markdown\"><span class=\"syntax-text syntax-html syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-markdown\">Start opencode with the anthropic/claude-sonnet-4-20250514 model, switch to GPT OSS 120B using the /models command, and ask it to analyze the project. You MUST capture the COMPLETE response.\n\n</span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">1<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\">Start opencode with the specified model:\n   <span class=\"syntax-markup syntax-raw syntax-code-fence syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-code-fence syntax-begin syntax-markdown\">```</span>\n   opencode --model anthropic/claude-sonnet-4-20250514\n<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-code-fence syntax-end syntax-markdown\">   ```\n</span></span></span>\n</span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">2<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\">Once opencode is running, use the /models slash command to switch to GPT OSS 120B:\n   <span class=\"syntax-markup syntax-raw syntax-code-fence syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-code-fence syntax-begin syntax-markdown\">```</span>\n   /models\n<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-code-fence syntax-end syntax-markdown\">   ```\n</span></span></span><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\">   </span><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\">When the models dialog opens, type &quot;GPT OSS 120B&quot; to filter the list, then select GPT OSS 120B by pressing enter.\n</span>\n</span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">3<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\">After successfully switching models, prompt it to analyze the project:\n   <span class=\"syntax-markup syntax-raw syntax-code-fence syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-code-fence syntax-begin syntax-markdown\">```</span>\n   Read README.md explain what this project does\n<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-code-fence syntax-end syntax-markdown\">   ```\n</span></span></span>\n</span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">4<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\">Capture the model&#39;s COMPLETE response. This will require scrolling upwards to capture all output using stdout with sufficient lines parameter.\n</span>\n</span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">5<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\">Report the full summary provided by the model.\n</span>\n</span><span class=\"syntax-meta syntax-paragraph syntax-markdown\">IMPORTANT: If you cannot successfully switch to GPT OSS 120B, the task has failed. Report that the model switching failed and do not proceed with the analysis.\n</span></span></span></code></pre>\n<h3>Example evaluation prompt</h3>\n<p>Here's what the evaluation framework actually sends to Claude Code when combining a task and tool definition. This is the prompt for the Python REPL task with tmux:</p>\n<pre><code class=\"language-markdown\"><span class=\"code-snippet\" data-language=\"Markdown\"><span class=\"syntax-text syntax-html syntax-markdown\"><span class=\"syntax-meta syntax-block-level syntax-markdown\"><span class=\"syntax-markup syntax-heading syntax-2 syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-heading syntax-begin syntax-markdown\">##</span> </span><span class=\"syntax-markup syntax-heading syntax-2 syntax-markdown\"><span class=\"syntax-entity syntax-name syntax-section syntax-markdown\">Task</span><span class=\"syntax-meta syntax-whitespace syntax-newline syntax-markdown\">\n</span></span></span>\n<span class=\"syntax-meta syntax-paragraph syntax-markdown\">Start a Python REPL and complete these steps:\n\n</span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">1<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\">Calculate 42 * 17 and verify the result appears\n</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">2<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> Import math module and calculate math.factorial(10)\n</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">3<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> Create list comprehension: [x<span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>2 for x in range(10)]\n</span></span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">4<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> Define a function that checks if a number is prime (enter it line by line with proper indentation)\n</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">5<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> Test your prime function with the number 97 and report whether it&#39;s prime\n</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">6<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> Exit the REPL cleanly\n</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\">\n</span><span class=\"syntax-meta syntax-paragraph syntax-markdown\">After each input, check the output to confirm your command executed correctly before proceeding to the next step.\n\n</span><span class=\"syntax-meta syntax-paragraph syntax-markdown\">Finally, get all the output and summarize the results, including whether 97 is prime.\n\n</span><span class=\"syntax-meta syntax-block-level syntax-markdown\"><span class=\"syntax-markup syntax-heading syntax-2 syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-heading syntax-begin syntax-markdown\">##</span> </span><span class=\"syntax-markup syntax-heading syntax-2 syntax-markdown\"><span class=\"syntax-entity syntax-name syntax-section syntax-markdown\">Tool</span><span class=\"syntax-meta syntax-whitespace syntax-newline syntax-markdown\">\n</span></span></span>\n<span class=\"syntax-meta syntax-paragraph syntax-markdown\">You must use <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Tmux<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span> to complete this task.\n\n</span><span class=\"syntax-meta syntax-block-level syntax-markdown\"><span class=\"syntax-markup syntax-heading syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-heading syntax-begin syntax-markdown\">###</span> </span><span class=\"syntax-markup syntax-heading syntax-markdown\"><span class=\"syntax-entity syntax-name syntax-section syntax-markdown\">Quick Start (Typical Workflow)</span><span class=\"syntax-meta syntax-whitespace syntax-newline syntax-markdown\">\n</span></span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">1<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"><span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>tmux new-session -d -s NAME &quot;command&quot; \\; set remain-on-exit on<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> - Start session\n</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">2<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>tmux send-keys -t NAME &quot;input&quot; Enter<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> - Send input\n</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">3<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>tmux capture-pane -t NAME -p<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> - Get current viewport (clean, rendered)\n</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-bullet syntax-markdown\">4<span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">.</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>tmux kill-session -t NAME<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> - Clean up when done\n</span></span><span class=\"syntax-markup syntax-list syntax-numbered syntax-markdown\">\n</span><span class=\"syntax-meta syntax-block-level syntax-markdown\"><span class=\"syntax-markup syntax-heading syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-heading syntax-begin syntax-markdown\">###</span> </span><span class=\"syntax-markup syntax-heading syntax-markdown\"><span class=\"syntax-entity syntax-name syntax-section syntax-markdown\">Core Commands</span><span class=\"syntax-meta syntax-whitespace syntax-newline syntax-markdown\">\n</span></span></span>\n<span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"><span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Start session<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>tmux new-session -d -s NAME &quot;command args&quot; \\; set remain-on-exit on<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>-d<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> detached mode, <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>-s<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> session name\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>IMPORTANT<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: Use <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>remain-on-exit on<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> to capture output after process ends\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> Example: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>tmux new-session -d -s repl &quot;python3 -i&quot; \\; set remain-on-exit on<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">\n</span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"><span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>List sessions<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>tmux list-sessions<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> or <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>tmux ls<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span>\n</span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"><span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Send input<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>tmux send-keys -t NAME &quot;input&quot; Enter<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> Batch multiple: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>tmux send-keys -t NAME &quot;cmd1&quot; Enter &quot;cmd2&quot; Enter &quot;cmd3&quot; Enter<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> Special keys: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>C-c<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> (Ctrl+C), <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>Up<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>/<span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>Down<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>/<span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>Right<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>/<span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>Left<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> (arrows), <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>PageUp<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>/<span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>PageDown<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> Example: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>tmux send-keys -t repl &quot;2+2&quot; Enter<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Multiline (Python auto-indents)<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>tmux send-keys -t repl &quot;def greet(name):&quot; Enter &quot;return f&#39;Hello {name}&#39;&quot; Enter Enter<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">\n</span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"><span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Get output<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>:\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Current viewport<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span> (RECOMMENDED - clean, rendered view): <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>tmux capture-pane -t NAME -p<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Last N lines<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>tmux capture-pane -t NAME -p -S -N<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">  </span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Full scrollback<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>tmux capture-pane -t NAME -p -S -<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">\n</span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"><span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Check if alive<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>tmux list-panes -t NAME -F &quot;#{pane_dead}&quot;<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> (0=alive, 1=dead)\n</span>\n</span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"><span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Kill session<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>tmux kill-session -t NAME<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span>\n</span>\n</span><span class=\"syntax-meta syntax-block-level syntax-markdown\"><span class=\"syntax-markup syntax-heading syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-heading syntax-begin syntax-markdown\">###</span> </span><span class=\"syntax-markup syntax-heading syntax-markdown\"><span class=\"syntax-entity syntax-name syntax-section syntax-markdown\">Important Notes</span><span class=\"syntax-meta syntax-whitespace syntax-newline syntax-markdown\">\n</span></span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"><span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>Only kill sessions you started by name<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>capture-pane = viewport only<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: Shows current screen (clean, rendered), perfect for TUIs/REPLs\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>capture-pane -S - = full scrollback<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: Clean rendered history\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>remain-on-exit on<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: Essential for capturing output after process ends\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> <span class=\"syntax-markup syntax-bold syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-bold syntax-begin syntax-markdown\">**</span>TIP<span class=\"syntax-punctuation syntax-definition syntax-bold syntax-end syntax-markdown\">**</span></span>: For interactive programs, use capture-pane after operations complete for clean view\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\">\n</span><span class=\"syntax-meta syntax-paragraph syntax-markdown\">You are free to run <span class=\"syntax-markup syntax-raw syntax-inline syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-raw syntax-begin syntax-markdown\">`</span>tmux --help<span class=\"syntax-punctuation syntax-definition syntax-raw syntax-end syntax-markdown\">`</span></span> if you require more information on the tool.\n\n</span><span class=\"syntax-meta syntax-block-level syntax-markdown\"><span class=\"syntax-markup syntax-heading syntax-2 syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-heading syntax-begin syntax-markdown\">##</span> </span><span class=\"syntax-markup syntax-heading syntax-2 syntax-markdown\"><span class=\"syntax-entity syntax-name syntax-section syntax-markdown\">Completion</span><span class=\"syntax-meta syntax-whitespace syntax-newline syntax-markdown\">\n</span></span></span>\n<span class=\"syntax-meta syntax-paragraph syntax-markdown\">Complete the task using only the tool specified above.\n</span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"> <span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\">If successful, output: TASK_COMPLETE\n</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-bullet syntax-markdown\"><span class=\"syntax-punctuation syntax-definition syntax-list_item syntax-markdown\">-</span></span><span class=\"syntax-markup syntax-list syntax-unnumbered syntax-markdown\"><span class=\"syntax-meta syntax-paragraph syntax-list syntax-markdown\"> If unsuccessful, output: TASK_FAILED and explain what went wrong\n</span></span></span></span></code></pre>\n<h3>Running the evaluation</h3>\n<p>The evaluation runs through a simple CLI where I specify which task/tool combinations to test and how many repetitions. The framework generates prompts for each combination, spawns Claude Code via TerminalManager, and monitors execution. If Claude stalls, it gets nudged to continue. Once complete, it captures costs and saves all outputs.</p>\n<p>Here's what that looks like:</p>\n<p>Since I'm evaluating terminal multiplexers, I can attach to the session and watch what Claude is doing.</p>\n<h3>Statistics and judgments</h3>\n<p>After all runs complete, a second CLI command parses the outputs, extracts statistics, and has Claude judge each task/tool combination and rank the tools.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://mariozechner.at/posts/2025-08-15-mcp-vs-cli/media/stats.png\" alt=\"\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>All of that gets written to a final evaluation-summary.json file which looks something like this:</p>\n<pre><code class=\"language-json\"><span class=\"code-snippet\" data-language=\"JSON\">{\n  &quot;claude-code&quot;: {\n    &quot;debug-lldb&quot;: {\n      &quot;judgeNotes&quot;: &quot;## Tool Comparison for debug-lldb\\n\\n### Rankings\\nRank the tools from best to worst based on:\\n1. Success rate: All tools tied at 100%\\n2. Efficiency (tokens/turns): \\n   - 1st: tmux (avg 0.3729 cost, 1m 28.7s)\\n   - 2nd: terminalcp-cli (avg 0.3865 cost, 1m 37.2s)  \\n   - 3rd: terminalcp (avg 0.4804 cost, 1m 22.2s)\\n   - 4th: screen (avg 0.6003 cost, 1m 46.2s)\\n3. Ease of use:\\n   - 1st: terminalcp\\n   - 2nd: tmux\\n   - 3rd: terminalcp-cli\\n   - 4th: screen\\n4. Overall effectiveness:\\n   - 1st: tmux\\n   - 2nd: terminalcp\\n   - 3rd: terminalcp-cli\\n   - 4th: screen\\n\\n### Best Tool: tmux\\nTmux performed best for this task due to its combination of lowest cost ($0.3729 avg), consistent clean execution, and efficient debugging workflow without unnecessary steps or workarounds.\\n\\n### Tool-by-Tool Analysis\\n- **screen**: Most expensive ($0.6003 avg) and required expect workaround for hardcopy bug, but provided reliable debugging with thorough analysis. Several runs unnecessarily examined source code before debugging, reducing efficiency.\\n- **terminalcp**: Simple and straightforward terminal interface with good efficiency, though some runs included unnecessary file reading. Second fastest average duration at 1m 22.2s despite higher token usage than tmux.\\n- **terminalcp-cli**: CLI-based approach had occasional session management issues (\\&quot;Process not found\\&quot; errors) and some inefficient multi-session runs. Middle-tier performance with reasonable cost but longest average duration.\\n- **tmux**: Most efficient with lowest cost and consistent clean execution across all runs. No workarounds needed and minimal unnecessary steps, with only one run setting an unneeded breakpoint.\\n\\n### Key Insights\\nAll tools achieved 100% success rate for this debugging task, showing that terminal multiplexers are reliable for LLDB integration. The main differentiators were efficiency and ease of use, with simpler interfaces (terminalcp, tmux) outperforming more complex ones (screen, terminalcp-cli) in terms of cost and execution time.\\n\\n### Recommendation\\nTmux should be preferred for LLDB debugging tasks due to its lowest cost, fastest average execution time, and cleanest implementation without requiring workarounds or experiencing session management issues.&quot;,\n      &quot;screen&quot;: {\n        &quot;judgeNotes&quot;: &quot;Now I have read all the evaluation files for claude-code using screen on the debug-lldb task. Let me provide my assessment in the required format:\\n\\n## Overall Performance\\nThe agent consistently succeeded in all 10 runs, correctly identifying the NULL pointer dereference crash in the demo-buggy program using LLDB through Screen. Performance was reliable with thorough debugging analysis in each run.\\n\\n## What Went Well\\n- Successfully started LLDB sessions through Screen in all runs\\n- Correctly identified the crash location (demo-buggy.c:26 in add_score function)\\n- Accurately diagnosed the root cause (NULL pointer dereference of scores field)\\n- Properly examined variables, memory, and call stack as requested\\n- Consistently used the expect workaround for Screen&#39;s hardcopy bug\\n- Provided detailed technical analysis including memory addresses and variable states\\n- Properly cleaned up Screen sessions after completion\\n\\n## What Went Wrong\\n- Some runs unnecessarily examined the source code files before debugging (runs 3, 4, 8, 9)\\n- Occasional redundant tool calls when examining variables\\n- Minor inconsistency in debugging approach (some set breakpoints, others ran directly)\\n- Some runs were more verbose than necessary in their analysis\\n\\n## Run-by-Run Analysis\\n- Run 20250815220002898000: Pass - Clean execution with efficient debugging and clear root cause analysis\\n- Run 20250815220123424001: Pass - Thorough debugging with proper variable examination and detailed analysis\\n- Run 20250815220303961002: Pass - Good execution but included unnecessary file listing before debugging\\n- Run 20250815220434495003: Pass - Comprehensive analysis but unnecessarily read source code first\\n- Run 20250815220625079004: Pass - Very detailed debugging with breakpoints and step-by-step analysis\\n- Run 20250815220855669005: Pass - Efficient debugging with clear identification of the NULL pointer issue\\n- Run 20250815221016207006: Pass - Good execution with proper variable examination and concise analysis\\n- Run 20250815221141740007: Pass - Clean debugging session with thorough variable inspection\\n- Run 20250815221302275008: Pass - Most comprehensive run with breakpoints and detailed stepping through code\\n- Run 20250815221547848009: Pass - Efficient debugging with proper cleanup and comprehensive final analysis\\n\\n## Recommendations\\nFocus on directly debugging the binary without reading source code first unless specifically needed. Standardize the debugging approach to either use breakpoints consistently or run directly to the crash. Reduce verbosity in analysis while maintaining technical accuracy. Consider batching related debugging commands to reduce the number of tool calls needed.&quot;,\n        &quot;runs&quot;: [\n          {\n            &quot;agent&quot;: &quot;claude-code&quot;,\n            &quot;task&quot;: &quot;debug-lldb&quot;,\n            &quot;tool&quot;: &quot;screen&quot;,\n            &quot;timestamp&quot;: &quot;20250815220002898000&quot;,\n            &quot;success&quot;: true,\n            &quot;totalCost&quot;: 0.4039,\n            &quot;totalDurationWall&quot;: &quot;1m 19.2s&quot;,\n            &quot;models&quot;: {\n              &quot;claude-3-5-haiku&quot;: {\n                &quot;input&quot;: 34100,\n                &quot;output&quot;: 679,\n                &quot;cacheRead&quot;: 0,\n                &quot;cacheWrite&quot;: 0\n              },\n              &quot;claude-sonnet&quot;: {\n                &quot;input&quot;: 108,\n                &quot;output&quot;: 2100,\n                &quot;cacheRead&quot;: 637000,\n                &quot;cacheWrite&quot;: 40300\n              }\n            }\n          },\n          ... 9 more runs ...\n      },\n      &quot;terminalcp&quot;: {\n        &quot;judgeNotes&quot;: &quot;Now I&#39;ve read all the files as instructed. Let me provide my assessment in the exact format requested:\\n\\n## Overall Performance\\nThe agent successfully completed the LLDB debugging task in all 10 runs, consistently identifying the null pointer dereference crash in the add_score function. Performance was reliable with correct use of the terminalcp tool and appropriate LLDB commands to examine variables, memory, and call stack.\\n\\n## What Went Well\\n- Successfully started LLDB sessions using terminalcp in all runs\\n- Correctly identified the crash location (line 26, add_score function) in every run\\n- Properly examined the Student structure and identified the NULL scores pointer\\n- Used appropriate LLDB commands (run, print, bt, frame select) effectively\\n- Correctly cleaned up sessions with stop command in all runs\\n- Provided accurate root cause analysis identifying NULL pointer dereference\\n- Maintained consistent workflow: start → run → examine → analyze → stop\\n\\n## What Went Wrong\\n- Run 3 and 4 unnecessarily read source files before debugging (Read tool usage)\\n- Some runs used verbose list commands to view source code when not essential\\n- Run 4 stepped through create_student function unnecessarily, making session longer\\n- Minor inconsistencies in session naming (lldb_debug, lldb-debug, debug_session, lldb)\\n- Some runs included excessive detail in final analysis when conciseness would suffice\\n\\n## Run-by-Run Analysis\\n- Run 20250815222127742000: Pass - Clean execution with concise, accurate analysis\\n- Run 20250815222228204001: Pass - Good debugging, noted additional off-by-one bug in calculate_average\\n- Run 20250815222333672002: Pass - Thorough analysis including intentional bug comment discovery\\n- Run 20250815222509136003: Pass - Read source unnecessarily but completed task correctly\\n- Run 20250815222634596004: Pass - Read binary first, used breakpoints and stepping (overcomplicated)\\n- Run 20250815222855081005: Pass - Clean execution with good variable examination\\n- Run 20250815223010524006: Pass - Efficient debugging with clear root cause identification\\n- Run 20250815223125966007: Pass - Good use of list commands to view source context\\n- Run 20250815223251410008: Pass - Multiple list attempts but successfully completed task\\n- Run 20250815223426868009: Pass - Clean, efficient execution with proper analysis\\n\\n## Recommendations\\nFocus on using only LLDB through terminalcp as specified in the task requirements without additional file reading. Maintain consistent session naming conventions. Keep final analysis concise while covering all essential points. Avoid unnecessary stepping through code when the crash information is sufficient for root cause analysis.&quot;,\n        &quot;runs&quot;: [\n          {\n            &quot;agent&quot;: &quot;claude-code&quot;,\n            &quot;task&quot;: &quot;debug-lldb&quot;,\n            &quot;tool&quot;: &quot;terminalcp&quot;,\n            &quot;timestamp&quot;: &quot;20250815222127742000&quot;,\n            &quot;success&quot;: true,\n            &quot;totalCost&quot;: 0.3008,\n            &quot;totalDurationWall&quot;: &quot;59.2s&quot;,\n            &quot;models&quot;: {\n              &quot;claude-3-5-haiku&quot;: {\n                &quot;input&quot;: 2000,\n                &quot;output&quot;: 78,\n                &quot;cacheRead&quot;: 0,\n                &quot;cacheWrite&quot;: 0\n              },\n              &quot;claude-sonnet&quot;: {\n                &quot;input&quot;: 130,\n                &quot;output&quot;: 1900,\n                &quot;cacheRead&quot;: 555100,\n                &quot;cacheWrite&quot;: 27400\n              }\n            }\n          },\n          ... 9 more runs ...\n</span></code></pre>\n<p>You may have noticed that the structure would allow for evaluating other coding agents as well. I've started work on that because I'd really like to see how Gemini CLI and OpenCode fare. We'll see if I have time to do that.</p>\n<h2>The Results</h2>\n<p>After 120 evaluation runs (3 tasks × 4 tools × 10 repetitions), here's what emerged:</p>\n<p>Loading evaluation results...</p>\n<h3>Token Usage</h3>\n<h3>Key Findings</h3>\n<ol>\n<li>\n<p><strong>MCP vs CLI truly is a wash</strong>: Both terminalcp MCP and CLI versions achieved 100% success rates. The MCP version was 23% faster (51m vs 66m) and 2.5% cheaper ($19.45 vs $19.95).</p>\n</li>\n<li>\n<p><strong>Screen completely failed on project analysis</strong>: Screen had 0% success on the project analysis task - it couldn't switch models in OpenCode's TUI. This dropped its overall success rate to 67%.</p>\n</li>\n<li>\n<p><strong>MCP's hidden advantage: no security checks</strong>: The lower Haiku token usage for terminalcp MCP (35k vs 1.3-2M) reveals that CLI tools trigger Claude Code's <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://mariozechner.at/posts/2025-08-03-cchistory/#toc_1\">malicious command detection</a> on every bash invocation. MCP bypasses this overhead entirely. It also means fewer round trips to Anthropic's servers.</p>\n</li>\n<li>\n<p><strong>Task complexity determines the winner</strong>: For simpler tasks (LLDB debugging, Python REPL), tmux actually beats terminalcp on cost by 10-22%. But for complex tasks requiring more back-and-forth (project analysis), terminalcp's cleaner output gives it a 39% cost advantage over tmux. Overall totals are close: terminalcp at $19-$20, tmux at $22.</p>\n</li>\n</ol>\n<h2>Reproducing the Results</h2>\n<p>You can download the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://mariozechner.at/posts/2025-08-15-mcp-vs-cli/media/evaluation-results.zip\">full evaluation results</a> if you want to dig into the details. The framework writes out the raw ANSI stream from each run. You can even playback the Claude Code sessions with cat:</p>\n<h3>Easy mode: Run individual prompts</h3>\n<p>Just take any <code>-prompt.md</code> file from the evaluation results and feed it into Claude Code. Make sure you have the required tools installed:</p>\n<ul>\n<li><strong>terminalcp</strong>: Clone repo, run <code>npm install</code>, then run Claude Code in the cloned repo dir</li>\n<li><strong>tmux</strong>: Install via package manager (<code>brew install tmux</code>, <code>apt-get install tmux</code>, etc.)</li>\n<li><strong>screen</strong>: Usually pre-installed on Linux/macOS</li>\n</ul>\n<h3>Full mode: Run the complete evaluation</h3>\n<p>Clone the repo and run the evaluation framework:</p>\n<pre><code class=\"language-bash\"><span class=\"code-snippet\" data-language=\"Shell\"><span class=\"syntax-source syntax-shell syntax-bash\"><span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">git</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> clone https://github.com/badlogic/terminalcp</span>\n<span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-support syntax-function syntax-cd syntax-shell\">cd</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> terminalcp</span>\n<span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">git</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> checkout ac9272ed03a40e4d9666ded80667688b16a7a16a</span>\n<span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">npm</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> install</span>\n\n<span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-begin syntax-shell\">#</span></span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"> Run ALL evaluations (3 tasks × 4 tools × 10 repetitions)</span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\">\n</span><span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">npx</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> tsx test/eval/run.ts</span>\n\n<span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-begin syntax-shell\">#</span></span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"> Or run specific combinations</span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\">\n</span><span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">npx</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> tsx test/eval/run.ts<span class=\"syntax-variable syntax-parameter syntax-option syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-parameter syntax-shell\"> --</span>agents</span> claude<span class=\"syntax-variable syntax-parameter syntax-option syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-parameter syntax-shell\"> --</span>tasks</span> python-repl<span class=\"syntax-variable syntax-parameter syntax-option syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-parameter syntax-shell\"> --</span>tools</span> tmux<span class=\"syntax-variable syntax-parameter syntax-option syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-parameter syntax-shell\"> --</span>repeat</span> 10</span>\n\n<span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-begin syntax-shell\">#</span></span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"> Generate statistics after runs complete</span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\">\n</span><span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">npx</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> tsx test/eval/stats.ts</span>\n</span></span></code></pre>\n<p>Available options:</p>\n<ul>\n<li><code>--agents</code>: Agent to use (for now just: claude)</li>\n<li><code>--tasks</code>: Task names (debug-lldb, python-repl, project-analysis) or file paths</li>\n<li><code>--tools</code>: Tool names (terminalcp, terminalcp-cli, tmux, screen) or file paths</li>\n<li><code>--repeat</code>: Number of repetitions per combination (default: 1)</li>\n<li><code>--parallel</code>: Number of parallel evaluations (default: 1)</li>\n</ul>\n<p>For the debug-lldb task you need to have LLDB installed. For the python-repl task, you need to have Python 3+ installed. For the project-analysis task, you need to install <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://opencode.ai\">opencode</a> and you'll need <code>GROQ_API_KEY</code> set in your environment as the task uses GPT-OSS 120B through Groq in opencode.</p>\n<h2>So, MCP or CLI?</h2>\n<p>The answer is, at least for this specific case, it doesn't matter as much as you'd think. What actually matters:</p>\n<ol>\n<li>\n<p><strong>Tool design</strong>: A well-designed, token-efficient tool can beat standard tools. Terminalcp's clean output and simple interface outperformed tmux and screen despite their training data advantage.</p>\n</li>\n<li>\n<p><strong>Documentation quality</strong>: Clear, concise instructions with examples can perform equally well as being in the training data. The terminalcp tool descriptions were enough to achieve 100% success rates.</p>\n</li>\n<li>\n<p><strong>Token efficiency</strong>: Both MCP and CLI can be token-efficient if designed well. The problem with many MCPs isn't the protocol - it's that they're badly designed wrappers that dump unnecessary JSON everywhere.</p>\n</li>\n</ol>\n<p>My takeaway? Maybe instead of arguing about MCP vs CLI, we should start building better tools. The protocol is just plumbing. What matters is whether your tool helps or hinders the agent's ability to complete tasks.</p>\n<p>That said, if you're building a tool from scratch and your users already have a shell tool available, just make a good CLI. It's simpler and more portable. Plus, the output of your CLI can be further filtered and massaged just by piping it into another CLI tool, which can increase token efficiency at the cost of additional instructions. That's not possible with MCPs.</p>\n<p>Once you have a well-designed, token-efficient CLI tool, adding an MCP server on top of it is very straightforward.</p>\n<p>This page respects your privacy by not using cookies or similar technologies and by not collecting any personally identifiable information.</p>\n",
  "content_markdown": "![](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli/media/header.jpg)\\\nTerminal tools comparison\n\n- [MCPs as thin wrappers](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_0)\n- [Building a CLI and MCP server](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_1)\n- [Designing the evaluation](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_2)\n  - [Tool definitions](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_3)\n  - [Task definitions](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_4)\n  - [Example evaluation prompt](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_5)\n  - [Running the evaluation](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_6)\n  - [Statistics and judgments](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_7)\n- [The Results](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_8)\n  - [Token Usage](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_9)\n  - [Key Findings](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_10)\n- [Reproducing the Results](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_11)\n  - [Easy mode: Run individual prompts](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_12)\n  - [Full mode: Run the complete evaluation](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_13)\n- [So, MCP or CLI?](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli#toc_14)\n\n[MCP servers](https://modelcontextprotocol.io) (MCPs for short) are all the rage. However, practitioners using agentic coding tools are usually skeptical. Many MCPs flood the context window with unnecessary output or offer dozens of tools, degrading your agent's performance by [poisoning the context](https://mariozechner.at/posts/2025-06-02-prompts-are-code/#toc_0). Many practitioners (myself included) resort to letting coding agents directly call CLI tools instead. But what if we're wrong?\n\n## MCPs as thin wrappers\n\nJust like a lot of meetings could have been emails, a lot of MCPs could have been CLI invocations. For example, there's the [GitHub MCP Server](https://github.com/github/github-mcp-server), which reimplements functionality that's already available in the [GitHub CLI](https://cli.github.com/). There's little benefit of using that MCP compared to telling your coding agent to use its shell tool to run the GitHub CLI directly. In fact, most often the GitHub MCP Server will lead to much worse results than just letting the agent run the command line tool directly.\n\nAnother popular choice is [Context7](https://context7.com/), which provides code snippets to help agents use popular libraries. I found [some of my own libraries](https://context7.com/libgdx/libgdx) in there and the snippets are utterly useless. What works better is having Claude clone the dependency's repository, then let a sub-agent analyze it and generate a concise user manual for the task at hand.\n\nBut it depends on the MCP and available CLI tools. Sometimes there are no easy-to-use CLI tools, making MCPs sensible. Other times CLI tools are too verbose. MCP servers are also the only option for LLM clients without a built-in shell tool. And stateful tools are easier to implement as MCPs than CLIs since MCP servers are stateful by default.\n\nI wanted to quantify the difference by writing an MCP server and a corresponding CLI that can be used with Claude Code and for which there are equivalent standard CLI tools Claude encountered during training. I then wrote a hacky evaluation framework to assess:\n\n- what costs more\n- what takes more time\n- which approach has higher success rates\n- whether the inherent knowledge about standard tools beats in-context learning about a previously unseen tool\n\n## Building a CLI and MCP server\n\nI started by building a tool that's inherently useful to myself: [terminalcp](https://github.com/badlogic/terminalcp/tree/ac9272ed03a40e4d9666ded80667688b16a7a16a), a (less capable) tmux alternative with an MCP server that lets agents control terminal applications (debuggers, REPLs, vim, htop) like Playwright controls browsers.\n\nHere's a quick example of terminalcp in action using the CLI version to debug an executable with lldb and observing the session in a second terminal window:\n\nAnd here's the terminalcp MCP server version used by Claude Code to debug the same executable with lldb:\n\nNote how I can attach to the lldb session from another terminal instance and co-debug with Claude.\n\nYou can bore yourself to death by watching the [making of the v0 of terminalcp](https://www.youtube.com/live/Pd1kP9WJhEo) or check out the [source code](https://github.com/badlogic/terminalcp/tree/ac9272ed03a40e4d9666ded80667688b16a7a16a). Here's a quick rundown:\n\n- [TerminalManager](https://github.com/badlogic/terminalcp/blob/ac9272ed03a40e4d9666ded80667688b16a7a16a/src/terminal-manager.ts) is the core: uses [node-pty](https://github.com/microsoft/node-pty) to spawn processes in pseudo terminals and [xterm.js](https://xtermjs.org/) to render ANSI sequences.\n- [TerminalServer](https://github.com/badlogic/terminalcp/blob/ac9272ed03a40e4d9666ded80667688b16a7a16a/src/terminal-server.ts) runs as a persistent daemon, auto-spawned when needed. Talks to clients via Unix socket (works on Windows too, thanks Node.js).\n- [TerminalClient](https://github.com/badlogic/terminalcp/blob/ac9272ed03a40e4d9666ded80667688b16a7a16a/src/terminal-client.ts) handles communication between the MCP/CLI and the server.\n- The [MCP server](https://github.com/badlogic/terminalcp/blob/ac9272ed03a40e4d9666ded80667688b16a7a16a/src/mcp-server.ts) just forwards LLM tool calls to the terminal server. Dead simple.\n- [CLI logic](https://github.com/badlogic/terminalcp/blob/ac9272ed03a40e4d9666ded80667688b16a7a16a/src/index.ts) I stuffed into index.ts. Parses arguments, handles special keys (up, down, etc.) using tmux-style symbolic key names and control sequences.\n- [AttachClient](https://github.com/badlogic/terminalcp/blob/ac9272ed03a40e4d9666ded80667688b16a7a16a/src/attach-client.ts) lets users attach to running sessions as shown in the videos.\n\nI tried to keep terminalcp token-efficient. The server replies with plain text, not JSON (in case of the MCP server, that plain text still gets wrapped in JSON-RPC messages, whoop whoop). The MCP server exposes a single `terminalcp` tool instead of one per command. This is not just voodoo. In an older version of the Claude Code documentation, Anthropic actually mentioned that there's a limit to the number of tools you should expose to the LLM, otherwise it gets confused (I can no longer find that reference). You can also find this [old Claude Sonnet 3.7 cookbook](https://github.com/anthropics/anthropic-cookbook/blob/main/tool_use/parallel_tools_claude_3_7_sonnet.ipynb) where they introduce a batch tool so that Claude can call multiple tools in parallel.\n\nFinally, the commands let you pick only the output you need. `stdout` can return just the last N lines of the rendered terminal scrollback buffer. `stream` can strip ANSI codes and return only new output since the last call with `since_last`. Here are all the commands, both the MCP tool arguments as JSON and the corresponding CLI invocation:\n\n```bash\n# start - spawn a process with optional name and working directory\n{\"action\": \"start\", \"command\": \"python3 -i\", \"name\": \"repl\", \"cwd\": \"/home/user\"}\nterminalcp start repl \"python3 -i\"\n\n# stop - kill one or all processes\n{\"action\": \"stop\", \"id\": \"repl\"}  # or just {\"action\": \"stop\"} for all\nterminalcp stop repl  # or just terminalcp stop for all\n\n# stdin - send input to a process\n{\"action\": \"stdin\", \"id\": \"repl\", \"data\": \"print('hello')\\r\"}\nterminalcp stdin repl \"print('hello')\" ::Enter\n\n# stdout - get rendered terminal screen with optional line limit\n{\"action\": \"stdout\", \"id\": \"repl\", \"lines\": 50}\nterminalcp stdout repl 50\n\n# stream - get raw output, optionally incremental with since_last\n{\"action\": \"stream\", \"id\": \"repl\", \"since_last\": true, \"strip_ansi\": false}\nterminalcp stream repl --since-last --no-strip-ansi\n\n# list - list all sessions\n{\"action\": \"list\"}\nterminalcp ls\n\n# term-size - get terminal dimensions\n{\"action\": \"term-size\", \"id\": \"repl\"}\n# Not exposed in CLI\n\n# version - check compatibility\n{\"action\": \"version\"}\nterminalcp version\n\n# kill-server - shut everything down\n{\"action\": \"kill-server\"}\nterminalcp kill-server\n```\n\nFinally, here's the tool description that the MCP server reports to the MCP client like Claude Code:\n\n```markdown\nControl background processes with virtual terminals. IMPORTANT: Always clean up processes with \"stop\" action when done.\n\nExamples:\n  Start dev server: {\"action\": \"start\", \"command\": \"npm run dev\", \"cwd\": \"/path/to/project\"}\n  Send text with Enter: {\"action\": \"stdin\", \"id\": \"proc-123\", \"data\": \"npm test\\r\"}\n  Send arrow keys: {\"action\": \"stdin\", \"id\": \"proc-123\", \"data\": \"echo hello\\u001b[D\\u001b[D\\u001b[Dhi \\r\"}\n  Send Ctrl+C: {\"action\": \"stdin\", \"id\": \"proc-123\", \"data\": \"\\u0003\"}\n  Stop process: {\"action\": \"stop\", \"id\": \"proc-abc123\"}\n  Stop all processes: {\"action\": \"stop\"}\n\n  Get terminal screen: {\"action\": \"stdout\", \"id\": \"proc-123\"}  # Current view + scrollback\n  Get last 50 lines: {\"action\": \"stdout\", \"id\": \"proc-123\", \"lines\": 50}\n  Get all output ever: {\"action\": \"stream\", \"id\": \"proc-123\"}  # From process start\n  Get new output only: {\"action\": \"stream\", \"id\": \"proc-123\", \"since_last\": true}  # Since last stream call\n\nOutput modes:\n  stdout: Terminal emulator output - returns the rendered screen as user would see it.\n          Limited to 10K lines scrollback. Best for: interactive tools, TUIs, REPLs, debuggers.\n\n  stream: Raw process output - returns all text the process has written to stdout/stderr.\n          Strips ANSI codes by default (set strip_ansi: false to keep). No limit on history.\n          With since_last: true, returns only new output since last stream call on this process.\n          Best for: build logs, test output, monitoring long-running processes.\n\nCommon escape sequences for stdin:\n  Enter: \\r or \\u000d\n  Tab: \\t or \\u0009\n  Escape: \\u001b\n  Backspace: \\u007f\n  Ctrl+C: \\u0003\n  Ctrl+D: \\u0004\n  Ctrl+Z: \\u001a\n\n  Arrow keys: Up=\\u001b[A Down=\\u001b[B Right=\\u001b[C Left=\\u001b[D\n  Navigation: Home=\\u001b[H End=\\u001b[F PageUp=\\u001b[5~ PageDown=\\u001b[6~\n  Delete: \\u001b[3~ Insert: \\u001b[2~\n  Function keys: F1=\\u001bOP F2=\\u001bOQ F3=\\u001bOR F4=\\u001bOS\n  Meta/Alt: Alt+x=\\u001bx (ESC followed by character)\n\nInteractive examples:\n  Vim: stdin \"vim test.txt\\r\" → stdin \"iHello\\u001b:wq\\r\" → stdout\n  Python: start \"python3 -i\" → stdin \"2+2\\r\" → stdout\n  Build monitoring: start \"npm run build\" → stream (since_last: true) → repeat\n  Interrupt: stdin \"sleep 10\\r\" → stdin \"\\u0003\" (Ctrl+C)\n\nNote: Commands run via bash -c. Use absolute paths, not aliases.\n```\n\nThis isn't quite perfect yet. For example, `stdin` could let you specify a pattern to watch for in the output and wait for it with a timeout, then return the new output. This would save a round trip between client and server. But it works well enough for my evaluation.\n\n## Designing the evaluation\n\nMy aim wasn't to create a fully scientific evaluation. For that, you should check out [Eugene Yan's blog](https://eugeneyan.com/writing/llm-evaluators/), which has fantastic information. I just aim at getting some basic stats with which I can annoy people at a party.\n\nHere's the bird's eye view: I defined three tasks requiring terminal control (start process, send input, get output) and four tools to test: terminalcp MCP server, terminalcp CLI, tmux, and screen. The [task definitions](https://github.com/badlogic/terminalcp/tree/ac9272ed03a40e4d9666ded80667688b16a7a16a/test/eval/tasks) and [tool definitions](https://github.com/badlogic/terminalcp/tree/ac9272ed03a40e4d9666ded80667688b16a7a16a/test/eval/tools) are simple markdown files. Tool definitions include some frontmatter that defines how to add them to Claude Code's toolset if necessary, as well as how to clean up after a run that used this tool. These are the inputs to my evaluation framework.\n\nThe super hacky [evaluation framework](https://github.com/badlogic/terminalcp/tree/ac9272ed03a40e4d9666ded80667688b16a7a16a/test/eval) works like this:\n\n1. **Run the tests**: For each task and tool combination, the framework spawns a fresh Claude Code instance with a clean config (no custom MCPs, no CLAUDE.md files). Each task/tool combination is run 10 times since LLMs are non-deterministic. The framework combines the task and tool definitions into a single prompt with instructions to output TASK\\_COMPLETE or TASK\\_FAILED markers. The Claude Code instance is driven via TerminalManager so the test runner can nudge Claude if it stalls. At the end of each run, it issues `/cost` to capture time, tokens, and cost.\n\n2. **Capture everything**: Each run produces multiple output files:\n\n   - The prompt that was sent\n   - The terminal scrollback buffer (what you'd see on screen)\n   - The raw ANSI stream (with and without escape codes)\n3. **Extract statistics**: Parses outputs for success/failure markers, cost, time, and token usage by model.\n\n4. **Judge with Claude**: The framework uses Claude Code to judge each task/tool combination, reading outputs and assessing what worked, what failed, and why. It also suggests improvements for the task. In a second pass, Claude ranks all tools for each task with analysis, insights, and recommendations.\n\nThe framework can run evaluations in parallel, repeat them multiple times for consistency, and handles cleanup between runs. A full run produces a lot of files.\n\n![](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli/media/mdfiles.png)\n\nWhich is why I use Claude as a judge to give me some initial insights I can then use to navigate the files for manual analysis.\n\nLet's have a quick look at the tools and task definitions.\n\n### Tool definitions\n\nI try to make the tool definitions follow the exact same structure, so the comparison is fair. This includes instructions for special keys, multiline input, scrollback handling, and other operations the agent needs to perform with the tool to complete the tasks. The goal is to give each tool equal footing via in-context information.\n\nThe terminalcp MCP server already reports the tool description, so I only added a few more hints. Here's the full definition:\n\n```markdown\n---\n{\n  \"type\": \"mcp\",\n  \"mcpServers\": {\n    \"terminalcp\": {\n      \"type\": \"stdio\",\n      \"command\": \"npx\",\n      \"args\": [\"tsx\", \"src/index.ts\", \"--mcp\"]\n    }\n  }\n}\n---\n\n### Quick Start (Typical Workflow)\n1. Start session: `{\"action\": \"start\", \"command\": \"command args\", \"name\": \"NAME\"}`\n2. Send input: `{\"action\": \"stdin\", \"id\": \"NAME\", \"data\": \"input\\r\"}`\n3. Get current viewport: `{\"action\": \"stdout\", \"id\": \"NAME\"}`\n4. Clean up: `{\"action\": \"stop\", \"id\": \"NAME\"}`\n\n### Important Notes\n- **Only stop sessions you started by name**\n- **stdout = viewport + scrollback**: Shows clean rendered terminal\n- **stdout with lines**: `{\"action\": \"stdout\", \"id\": \"NAME\", \"lines\": N}` for last N lines\n- **stream = raw output**: Contains all output since start (avoid for TUIs)\n- Use `\\r` for Enter, `\\u001b[A/B/C/D` for arrows, `\\u0003` for Ctrl+C\n- **TIP**: For interactive programs, use stdout after operations complete for clean view\n```\n\nThe terminalcp CLI tool definition is bigger since I need to explain the command syntax:\n\n```markdown\n---\n{\n  \"type\": \"cli\",\n  \"cleanup\": \"npx tsx src/index.ts stop || true\"\n}\n---\n\n### Quick Start (Typical Workflow)\n1. `npx tsx src/index.ts start NAME command args` - Start session\n2. `npx tsx src/index.ts stdin NAME \"input\" ::Enter` - Send input\n3. `npx tsx src/index.ts stdout NAME` - Get current viewport (clean, rendered)\n4. `npx tsx src/index.ts stop NAME` - Clean up when done\n\n### Core Commands\n\n- **Start session**: `npx tsx src/index.ts start NAME command args`\n  - Returns session ID (the NAME you provided)\n  - Example: `npx tsx src/index.ts start repl python3 -i`\n\n- **List sessions**: `npx tsx src/index.ts ls`\n  - Shows: ID, status (running/stopped), working directory, command\n\n- **Send input**: `npx tsx src/index.ts stdin NAME \"input\" ::Enter`\n  - Batch multiple: `npx tsx src/index.ts stdin NAME \"cmd1\" ::Enter \"cmd2\" ::Enter \"cmd3\" ::Enter`\n  - Special keys: `::C-c` (Ctrl+C), `::Up`/`::Down`/`::Right`/`::Left` (arrows), `::PageUp`/`::PageDown`\n  - Example: `npx tsx src/index.ts stdin repl \"2+2\" ::Enter`\n  - **Multiline (Python auto-indents)**: `npx tsx src/index.ts stdin repl \"def greet(name):\" ::Enter \"return f'Hello {name}'\" ::Enter ::Enter`\n\n- **Get output**:\n  - **Current viewport** (RECOMMENDED - clean, rendered view): `npx tsx src/index.ts stdout NAME`\n  - **Last N lines**: `npx tsx src/index.ts stdout NAME N`\n  - **Full scrollback**: `npx tsx src/index.ts stdout NAME 10000` (up to 10,000 lines max)\n\n- **Stop session**: `npx tsx src/index.ts stop NAME`\n\n### Important Notes\n- **Only stop sessions you started by name**\n- **stdout = viewport + scrollback**: Shows clean rendered terminal (up to 10,000 lines)\n- **stdout N = last N lines**: Efficient for checking recent output\n- **TIP**: For interactive programs, use stdout after operations complete for clean view\n\nYou are free to run `npx tsx src/index.ts --help` if you require more information on the tool.\n```\n\nThe tmux tool definition follows the same structure, mapping each terminalcp operation to its tmux equivalent:\n\n```markdown\n---\n{\n  \"type\": \"cli\",\n  \"cleanup\": \"tmux kill-server || true\"\n}\n---\n\n### Quick Start (Typical Workflow)\n1. `tmux new-session -d -s NAME \"command\" \\; set remain-on-exit on` - Start session\n2. `tmux send-keys -t NAME \"input\" Enter` - Send input\n3. `tmux capture-pane -t NAME -p` - Get current viewport (clean, rendered)\n4. `tmux kill-session -t NAME` - Clean up when done\n\n### Core Commands\n\n- **Start session**: `tmux new-session -d -s NAME \"command args\" \\; set remain-on-exit on`\n  - `-d` detached mode, `-s` session name\n  - **IMPORTANT**: Use `remain-on-exit on` to capture output after process ends\n  - Example: `tmux new-session -d -s repl \"python3 -i\" \\; set remain-on-exit on`\n\n- **List sessions**: `tmux list-sessions` or `tmux ls`\n\n- **Send input**: `tmux send-keys -t NAME \"input\" Enter`\n  - Batch multiple: `tmux send-keys -t NAME \"cmd1\" Enter \"cmd2\" Enter \"cmd3\" Enter`\n  - Special keys: `C-c` (Ctrl+C), `Up`/`Down`/`Right`/`Left` (arrows), `PageUp`/`PageDown`\n  - Example: `tmux send-keys -t repl \"2+2\" Enter`\n  - **Multiline (Python auto-indents)**: `tmux send-keys -t repl \"def greet(name):\" Enter \"return f'Hello {name}'\" Enter Enter`\n\n- **Get output**:\n  - **Current viewport** (RECOMMENDED - clean, rendered view): `tmux capture-pane -t NAME -p`\n  - **Last N lines**: `tmux capture-pane -t NAME -p -S -N`\n  - **Full scrollback**: `tmux capture-pane -t NAME -p -S -`\n\n- **Check if alive**: `tmux list-panes -t NAME -F \"#{pane_dead}\"` (0=alive, 1=dead)\n\n- **Kill session**: `tmux kill-session -t NAME`\n\n### Important Notes\n- **Only kill sessions you started by name**\n- **capture-pane = viewport only**: Shows current screen (clean, rendered), perfect for TUIs/REPLs\n- **capture-pane -S - = full scrollback**: Clean rendered history\n- **remain-on-exit on**: Essential for capturing output after process ends\n- **TIP**: For interactive programs, use capture-pane after operations complete for clean view\n\nYou are free to run `tmux --help` if you require more information on the tool.\n```\n\nThe screen tool definition follows the same pattern, except there's a bug in screen v4.0.3 that requires a one-time workaround command to enable hardcopy:\n\n````markdown\n---\n{\n  \"type\": \"cli\",\n  \"cleanup\": \"for session in $(screen -ls | grep -o \\\"[0-9]*\\\\\\\\.[^ ]*\\\"); do screen -S \\\"$session\\\" -X quit; done || true\"\n}\n---\n\n### Quick Start (Typical Workflow)\n1. `rm -f screenlog.0 && screen -dmS NAME -L command args` - Start session\n2. `expect -c 'spawn screen -r NAME; send \"\\001d\"; expect eof' >/dev/null 2>&1` - Enable hardcopy (once per session)\n3. `screen -S NAME -X stuff $'input\\n'` - Send input\n4. `screen -S NAME -p 0 -X hardcopy output.txt && cat output.txt` - Get current viewport (clean, rendered)\n5. `screen -S NAME -X quit` - Clean up when done\n\n### Core Commands\n\n- **Start session**: `screen -dmS NAME -L program args`\n  - `-d` detached mode, `-m` force new session, `-S` session name, `-L` enable logging\n  - **IMPORTANT**: Remove old `screenlog.0` first: `rm -f screenlog.0`\n  - Example: `rm -f screenlog.0 && screen -dmS repl -L python3 -i`\n\n- **List sessions**: `screen -ls`\n\n- **Send input**: `screen -S NAME -X stuff $'input\\n'`\n  - REQUIRED: Use $'...' syntax for proper escape sequences\n  - Batch multiple: `screen -S NAME -X stuff $'cmd1\\ncmd2\\ncmd3\\n'`\n  - Special keys: `$'\\003'` (Ctrl+C), `$'\\e[A]'/`$'\\e[B]'/`$'\\e[C]'/`$'\\e[D]'` (Up/Down/Right/Left arrows)\n  - Example: `screen -S repl -X stuff $'2+2\\n'`\n  - **Multiline (Python auto-indents)**: `screen -S repl -X stuff $'def greet(name):\\nreturn f\\'Hello {name}\\'\\n\\n'`\n\n- **Get output**:\n  - **Current viewport** (RECOMMENDED - clean, rendered view):\n    ```bash\n    # First time per session (v4.0.3 bug workaround):\n    expect -c 'spawn screen -r NAME; send \"\\001d\"; expect eof' >/dev/null 2>&1\n    # Then use hardcopy normally:\n    screen -S NAME -p 0 -X hardcopy output.txt && cat output.txt\n    ```\n  - **Last N lines** (raw with ANSI codes): `tail -N screenlog.0`\n  - **Full scrollback** (raw with ANSI codes): `cat screenlog.0`\n\n- **Kill session**: `screen -S NAME -X quit`\n\n### Important Notes\n- **Only kill sessions you started by name**\n- **hardcopy = viewport only**: Shows current screen (clean, rendered), perfect for TUIs/REPLs\n- **screenlog.0 = full raw output**: Contains all ANSI codes since session start\n- **v4.0.3 hardcopy bug**: Run expect workaround once per session\n- **TIP**: For interactive programs, use hardcopy after operations complete for clean view\n\nYou are free to run `screen --help` if you require more information on the tool.\n````\n\n### Task definitions\n\nI created three tasks that exercise different aspects of terminal control. They should speak for themselves. Probably the most interesting one is the project analysis task where the agent needs to command OpenCode and navigate its TUI.\n\n**Task 1: Debug with LLDB (debug-lldb.md)**\n\n```markdown\nThe program `evaluation-results/demo-buggy` crashes when executed. Use LLDB to:\n- Start the program under the debugger\n- Identify where and why it crashes\n- Examine variables, memory, and call stack\n- Report the root cause of the crash\n```\n\n**Task 2: Python REPL (python-repl.md)**\n\n```markdown\nStart a Python REPL and complete these steps:\n\n1. Calculate 42 * 17 and verify the result appears\n2. Import math module and calculate math.factorial(10)\n3. Create list comprehension: [x**2 for x in range(10)]\n4. Define a function that checks if a number is prime (enter it line by line with proper indentation)\n5. Test your prime function with the number 97 and report whether it's prime\n6. Exit the REPL cleanly\n\nAfter each input, check the output to confirm your command executed correctly before proceeding to the next step.\n\nFinally, get all the output and summarize the results, including whether 97 is prime.\n```\n\n**Task 3: Project analysis (project-analysis.md)**\n\n````markdown\nStart opencode with the anthropic/claude-sonnet-4-20250514 model, switch to GPT OSS 120B using the /models command, and ask it to analyze the project. You MUST capture the COMPLETE response.\n\n1. Start opencode with the specified model:\n   ```\n   opencode --model anthropic/claude-sonnet-4-20250514\n   ```\n\n2. Once opencode is running, use the /models slash command to switch to GPT OSS 120B:\n   ```\n   /models\n   ```\n   When the models dialog opens, type \"GPT OSS 120B\" to filter the list, then select GPT OSS 120B by pressing enter.\n\n3. After successfully switching models, prompt it to analyze the project:\n   ```\n   Read README.md explain what this project does\n   ```\n\n4. Capture the model's COMPLETE response. This will require scrolling upwards to capture all output using stdout with sufficient lines parameter.\n\n5. Report the full summary provided by the model.\n\nIMPORTANT: If you cannot successfully switch to GPT OSS 120B, the task has failed. Report that the model switching failed and do not proceed with the analysis.\n````\n\n### Example evaluation prompt\n\nHere's what the evaluation framework actually sends to Claude Code when combining a task and tool definition. This is the prompt for the Python REPL task with tmux:\n\n```markdown\n## Task\n\nStart a Python REPL and complete these steps:\n\n1. Calculate 42 * 17 and verify the result appears\n2. Import math module and calculate math.factorial(10)\n3. Create list comprehension: [x**2 for x in range(10)]\n4. Define a function that checks if a number is prime (enter it line by line with proper indentation)\n5. Test your prime function with the number 97 and report whether it's prime\n6. Exit the REPL cleanly\n\nAfter each input, check the output to confirm your command executed correctly before proceeding to the next step.\n\nFinally, get all the output and summarize the results, including whether 97 is prime.\n\n## Tool\n\nYou must use **Tmux** to complete this task.\n\n### Quick Start (Typical Workflow)\n1. `tmux new-session -d -s NAME \"command\" \\; set remain-on-exit on` - Start session\n2. `tmux send-keys -t NAME \"input\" Enter` - Send input\n3. `tmux capture-pane -t NAME -p` - Get current viewport (clean, rendered)\n4. `tmux kill-session -t NAME` - Clean up when done\n\n### Core Commands\n\n- **Start session**: `tmux new-session -d -s NAME \"command args\" \\; set remain-on-exit on`\n  - `-d` detached mode, `-s` session name\n  - **IMPORTANT**: Use `remain-on-exit on` to capture output after process ends\n  - Example: `tmux new-session -d -s repl \"python3 -i\" \\; set remain-on-exit on`\n\n- **List sessions**: `tmux list-sessions` or `tmux ls`\n\n- **Send input**: `tmux send-keys -t NAME \"input\" Enter`\n  - Batch multiple: `tmux send-keys -t NAME \"cmd1\" Enter \"cmd2\" Enter \"cmd3\" Enter`\n  - Special keys: `C-c` (Ctrl+C), `Up`/`Down`/`Right`/`Left` (arrows), `PageUp`/`PageDown`\n  - Example: `tmux send-keys -t repl \"2+2\" Enter`\n  - **Multiline (Python auto-indents)**: `tmux send-keys -t repl \"def greet(name):\" Enter \"return f'Hello {name}'\" Enter Enter`\n\n- **Get output**:\n  - **Current viewport** (RECOMMENDED - clean, rendered view): `tmux capture-pane -t NAME -p`\n  - **Last N lines**: `tmux capture-pane -t NAME -p -S -N`\n  - **Full scrollback**: `tmux capture-pane -t NAME -p -S -`\n\n- **Check if alive**: `tmux list-panes -t NAME -F \"#{pane_dead}\"` (0=alive, 1=dead)\n\n- **Kill session**: `tmux kill-session -t NAME`\n\n### Important Notes\n- **Only kill sessions you started by name**\n- **capture-pane = viewport only**: Shows current screen (clean, rendered), perfect for TUIs/REPLs\n- **capture-pane -S - = full scrollback**: Clean rendered history\n- **remain-on-exit on**: Essential for capturing output after process ends\n- **TIP**: For interactive programs, use capture-pane after operations complete for clean view\n\nYou are free to run `tmux --help` if you require more information on the tool.\n\n## Completion\n\nComplete the task using only the tool specified above.\n- If successful, output: TASK_COMPLETE\n- If unsuccessful, output: TASK_FAILED and explain what went wrong\n```\n\n### Running the evaluation\n\nThe evaluation runs through a simple CLI where I specify which task/tool combinations to test and how many repetitions. The framework generates prompts for each combination, spawns Claude Code via TerminalManager, and monitors execution. If Claude stalls, it gets nudged to continue. Once complete, it captures costs and saves all outputs.\n\nHere's what that looks like:\n\nSince I'm evaluating terminal multiplexers, I can attach to the session and watch what Claude is doing.\n\n### Statistics and judgments\n\nAfter all runs complete, a second CLI command parses the outputs, extracts statistics, and has Claude judge each task/tool combination and rank the tools.\n\n![](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli/media/stats.png)\n\nAll of that gets written to a final evaluation-summary.json file which looks something like this:\n\n```json\n{\n  \"claude-code\": {\n    \"debug-lldb\": {\n      \"judgeNotes\": \"## Tool Comparison for debug-lldb\\n\\n### Rankings\\nRank the tools from best to worst based on:\\n1. Success rate: All tools tied at 100%\\n2. Efficiency (tokens/turns): \\n   - 1st: tmux (avg 0.3729 cost, 1m 28.7s)\\n   - 2nd: terminalcp-cli (avg 0.3865 cost, 1m 37.2s)  \\n   - 3rd: terminalcp (avg 0.4804 cost, 1m 22.2s)\\n   - 4th: screen (avg 0.6003 cost, 1m 46.2s)\\n3. Ease of use:\\n   - 1st: terminalcp\\n   - 2nd: tmux\\n   - 3rd: terminalcp-cli\\n   - 4th: screen\\n4. Overall effectiveness:\\n   - 1st: tmux\\n   - 2nd: terminalcp\\n   - 3rd: terminalcp-cli\\n   - 4th: screen\\n\\n### Best Tool: tmux\\nTmux performed best for this task due to its combination of lowest cost ($0.3729 avg), consistent clean execution, and efficient debugging workflow without unnecessary steps or workarounds.\\n\\n### Tool-by-Tool Analysis\\n- **screen**: Most expensive ($0.6003 avg) and required expect workaround for hardcopy bug, but provided reliable debugging with thorough analysis. Several runs unnecessarily examined source code before debugging, reducing efficiency.\\n- **terminalcp**: Simple and straightforward terminal interface with good efficiency, though some runs included unnecessary file reading. Second fastest average duration at 1m 22.2s despite higher token usage than tmux.\\n- **terminalcp-cli**: CLI-based approach had occasional session management issues (\\\"Process not found\\\" errors) and some inefficient multi-session runs. Middle-tier performance with reasonable cost but longest average duration.\\n- **tmux**: Most efficient with lowest cost and consistent clean execution across all runs. No workarounds needed and minimal unnecessary steps, with only one run setting an unneeded breakpoint.\\n\\n### Key Insights\\nAll tools achieved 100% success rate for this debugging task, showing that terminal multiplexers are reliable for LLDB integration. The main differentiators were efficiency and ease of use, with simpler interfaces (terminalcp, tmux) outperforming more complex ones (screen, terminalcp-cli) in terms of cost and execution time.\\n\\n### Recommendation\\nTmux should be preferred for LLDB debugging tasks due to its lowest cost, fastest average execution time, and cleanest implementation without requiring workarounds or experiencing session management issues.\",\n      \"screen\": {\n        \"judgeNotes\": \"Now I have read all the evaluation files for claude-code using screen on the debug-lldb task. Let me provide my assessment in the required format:\\n\\n## Overall Performance\\nThe agent consistently succeeded in all 10 runs, correctly identifying the NULL pointer dereference crash in the demo-buggy program using LLDB through Screen. Performance was reliable with thorough debugging analysis in each run.\\n\\n## What Went Well\\n- Successfully started LLDB sessions through Screen in all runs\\n- Correctly identified the crash location (demo-buggy.c:26 in add_score function)\\n- Accurately diagnosed the root cause (NULL pointer dereference of scores field)\\n- Properly examined variables, memory, and call stack as requested\\n- Consistently used the expect workaround for Screen's hardcopy bug\\n- Provided detailed technical analysis including memory addresses and variable states\\n- Properly cleaned up Screen sessions after completion\\n\\n## What Went Wrong\\n- Some runs unnecessarily examined the source code files before debugging (runs 3, 4, 8, 9)\\n- Occasional redundant tool calls when examining variables\\n- Minor inconsistency in debugging approach (some set breakpoints, others ran directly)\\n- Some runs were more verbose than necessary in their analysis\\n\\n## Run-by-Run Analysis\\n- Run 20250815220002898000: Pass - Clean execution with efficient debugging and clear root cause analysis\\n- Run 20250815220123424001: Pass - Thorough debugging with proper variable examination and detailed analysis\\n- Run 20250815220303961002: Pass - Good execution but included unnecessary file listing before debugging\\n- Run 20250815220434495003: Pass - Comprehensive analysis but unnecessarily read source code first\\n- Run 20250815220625079004: Pass - Very detailed debugging with breakpoints and step-by-step analysis\\n- Run 20250815220855669005: Pass - Efficient debugging with clear identification of the NULL pointer issue\\n- Run 20250815221016207006: Pass - Good execution with proper variable examination and concise analysis\\n- Run 20250815221141740007: Pass - Clean debugging session with thorough variable inspection\\n- Run 20250815221302275008: Pass - Most comprehensive run with breakpoints and detailed stepping through code\\n- Run 20250815221547848009: Pass - Efficient debugging with proper cleanup and comprehensive final analysis\\n\\n## Recommendations\\nFocus on directly debugging the binary without reading source code first unless specifically needed. Standardize the debugging approach to either use breakpoints consistently or run directly to the crash. Reduce verbosity in analysis while maintaining technical accuracy. Consider batching related debugging commands to reduce the number of tool calls needed.\",\n        \"runs\": [\n          {\n            \"agent\": \"claude-code\",\n            \"task\": \"debug-lldb\",\n            \"tool\": \"screen\",\n            \"timestamp\": \"20250815220002898000\",\n            \"success\": true,\n            \"totalCost\": 0.4039,\n            \"totalDurationWall\": \"1m 19.2s\",\n            \"models\": {\n              \"claude-3-5-haiku\": {\n                \"input\": 34100,\n                \"output\": 679,\n                \"cacheRead\": 0,\n                \"cacheWrite\": 0\n              },\n              \"claude-sonnet\": {\n                \"input\": 108,\n                \"output\": 2100,\n                \"cacheRead\": 637000,\n                \"cacheWrite\": 40300\n              }\n            }\n          },\n          ... 9 more runs ...\n      },\n      \"terminalcp\": {\n        \"judgeNotes\": \"Now I've read all the files as instructed. Let me provide my assessment in the exact format requested:\\n\\n## Overall Performance\\nThe agent successfully completed the LLDB debugging task in all 10 runs, consistently identifying the null pointer dereference crash in the add_score function. Performance was reliable with correct use of the terminalcp tool and appropriate LLDB commands to examine variables, memory, and call stack.\\n\\n## What Went Well\\n- Successfully started LLDB sessions using terminalcp in all runs\\n- Correctly identified the crash location (line 26, add_score function) in every run\\n- Properly examined the Student structure and identified the NULL scores pointer\\n- Used appropriate LLDB commands (run, print, bt, frame select) effectively\\n- Correctly cleaned up sessions with stop command in all runs\\n- Provided accurate root cause analysis identifying NULL pointer dereference\\n- Maintained consistent workflow: start → run → examine → analyze → stop\\n\\n## What Went Wrong\\n- Run 3 and 4 unnecessarily read source files before debugging (Read tool usage)\\n- Some runs used verbose list commands to view source code when not essential\\n- Run 4 stepped through create_student function unnecessarily, making session longer\\n- Minor inconsistencies in session naming (lldb_debug, lldb-debug, debug_session, lldb)\\n- Some runs included excessive detail in final analysis when conciseness would suffice\\n\\n## Run-by-Run Analysis\\n- Run 20250815222127742000: Pass - Clean execution with concise, accurate analysis\\n- Run 20250815222228204001: Pass - Good debugging, noted additional off-by-one bug in calculate_average\\n- Run 20250815222333672002: Pass - Thorough analysis including intentional bug comment discovery\\n- Run 20250815222509136003: Pass - Read source unnecessarily but completed task correctly\\n- Run 20250815222634596004: Pass - Read binary first, used breakpoints and stepping (overcomplicated)\\n- Run 20250815222855081005: Pass - Clean execution with good variable examination\\n- Run 20250815223010524006: Pass - Efficient debugging with clear root cause identification\\n- Run 20250815223125966007: Pass - Good use of list commands to view source context\\n- Run 20250815223251410008: Pass - Multiple list attempts but successfully completed task\\n- Run 20250815223426868009: Pass - Clean, efficient execution with proper analysis\\n\\n## Recommendations\\nFocus on using only LLDB through terminalcp as specified in the task requirements without additional file reading. Maintain consistent session naming conventions. Keep final analysis concise while covering all essential points. Avoid unnecessary stepping through code when the crash information is sufficient for root cause analysis.\",\n        \"runs\": [\n          {\n            \"agent\": \"claude-code\",\n            \"task\": \"debug-lldb\",\n            \"tool\": \"terminalcp\",\n            \"timestamp\": \"20250815222127742000\",\n            \"success\": true,\n            \"totalCost\": 0.3008,\n            \"totalDurationWall\": \"59.2s\",\n            \"models\": {\n              \"claude-3-5-haiku\": {\n                \"input\": 2000,\n                \"output\": 78,\n                \"cacheRead\": 0,\n                \"cacheWrite\": 0\n              },\n              \"claude-sonnet\": {\n                \"input\": 130,\n                \"output\": 1900,\n                \"cacheRead\": 555100,\n                \"cacheWrite\": 27400\n              }\n            }\n          },\n          ... 9 more runs ...\n```\n\nYou may have noticed that the structure would allow for evaluating other coding agents as well. I've started work on that because I'd really like to see how Gemini CLI and OpenCode fare. We'll see if I have time to do that.\n\n## The Results\n\nAfter 120 evaluation runs (3 tasks × 4 tools × 10 repetitions), here's what emerged:\n\nLoading evaluation results...\n\n### Token Usage\n\n### Key Findings\n\n1. **MCP vs CLI truly is a wash**: Both terminalcp MCP and CLI versions achieved 100% success rates. The MCP version was 23% faster (51m vs 66m) and 2.5% cheaper ($19.45 vs $19.95).\n\n2. **Screen completely failed on project analysis**: Screen had 0% success on the project analysis task - it couldn't switch models in OpenCode's TUI. This dropped its overall success rate to 67%.\n\n3. **MCP's hidden advantage: no security checks**: The lower Haiku token usage for terminalcp MCP (35k vs 1.3-2M) reveals that CLI tools trigger Claude Code's [malicious command detection](https://mariozechner.at/posts/2025-08-03-cchistory/#toc_1) on every bash invocation. MCP bypasses this overhead entirely. It also means fewer round trips to Anthropic's servers.\n\n4. **Task complexity determines the winner**: For simpler tasks (LLDB debugging, Python REPL), tmux actually beats terminalcp on cost by 10-22%. But for complex tasks requiring more back-and-forth (project analysis), terminalcp's cleaner output gives it a 39% cost advantage over tmux. Overall totals are close: terminalcp at $19-$20, tmux at $22.\n\n## Reproducing the Results\n\nYou can download the [full evaluation results](https://mariozechner.at/posts/2025-08-15-mcp-vs-cli/media/evaluation-results.zip) if you want to dig into the details. The framework writes out the raw ANSI stream from each run. You can even playback the Claude Code sessions with cat:\n\n### Easy mode: Run individual prompts\n\nJust take any `-prompt.md` file from the evaluation results and feed it into Claude Code. Make sure you have the required tools installed:\n\n- **terminalcp**: Clone repo, run `npm install`, then run Claude Code in the cloned repo dir\n- **tmux**: Install via package manager (`brew install tmux`, `apt-get install tmux`, etc.)\n- **screen**: Usually pre-installed on Linux/macOS\n\n### Full mode: Run the complete evaluation\n\nClone the repo and run the evaluation framework:\n\n```bash\ngit clone https://github.com/badlogic/terminalcp\ncd terminalcp\ngit checkout ac9272ed03a40e4d9666ded80667688b16a7a16a\nnpm install\n\n# Run ALL evaluations (3 tasks × 4 tools × 10 repetitions)\nnpx tsx test/eval/run.ts\n\n# Or run specific combinations\nnpx tsx test/eval/run.ts --agents claude --tasks python-repl --tools tmux --repeat 10\n\n# Generate statistics after runs complete\nnpx tsx test/eval/stats.ts\n```\n\nAvailable options:\n\n- `--agents`: Agent to use (for now just: claude)\n- `--tasks`: Task names (debug-lldb, python-repl, project-analysis) or file paths\n- `--tools`: Tool names (terminalcp, terminalcp-cli, tmux, screen) or file paths\n- `--repeat`: Number of repetitions per combination (default: 1)\n- `--parallel`: Number of parallel evaluations (default: 1)\n\nFor the debug-lldb task you need to have LLDB installed. For the python-repl task, you need to have Python 3+ installed. For the project-analysis task, you need to install [opencode](https://opencode.ai) and you'll need `GROQ_API_KEY` set in your environment as the task uses GPT-OSS 120B through Groq in opencode.\n\n## So, MCP or CLI?\n\nThe answer is, at least for this specific case, it doesn't matter as much as you'd think. What actually matters:\n\n1. **Tool design**: A well-designed, token-efficient tool can beat standard tools. Terminalcp's clean output and simple interface outperformed tmux and screen despite their training data advantage.\n\n2. **Documentation quality**: Clear, concise instructions with examples can perform equally well as being in the training data. The terminalcp tool descriptions were enough to achieve 100% success rates.\n\n3. **Token efficiency**: Both MCP and CLI can be token-efficient if designed well. The problem with many MCPs isn't the protocol - it's that they're badly designed wrappers that dump unnecessary JSON everywhere.\n\nMy takeaway? Maybe instead of arguing about MCP vs CLI, we should start building better tools. The protocol is just plumbing. What matters is whether your tool helps or hinders the agent's ability to complete tasks.\n\nThat said, if you're building a tool from scratch and your users already have a shell tool available, just make a good CLI. It's simpler and more portable. Plus, the output of your CLI can be further filtered and massaged just by piping it into another CLI tool, which can increase token efficiency at the cost of additional instructions. That's not possible with MCPs.\n\nOnce you have a well-designed, token-efficient CLI tool, adding an MCP server on top of it is very straightforward.\n\nThis page respects your privacy by not using cookies or similar technologies and by not collecting any personally identifiable information.\n",
  "dateCreated": "2026-09-27T19:29:15.293681927+00:00",
  "date_created": "2025-08-15T00:00:00+00:00",
  "date_modified": "2025-08-15T00:00:00+00:00",
  "date_published": "2025-08-15T00:00:00+00:00",
  "description": "A data-driven comparison of MCP and CLI approaches for coding agent terminal control",
  "external_url": "https://mariozechner.at/posts/2025-08-15-mcp-vs-cli",
  "git": {
    "commit": "ebb0941c5c06a2ab2377342d607535262a3e969e",
    "path": "items/mariozechner-at/2025/08/2025-08-15-mcp-vs-cli-benchmarking-tools-for-coding-agents.md",
    "permalink": "https://github.com/aymericbeaumet/aggr-instance/blob/ebb0941c5c06a2ab2377342d607535262a3e969e/items/mariozechner-at/2025/08/2025-08-15-mcp-vs-cli-benchmarking-tools-for-coding-agents.md"
  },
  "id": "urn:aggr:item:98d08ac5b86eaa6e786ee12e4caf3da8c49c39d8",
  "isBasedOn": {
    "@id": "https://mariozechner.at/posts/2025-08-15-mcp-vs-cli"
  },
  "mainEntity": {
    "@id": "https://mariozechner.at/posts/2025-08-15-mcp-vs-cli",
    "@type": "CreativeWork",
    "archivedAt": {
      "@id": "https://aggr.aymericbeaumet.com/items/mariozechner-at/2025-08-15-mcp-vs-cli-benchmarking-tools-for-coding-agents/#webpage"
    },
    "dateModified": "2025-08-15T00:00:00+00:00",
    "datePublished": "2025-08-15T00:00:00+00:00",
    "headline": "MCP vs CLI: Benchmarking Tools for Coding Agents",
    "timeRequired": "PT26M",
    "url": "https://mariozechner.at/posts/2025-08-15-mcp-vs-cli",
    "wordCount": 5808
  },
  "name": "Archived snapshot: MCP vs CLI: Benchmarking Tools for Coding Agents",
  "preview": null,
  "reading_minutes": 26,
  "replicated_at": null,
  "source": "mariozechner-at",
  "source_name": "{ Mario Zechner }",
  "summary": "A data-driven comparison of MCP and CLI approaches for coding agent terminal control",
  "tags": [],
  "temporalCoverage": "2026-09-27T19:29:15.293681927+00:00",
  "title": "MCP vs CLI: Benchmarking Tools for Coding Agents",
  "url": "https://aggr.aymericbeaumet.com/items/mariozechner-at/2025-08-15-mcp-vs-cli-benchmarking-tools-for-coding-agents/",
  "word_count": 5808
}