> your AI agent picks dependencies from memory; give it dated facts — try starlog.dev ↗ vet your agent's deps ↗ vibe-coding is fine. vibe-importing isn’t. — try starlog.dev ↗ vibe-importing isn’t fine ↗ your agent has never seen your private packages — try starlog.dev ↗ facts for private packages ↗ a linter for the dependencies your AI agent picks — try starlog.dev ↗ a linter for agent deps ↗

Back to Articles

Oh-My-Pi: The AI Coding Agent That Fixed the String-Match Catastrophe

[ View on GitHub ]

Oh-My-Pi: The AI Coding Agent That Fixed the String-Match Catastrophe

Hook

Traditional AI coding agents fail 93% of the time on models like Grok Code Fast 1 because they're still using line numbers and string matching like it's 1998. One terminal tool just hit 68% accuracy by treating code like git treats commits.

Context

Every developer who's used Cursor, Aider, or Copilot has watched the same disaster unfold: the AI generates a diff, applies it to the wrong location because indentation shifted, retries with a corrected line number, fails again because the file changed, and burns through $2 of API credits before you Ctrl+C and fix it manually. The culprit is str_replace editing—agents specify changes by matching text snippets and replacing them, which works beautifully until someone adds a blank line, refactors a function, or uses tabs instead of spaces.

This isn't a model intelligence problem. It's an addressing problem. We've known since git's inception that content-addressable storage—referencing data by its hash rather than its location—is more resilient than path-based addressing. Yet every mainstream AI coding agent still uses the equivalent of absolute file paths: line numbers and string literals that become invalid the moment the file changes. Oh-my-pi applies git's insight to code editing: it addresses code blocks by their SHA-256 hash, creating anchors that survive whitespace changes, file moves, and concurrent edits. The result is a 10x improvement in edit success rate on fast models like Grok Code Fast 1—jumping from 6.7% to 68.3%—and a 61% reduction in wasted tokens spent retrying failed edits.

Technical Insight

edit request

stable anchor

git/fs ops

loopback

streaming tokens

inline critique

results

unified API

Virtual Filesystems

pr://

conflict://

agent://

Tools

ripgrep linked

brush shell

46 coreutils

LSP/DAP

LLM Agent

Rust Core

80k lines

IPC Boundary

Bun/TypeScript

Hash-Anchor Map

AST → Location

Python/Bun REPL

Reviewer Agent

separate budget

System architecture — auto-generated

The hash-anchored edit system works by fingerprinting code blocks during the read phase and embedding those hashes as anchor points in edit instructions. When the agent wants to modify a function, it doesn't say 'replace lines 42-56' or 'find the string function processData()—it says 'replace the block with hash a3f5e9... with this new content.' The system walks the file's AST, computes stable hashes for each node (function, class, block), and maintains a hash-to-location map that updates as edits land.

Here's what an edit payload looks like compared to traditional approaches:

// Traditional str_replace (fails on whitespace drift)
{
  "type": "str_replace",
  "path": "src/parser.ts",
  "old_str": "function parse(input: string) {\n  return JSON.parse(input);\n}",
  "new_str": "function parse(input: string) {\n  try {\n    return JSON.parse(input);\n  } catch {\n    return null;\n  }\n}"
}

// Hash-anchored (survives file changes)
{
  "type": "hash_edit",
  "path": "src/parser.ts",
  "anchor": "a3f5e927d4c8b1e0",
  "content": "function parse(input: string) {\n  try {\n    return JSON.parse(input);\n  } catch {\n    return null;\n  }\n}"
}

If another developer refactors the file while the agent is working, the hash map updates and the anchor still resolves correctly—or fails gracefully with a clear conflict marker instead of silently corrupting the file.

The second architectural breakthrough is in-process tool execution. Most agents shell out to external tools: they spawn rg as a subprocess, parse stdout, and feed it back to the LLM. Oh-my-pi links ripgrep, fd, and a full bash implementation (called 'brush' with 46 coreutils as native Rust functions) directly into the harness. When the agent runs grep -r "TODO" src/, it's invoking a native function call, not fork-exec'ing a subprocess. This eliminates the 50-200ms startup latency per tool invocation and works identically on Windows (where shell semantics are a nightmare) and Unix.

