{"id":"c1e6f754-e542-4837-bfcf-1da3cf10b027","slug":"trueline-mcp","kind":"mcp","name":"trueline-mcp","summary":"Smarter reads, safer edits. An MCP plugin that cuts token usage and catches editing mistakes before they hit disk. Supports Claude Code, Gemini CLI, GitHub Copilot, and Codex.","owner":"rjkaes","repoUrl":"https://github.com/rjkaes/trueline-mcp","license":"Apache-2.0","licenseTier":"permissive","trust":"community","stars":36,"match":null,"fewStars":false,"format":"mcp","createdAt":"2026-03-04T15:12:31.000Z","addedAt":"2026-10-14T03:47:07.870Z","logoUrl":"https://avatars.githubusercontent.com/u/128173?u=9615a116b3ccd82487bacdcec3120b55bcaab2eb&v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["developer-tools","cloud-infra","memory-knowledge"],"tags":["ai-coding","claude-code","developer-tools","token-optimization","tree-sitter","agentic-coding","anthropic","ast"],"runtime":"node","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-15T03:02:51.613Z","sample":false,"url":"https://conduits.dev/tools/trueline-mcp","language":"TypeScript","transports":["stdio"],"install":{"npm":"trueline-mcp"},"requirements":{"env":[],"upstreamMayCharge":false},"tools":null,"readme":"# trueline-mcp\n\n[![CI](https://github.com/rjkaes/trueline-mcp/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/rjkaes/trueline-mcp/actions/workflows/ci.yml)\n\nAn [MCP](https://modelcontextprotocol.io/) plugin that gives AI coding agents\nhash-verified file editing and targeted reads. Works with Claude Code, Gemini\nCLI, VS Code Copilot, OpenCode, and Codex CLI.\n\n## Installation\n\n**Claude Code** (recommended; hooks are automatic):\n\n```\n/plugin marketplace add rjkaes/trueline-mcp\n/plugin install trueline-mcp@trueline-mcp\n```\n\n**Other platforms** (Gemini CLI, VS Code Copilot, OpenCode, Codex CLI):\nSee [INSTALL.md](INSTALL.md) for platform-specific setup.\n\n**CLI (no MCP):** For agents that use shell commands instead of MCP, install\nglobally with `npm i -g trueline-mcp` and add `configs/cli/instructions.md`\nto your agent's system prompt. See [INSTALL.md](INSTALL.md#cli-no-mcp).\n\n## Why\n\nAI coding agents read entire files to find one function, then echo back\neverything they're replacing. Both waste context on content the agent already\nknows or doesn't need. That context costs money, eats into the conversation\nwindow, and limits how much real work fits in a session.\n\nWorse, the built-in edit tools match by string content. If the agent\nhallucinates a line, works from stale context, or hits an ambiguous match,\nyour code gets silently corrupted.\n\ntrueline fixes both problems: it reads less, writes less, and rejects every\nedit that doesn't match the file's actual content.\n\n## How it works\n\ntrueline provides six MCP tools organized around three workflows.\n\n### Explore: understand before you read\n\n`trueline_outline` returns an AST-based structural outline of any file:\nfunctions, classes, declarations, and their line ranges. For a typical\nsource file, that's 10-20 lines instead of hundreds.\n\n```\n7-14: (8 imports)\n20-23: export const jsonFlag = {\n26-30: export interface CliSubcommand {\n  28-28: usage: string;\n  29-29: run(argv: string[]): Promise<void>;\n36-36: export class UsageError extends Error {}\n39-39: export class HelpRequested extends Error {}\n45-47: type ParsedArgs<T extends ParseArgsOptionsConfig> = ReturnType< typeof parseArgs<{ options: T; allowPositionals: true }>\n50-50: const LONG_FLAG_LIKE = /^--[A-Za-z]/;\n57-84: export function parseCliArgs<T extends ParseArgsOptionsConfig>(argv: string[], options: T) {\n90-96: export function parseIntFlag(name: string, raw: string | undefined, min: 0 | 1): number | undefined {\n104-106: export function fromCwd(arg: string): string {\n115-126: async function assertNotDenied(filePath: string): Promise<void> {\n128-130: function stripBom(text: string): string {\n146-183: export async function loadAtOrDashOrLiteral(value: string, kind: \"json\" | \"text\"): Promise<unknown> {\n189-193: export interface FormatOptions {\n  190-190: json: boolean;\n  192-192: search?: boolean;\n206-225: export function emitResult(result: ToolResult, opts: FormatOptions): void {\n\n(19 symbols, 225 source lines)\n```\n\nThe agent sees the full structure, then uses `trueline_read` to fetch only\nthe ranges it needs. Ranges are specified inline on each path:\n\n```\nfile_paths: [\"src/cli/io.ts:115-126\", \"src/tools/verify.ts:1-20,35-60\"]\n```\n\nA 500-line file where the agent needs one 20-line function? It reads 20\nlines, not 500. Multiple files with different ranges in a single call.\n\n`trueline_search` finds lines by literal string or regex and returns them\nwith edit-ready refs, no outline or read step needed. For targeted\nedits where the agent knows what it's looking for, this is the fastest path.\n\n### Edit: compact and verified\n\nThe built-in edit tool requires the agent to echo back the old text being\nreplaced. `trueline_edit` replaces that with a compact line-range reference\nand a content hash. The agent outputs only the new content.\n\nThe savings scale with the size of the replaced block. A one-line change\nsaves little; replacing 30 lines of old code saves the agent from\noutputting all 30 of those lines again.\n\nMultiple edits can be batched in a single call and applied atomically.\n\nAll MCP trueline tools require an absolute `file_path`/`file_paths`; relative\npaths are rejected to avoid silently operating on the wrong file when the\nagent is working in a git worktree. The CLI (`trueline edit`, `trueline\nread`, etc.) still accepts relative paths, since its working directory is\nunambiguous.\n\n### Review: semantic diffs\n\n`trueline_changes` provides an AST-based summary of structural changes\ncompared to a git ref. Instead of raw line diffs, it reports\nadded/removed/renamed symbols, signature changes, and logic modifications\nwith inline mini-diffs. Pass `[\"*\"]` to diff all changed files at once.\n\n### Hash verification: no silent corruption\n\nEvery line from `trueline_read` and `trueline_search` carries a content\nhash. Every edit must present those hashes back, proving the agent is\nediting what it thinks it's editing.\n\nIf the file changed since the agent read it (concurrent edits, a build\nstep, another tool), the edit is rejected. If the agent hallucinates\ncontent that doesn't match what's on disk, the edit is rejected. If the\nagent targets the wrong lines, the edit is rejected. Nothing hits disk\nunless the hashes match.\n\n`trueline_verify` checks whether held refs are still valid without\nre-reading the file. When nothing changed (the common case), the response\nis a single line.\n\n## How agents actually use it\n\ntrueline doesn't just register tools and hope the agent picks them up.\nOn platforms that support hooks, it actively intercepts the agent's\nworkflow:\n\n- **SessionStart** injects instructions telling the agent how and when\n  to use each trueline tool, calibrated per platform.\n- **PreToolUse** intercepts calls to the built-in read and edit tools,\n  redirecting reads of files over 3 KB to trueline and blocking\n  unverified edits entirely.\n- **Shipped skill** (`skills/trueline-workflow/SKILL.md`) auto-discovers\n  on any file-editing prompt, carrying richer examples and workflow\n  guidance for clients that honor Claude Code skills.\n\nWith hooks, agent compliance is ~98%. Without hooks (instruction-only\nplatforms like OpenCode and Codex CLI), compliance is ~60%. The\ninstruction file still helps; hooks make it reliable.\n\nThe instructions are not one-size-fits-all. They reference each\nplatform's native tool names (`Read`/`Edit` on Claude Code,\n`read_file`/`edit_file` on Gemini CLI, `view`/`edit` on OpenCode) and\nadapt advice accordingly.\n\n## Where it helps most\n\ntrueline's overhead is an MCP round-trip per tool call. For small files\n(under ~3 KB), the built-in tools are perfectly fine and pass through\nwithout interception.\n\nThe payoff comes on larger files and multi-file editing sessions, where\ntargeted reads and compact edits avoid sending hundreds or thousands of\nredundant lines through the context window.\n\nIn a typical 20-turn session exploring 8 files and editing 3, trueline\nsaves roughly 11,000 tokens of mid-session context plus 623 tokens per\nturn from leaner instructions, for an estimated $1.58 per session in\nreduced API cost.\n\n## Design\n\nSee [DESIGN.md](DESIGN.md) for the protocol specification, hash\nalgorithm details, streaming architecture, and security model.\n\n## Development\n\nRequires [Bun](https://bun.sh) ≥ 1.3.\n\n```sh\nbun install          # install dependencies\nbun test             # run tests\nbun run build        # build binary for the current platform\n```\n\n\n## Security model\n\ntrueline-mcp assumes a single-user filesystem trust model: the invoking user\nis trusted, and any process running as that user can already read and write\nthe same files trueline can.\n\n`validatePath()` blocks path traversal and symlink escape at check time by\nresolving with `realpath()` and verifying containment within the project\ndirectory, `TRUELINE_ALLOWED_DIRS`, and (under Claude Code) `~/.claude/`.\n\nConcurrent symlink races (TOCTOU) — where another process under the same\nUID swaps a directory component between the check and a later open — are not\nin scope. Closing them would require fd-based I/O throughout the codebase,\nwhich conflicts with the streaming and atomic-rename design. That tradeoff is\nstated here rather than left implicit.\n\nAs defense-in-depth, read-side opens of user-supplied paths pass `O_NOFOLLOW`\non POSIX. A leaf-component symlink swap between `validatePath` and the open\nfails the open rather than silently following. Writes and rename targets are\nunchanged — the edit path's temp-file and rename pattern was already\nsymlink-safe.\n\nIf you run trueline in a shared-account or multi-tenant environment, harden\nthe OS layer (chroot, mount namespaces) rather than relying on trueline's\npath checks alone.\n## Inspiration\n\nInspired by [The Harness Problem](https://blog.can.ac/2026/02/12/the-harness-problem/)\nby Can Boluk and the\n[vscode-hashline-edit-tool](https://github.com/sethml/vscode-hashline-edit-tool)\nby Seth Livingston.\n\n## Special Thanks\n\n<a href=\"https://github.com/domis86\"><img src=\"https://avatars.githubusercontent.com/u/2327600?v=4\" width=\"32\"></a>\n"}