yaml
title: “Oh-My-Pi’s Hash-Anchored Edits: How Terminal Coding Agents Avoid Overwriting Your Work” description: “Hash-anchored edit protocol lets agents modify code without clobbering concurrent human changes, plus LSP/DAP integration for terminal-native agents.” pubDate: 2026-05-22T08:08:41.546335Z category: dev-tools heroImage: “https://images.unsplash.com/photo-1771942202908-6ce86ef73701?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4Njk2ODR8MHwxfHNlYXJjaHwxfHxPaC1NeS1QaSUyN3MlMjBIYXNoLUFuY2hvcmVkJTIwRWRpdHMlM0ElMjBIb3clMjBUZXJtaW5hbCUyMENvZGluZyUyMEFnZW50cyUyMEF2b2lkJTIwT3ZlcndyaXRpbmclMjBZb3VyJTIwV29yayUyMHNvZnR3YXJlJTIwaW5mcmFzdHJ1Y3R1cmUlMjBkYXNoYm9hcmR8ZW58MXwwfHx8MTc3OTQzNzMyMXww&ixlib=rb-4.1.0&q=80&w=1080” sourceUrl: “https://github.com/can1357/oh-my-pi” sourceName: “github.com” tags: [“agentic-ai”, “orchestration”, “infrastructure”] featured: false
Terminal coding agents face a fundamental race condition: when you edit a file while the agent is planning changes, whose version wins? Oh-My-Pi solves this with hash-anchored edits, a protocol that detects conflicts at the line range level and forces the agent to rebase its changes against your current state. The project also wires LSP (Language Server Protocol) and DAP (Debug Adapter Protocol) directly into the agent’s tool harness, giving it IDE-grade type information and debugging primitives without requiring a graphical editor.
This is a maintained fork of Pi by Mario Zechner, now trending at #4 on GitHub TypeScript with 180 stars. The core is 27,000 lines of Rust, exposing 32 built-in tools, 13 LSP operations, and 27 DAP operations to the agent runtime. It runs on Bun (≥1.3.14) and supports 40+ LLM providers.
Hash-Anchored Edit Protocol
Traditional agent edit tools send a file path and replacement content. If the file changed since the agent last read it, the edit either fails silently or overwrites your work. Oh-My-Pi anchors each edit to a content hash of the target line range.
Edit request structure:
interface HashAnchoredEdit {
file: string;
startLine: number;
endLine: number;
expectedHash: string; // SHA-256 of original lines
replacement: string;
}
When the agent calls the edit tool, the runtime:
- Reads the current file state
- Extracts lines
startLinetoendLine - Computes SHA-256 of that range
- Compares against
expectedHash
If hashes match, the edit applies. If they diverge, the runtime returns a conflict error with the current content. The agent must re-read the file, adjust its edit, and retry with the new hash.
Conflict resolution flow:
- Agent reads
main.rslines 10-20, hashabc123 - Human edits line 15 while agent is planning
- Agent submits edit with hash
abc123 - Runtime detects mismatch, returns current lines 10-20 with hash
def456 - Agent rebases its change against new content, resubmits with
def456
This prevents silent overwrites but does not merge changes automatically. If both agent and human modified the same logical block, the agent must understand the human’s intent and incorporate it.
LSP and DAP Integration
Oh-My-Pi exposes 13 LSP operations as agent tools:
lsp_definition: Jump to symbol definitionlsp_references: Find all references to a symbollsp_hover: Get type and documentation for a symbollsp_diagnostics: Fetch compiler errors and warningslsp_completion: Trigger autocomplete at a positionlsp_rename: Rename a symbol across the workspacelsp_format: Format a file or rangelsp_code_action: Get available refactoringslsp_document_symbols: List all symbols in a filelsp_workspace_symbols: Search symbols across the projectlsp_signature_help: Get function signature hintslsp_type_definition: Jump to type definitionlsp_implementation: Find implementations of an interface
The agent calls these tools the same way it calls file read or shell exec. The runtime maintains a persistent LSP client connection to the language server (rust-analyzer, typescript-language-server, etc.) and translates tool calls into LSP JSON-RPC requests.
Example tool call:
{
"tool": "lsp_definition",
"args": {
"file": "src/main.rs",
"line": 42,
"character": 15
}
}
The runtime sends textDocument/definition to rust-analyzer, receives a location response, and returns it to the agent as structured JSON. The agent can then read the definition file or chain another LSP call.
DAP integration works identically. The 27 DAP operations include:
dap_launch: Start a debug sessiondap_set_breakpoint: Set breakpoint at linedap_continue: Resume executiondap_step_in,dap_step_out,dap_next: Step through codedap_evaluate: Evaluate an expression in the current framedap_stack_trace: Get call stackdap_scopes: List variable scopesdap_variables: Inspect variable valuesdap_set_variable: Modify a variable during debugging
The agent can launch a debugger, set breakpoints, step through code, and inspect state without leaving the terminal. This is useful for diagnosing test failures or understanding runtime behavior.
Tool Harness and Subagent Delegation
The 32 built-in tools include file operations, shell exec, git commands, browser control (via Playwright), Python REPL, and the LSP/DAP tools. The runtime decides whether to execute a tool inline or delegate to a subagent based on complexity heuristics.
Delegation logic:
| Tool Type | Execution Mode | State Preserved |
|---|---|---|
| File read/write | Inline | File system state |
| Shell exec (< 5 sec) | Inline | Process exit code, stdout/stderr |
| Shell exec (> 5 sec) | Subagent | Full terminal session, environment vars |
| Browser control | Subagent | Page state, cookies, local storage |
| Python REPL | Subagent | Interpreter state, imported modules |
| LSP/DAP | Inline | Language server connection |
When a subagent spawns, it receives a copy of the parent’s context (current directory, environment variables, conversation history up to the delegation point). The subagent runs until it completes the task or hits a token limit, then returns a summary to the parent. The parent can inspect the subagent’s tool calls and outputs but does not inherit its full state.
Subagent boundary:
- Parent agent calls
browser_navigatetool - Runtime spawns subagent with Playwright session
- Subagent interacts with page, fills forms, clicks buttons
- Subagent returns final page state and screenshot
- Parent agent continues with that information
This prevents long-running tasks from blocking the main agent loop and isolates failure modes. If the browser subagent crashes, the parent can retry or switch strategies.
Observability and Failure Modes
The runtime logs every tool call, response, and conflict to a structured JSON log. Each entry includes:
- Timestamp
- Tool name
- Arguments
- Response or error
- Hash mismatch details (for edit conflicts)
- Subagent spawn/exit events
You can tail this log in real time or replay a session to debug agent behavior.
Common failure modes:
- Edit conflict loop: Agent repeatedly submits edits with stale hashes because it does not re-read the file after each conflict. Fix: Add a re-read step to the agent’s edit prompt.
- LSP timeout: Language server takes too long to respond (e.g., indexing a large project). Runtime returns a timeout error after 10 seconds. Agent must retry or skip the LSP call.
- Subagent token exhaustion: Subagent hits token limit before completing the task. Parent receives a truncated summary. Fix: Break the task into smaller subagent calls.
- DAP session crash: Debugger disconnects during a step operation. Runtime returns an error, agent must restart the debug session.
The hash-anchored edit protocol does not prevent logical conflicts. If the agent and human both refactor the same function in incompatible ways, the agent will apply its change on top of yours, potentially breaking the code. The hash only ensures the agent sees your changes before proceeding.
Deployment Shape
Oh-My-Pi runs as a single Bun process. The Rust core compiles to a native binary that Bun loads via FFI. The runtime maintains:
- One LSP client per language server (lazy-spawned)
- One DAP client per debug session (on-demand)
- One Playwright browser instance (shared across subagents)
- One Python interpreter process (persistent REPL)
The agent itself is stateless between turns. Conversation history and tool call logs persist in a SQLite database. You can run multiple agents concurrently (e.g., one per project directory) without interference.
Resource footprint:
- Rust core: ~50 MB resident memory
- Bun runtime: ~100 MB
- LSP servers: 50-200 MB each (depends on language)
- Browser instance: ~300 MB
- Python REPL: ~80 MB
Total memory usage ranges from 300 MB (minimal) to 1 GB (all tools active).
Security Boundaries
The agent has full shell access and can execute arbitrary commands. There is no sandbox. The hash-anchored edit protocol prevents accidental overwrites but does not restrict what the agent can modify.
Mitigation strategies:
- Run the agent in a container or VM if you do not trust the model
- Use git to track changes and revert agent edits
- Review the tool call log before merging agent-generated code
- Disable shell exec tool if you only need LSP/DAP operations
The LSP and DAP tools are read-only by default (except lsp_rename and dap_set_variable). The agent cannot modify code through LSP unless you enable write operations in the config.
Technical Verdict
Use Oh-My-Pi when:
- You work in a terminal-first environment and want agent assistance without switching to a GUI
- You need fine-grained control over agent edits and want to avoid silent overwrites
- You want the agent to leverage LSP type information and DAP debugging without manual setup
- You are comfortable running an agent with full shell access in your development environment
Avoid it when:
- You need a sandboxed agent that cannot execute arbitrary commands
- You want automatic merge resolution for concurrent edits (hash-anchored edits only detect conflicts, they do not merge)
- You prefer a GUI-based agent interface (this is terminal-only)
- You need Windows support with full feature parity (LSP/DAP integration is less mature on Windows)
The hash-anchored edit protocol is the key differentiator. It trades automatic merge resolution for explicit conflict detection, which fits terminal workflows where you want to review every change. The LSP/DAP integration is a close second, giving the agent IDE-grade tooling without requiring an IDE.