The bidirectional REPL bridge is where things get wild. Traditional agents treat REPL evaluation as one-way: send code, get output. Oh-my-pi's Python and Bun kernels can call back into the agent's tool surface over a loopback IPC bridge. This means a Python cell can invoke tool.read('data.csv') to fetch a file through the agent's filesystem abstraction, or call tool.task('Extract schema from this JSON') to spawn a subagent—all without breaking REPL state:

# Running inside oh-my-pi's Python REPL
import json

# This calls back into the agent's tool harness
raw = tool.read('config/schema.json')
schema = json.loads(raw)

# Spawn a subagent to validate all data files
results = tool.task(
  'Validate all JSON files in data/ against this schema',
  context={'schema': schema}
)

print(f"Validated {len(results)} files")

The agent doesn't have to juggle 'write a Python script to load the CSV, then read the script output'—it just loads the CSV from inside Python using the same tool.read it uses from the main context.

Virtual filesystems unify disparate APIs into a single surface the model already understands. Reading pr://1428/src/auth.ts fetches a file from pull request #1428 using the same interface as read src/auth.ts. Running grep -r "TODO" conflict:// searches all files with merge conflicts. The agent sees these as filesystem operations—no custom API syntax to learn, no special prompting required. The implementation maps virtual paths to backend adapters (GitHub API for pr://, git conflict markers for conflict://, SQLite for agent:// subagent storage) through a FUSE-like layer.

The time-traveling stream rule system is the most aggressive optimization. Instead of waiting for the LLM to generate a full response, realize it's heading toward a bad trajectory, and retrying with corrective context, oh-my-pi pattern-matches the token stream mid-generation. If regex rules detect the agent about to write rm -rf / or reference a file that doesn't exist, the system aborts generation, injects a system prompt with the correction, and resumes inference from the exact same context position—no wasted tokens on completed-but-wrong responses.

Gotcha

The Bun runtime requirement is the first wall you'll hit. Oh-my-pi won't run on Node because it relies on Bun's native module loader, faster startup, and built-in SQLite. If your team standardizes on Node, your deployment pipeline uses Lambda with Node runtimes, or you're in a regulated environment that vets every runtime addition, you're locked out. Bun is mature and production-ready, but it's not Node—expect friction with existing toolchains.

Hash-anchored edits break down when the file changes externally mid-session. The README acknowledges this: 'If the file content has changed since the last read, anchors may diverge.' If you're pair-programming with oh-my-pi and manually edit a file it's working on, or if a Git pull changes the file, the hash map becomes stale. The system doesn't automatically re-anchor—you have to manually trigger a re-read or resolve conflicts like a merge. This is tractable for solo work but becomes painful in collaborative environments where multiple agents or humans edit the same files concurrently.

The 80,000-line Rust core is a maintenance liability. Every LSP protocol update (which happens quarterly) requires changes to native code, recompilation for macOS/Linux/Windows, and coordinated releases of both the Rust binary and TypeScript harness. The contributor barrier is high: you need competence in both TypeScript and Rust, familiarity with LSP/DAP protocol internals, and the ability to debug IPC boundary issues. For a project with 22K stars, that's a narrow contributor funnel.

Verdict

Use if: You're a senior engineer or security researcher who lives in the terminal, pays per-token for API usage (especially on fast models like Grok or Gemini), and needs the agent to succeed on the first try instead of burning tokens on retry loops. The hash-anchored edits alone justify adoption if you're spending $500+/month on AI coding tools—61% token reduction on Grok 4 Fast translates to real money. Use it if you need LSP operations (workspace/willRenameFiles, go-to-definition, debugger frame inspection) as first-class agent primitives rather than shell-script approximations. Use it if you're willing to install Bun and can tolerate native build complexity in exchange for the most technically capable agent harness available. Skip if: You need Node compatibility, can't install exotic runtimes in your deployment environment, or prioritize shallow contributor onboarding over raw capability. Skip if you're collaborating with a team where multiple people edit the same files concurrently—hash-anchor invalidation will cause friction. Skip if you want a low-maintenance tool—the Rust core and LSP/DAP integrations require ongoing maintenance that pure-Python alternatives like Aider avoid. Skip if you're cost-sensitive and the double-inference advisor model (which runs a second LLM in parallel for every turn) exceeds your budget.