The IDE Solved This Twenty Years Ago

Your IDE already knows code isn't text. Nobody gave agents the same courtesy.

· 13 min read · updated

mache agents developer-tools aci

the map · part 2 of 8

mache · part 1 of 3


When you hover over a function in VS Code, it doesn’t grep the file. It asks the language server. The language server parsed the AST, resolved the types, tracked the references, and sent the answer back as structured JSON over LSP. When you rename a symbol, the IDE doesn’t find-and-replace a string. It walks the graph, finds every reference, and updates them atomically. When you type a syntax error, the red squiggly appears before you save.

File watchers. JSON-RPC. Tree-sitter. Debug adapters. The entire IDE is a graph-aware layer between humans and code. It has been for twenty years. We solved this problem already.

And then we gave AI agents grep and a prayer.

I’ve spent the last year watching agents fail. Not fail in interesting ways — fail in stupid ways. An agent writes a broken import. The file is now corrupt. The agent doesn’t know until the build fails three minutes later. It parses the error message, re-reads the file, tries again, writes a different syntax error. Three more minutes. I’ve watched this loop run five, six, seven times on a single function edit.

And every time, I think: VS Code would have caught that before the keystroke landed.

The IDE solved the human problem. Nobody solved the agent problem. And the answer has been sitting right in front of us the whole time.

What Agents Actually Do All Day

Right now, the best AI coding tools in the world work like this:

  1. Spin up an agent in a Docker container
  2. Give it a bash shell
  3. Point it at a checkout of the repo
  4. Hope for the best

This isn’t a strawman. Docker’s 2026 State of Agentic AI survey found that 94% of organizations use containers for agent development or production, and 98% follow the same cloud-native workflows as traditional software. The container is the agent’s world.

The agent reads files by cat-ing them — all 2,000 lines, burning context tokens on code it doesn’t need. It finds functions by grep-ing for them — and gets twelve results because the function name is also a variable name in three test files. It makes changes by writing entire files. And it discovers errors by running the build and parsing the output.

When it writes a syntax error, the file is now corrupt and nobody knows. The linter hasn’t run yet. CI hasn’t run yet. The agent might make three more edits on top of the broken one before anything catches it. Now it’s debugging a cascade instead of fixing the original problem. This is a Tuesday morning for Claude Code.

This is like asking a human to code by dictating characters into a telephone and waiting for a letter back telling them if it compiled.

And the scale problem is real. Factory.ai’s analysis found that a typical enterprise monorepo spans thousands of files and several million tokens — dwarfing even million-token context windows. Worse, citing Chroma’s research on context rot, they found that model performance degrades as input length grows. More context doesn’t mean better understanding. It often means worse.

Every agent framework tries to fix this at the prompt layer. Better system prompts. Smarter tool definitions. More sophisticated orchestration. Real progress is being made there — but it’s all built on top of a filesystem that treats code as bytes.

The IDE fixed this for humans by building a graphical layer on top of the flat filesystem. But agents don’t have eyes. They don’t need pixels. They have stdin and stdout.

Their IDE is the filesystem. And nobody just… made the filesystem understand code.

ACI: The Agent-Computer Interface

The SWE-agent team at Princeton introduced the term ACI and got the diagnosis exactly right: agents are a new category of end user and they need purpose-built interfaces. Their key finding: the default interface “does not provide simple commands to edit a small chunk of a file, and does not provide any feedback when invalid edits are made” — and this substantially hampered performance. They even discovered the same write-validation insight — rejecting edits that introduce syntax errors dramatically improves results. But their ACI was a new API: custom commands for viewing, scrolling, and editing files, layered on top of the same flat file system. Every agent framework has since built its own version of this — its own commands, its own feedback format, its own abstractions. None of them compose. And underneath, the OS is still blind to code structure.

Mache takes the opposite approach: don’t build new commands. Change what the filesystem contains.

GUI was the human-computer interface. CLI was the power-user interface. ACI is the agent-computer interface. Same underlying graph. Different projection for a different consumer.

The IDE projects the graph into pixels — syntax highlighting, squiggly underlines, hover tooltips, a file tree with icons. All for a human with eyes and a mouse.

ACI projects the graph into paths — directories you can cd into, files you can cat, writes that get validated before they land. All for an agent with stdin. No custom commands. No SDK. No framework-specific API. The ACI is POSIX itself — cd, ls, cat, write — operating on the graph instead of on bytes.

The structure is identical. The surface is different. And the surface matters, because the surface determines whether your consumer can actually use the structure.

Right now, agents don’t have a surface. They have raw bytes behind paths. That’s why they hallucinate imports, corrupt files, blow context windows, and waste ten-minute CI cycles discovering errors that the IDE would have caught in milliseconds.

“But Agents Already Use LSP”

Fair point — sort of. Claude Code shipped LSP support in December 2025, covering 11 languages and cutting code navigation from 45 seconds (grep) to 50ms (semantic lookup). Cursor, Windsurf, and others are integrating similar capabilities. The landscape has genuinely moved.

But look at what’s actually happening: the agent makes a tool call, the language server returns structured data, the agent holds it in context, and then goes back to operating on raw bytes behind paths. Between queries, nothing has changed. The agent has to know to ask the right question, at the right time, and the protocol assumes it already knows where to look — because it was designed for editors, not agents.

José Valim, creator of Elixir, identified this friction immediately: most LSP APIs require passing file:line:column — you can’t simply ask “tell me where Foo#bar is defined.” Agents don’t have cursors. That’s not an ACI. That’s the HCI piped through JSON.

Mache is different in kind, not degree. The structure isn’t a tool the agent calls — it’s the medium the agent operates in. An agent in Mache can’t accidentally cat a 2,000-line file because the file doesn’t exist in that form. It doesn’t need to know to ask for the imports visible to this scope — they’re in context, and there’s no other way to see the code. One approach gives the agent structured answers when it knows the right question. The other makes unstructured access impossible.

But MCP Solves This

The Model Context Protocol is the other obvious response. MCP lets agents discover and call tools — read a database, search a codebase, file a ticket. Real progress for connecting agents to services. But as an ACI for code, it has the same structural problem as LSP, plus new ones.

The London MCP conference in February 2026 made the gaps visible. Tools consume context window space — seven active MCP servers consumed 33.7% of a 200K-token context window before any user input. One developer reported 72%. Security is being retrofitted after the fact; Docker’s survey found that 85% of teams are familiar with MCP, yet most report significant security and configuration issues preventing production deployment.

Mache doesn’t have these problems because it doesn’t add tools. There are no tool descriptions in the context window — the interface is cd, ls, cat, write. There is no new protocol to secure — agents access the filesystem through NFS or FUSE, with standard OS permissions. The agent doesn’t call a tool to get the callers of a function. It runs ls callers/.

MCP solves a real problem: connecting agents to external services. But when the service is your codebase, adding a protocol layer between the agent and the code is solving the wrong problem. The code is already on the filesystem. The filesystem just needs to understand it.

Mache

Mache is the ACI layer for code. It takes your codebase, parses the AST with tree-sitter, and mounts the graph as a filesystem.

mache --agent -d ~/my-project

One command. Auto-infers the schema. Enables write-back. Generates a PROMPT.txt for your LLM. Works with Claude, Aider, Cursor, Copilot — anything that reads and writes files.

What the agent sees:

/tmp/mache/my-project/
  functions/
    HandleRequest/
      source          # the function body
      context         # only the imports and types visible to this scope
      callers/        # every function that calls this one
      callees/        # every function this one calls
      _diagnostics/   # write status, AST errors
    Main/
      source
      context
      callers/

Compare this to what the agent sees today: a directory of .go files. To understand HandleRequest, it has to find the right file, read the whole thing, figure out which imports matter, grep for callers across the entire repo. And it has to do all of this within a finite context window that it’s burning on irrelevant code.

With Mache:

  • cat source — the function body. Nothing else.
  • cat context — only the imports and types this function can see. Surgical token usage.
  • ls callers/ — who calls this. No grep. No LSP client. Just ls.
  • ls callees/ — what this function calls. Blast radius in one command.

This is what the IDE gives humans, projected into the interface agents actually use.

A concrete example. The agent needs to add error handling to HandleRequest:

# Today: flat filesystem
grep -r "HandleRequest" .          # 14 results, 3 are test files
cat server/handler.go              # 2,000 lines, 800 tokens burned
# ...manually find the function at line 847...
# ...edit the whole file...
# ...build fails 3 minutes later: broken import
# Mache: graph filesystem
cd functions/HandleRequest/
cat source                         # just the function - 40 lines
cat context                        # only visible imports and types
ls callers/                        # who breaks if I change this
write source < fixed_version       # validated in microseconds

Six commands. No grep. No scrolling. No wasted tokens. No surprise build failures.

Write-Time Validation

Mache validates writes before they touch the source file — the piece that makes the rest of this work.

When an agent writes to a source file, Mache runs it through tree-sitter. If the syntax is valid, the change gets formatted, spliced into the original source file as an atomic byte-range replacement, and the node is updated in place. Sibling offsets shift. The graph stays consistent. No re-ingest.

If the syntax is invalid, the source file is never touched. The broken code is saved as a draft. The error is written to _diagnostics/ast-errors. The node path stays stable. The agent reads the error, fixes it, and retries.

Valid write:    validate → format → splice → source updated
Invalid write:  validate fails → draft saved → _diagnostics/ast-errors
                Source file untouched. Node path stable. Agent retries.

In the current paradigm, an agent writes a syntax error and the file is corrupt. Nobody knows until the build fails. The agent has to parse the error message, figure out which file and line, re-read the file, and try again. Minutes.

With Mache, the write is rejected in microseconds. The workspace is never corrupted. The agent knows immediately, structurally, what went wrong. The feedback loop that takes minutes becomes the feedback loop that takes microseconds.

This is what the IDE does when it shows you a red squiggly before you save. Same check. Different surface.

A note on scope: Tree-sitter catches structural errors — syntax, malformed AST nodes, broken nesting. It doesn’t catch type errors, wrong argument counts, or calls to functions that don’t exist. Those are semantic errors, and they still require a build or a type checker. Mache eliminates one class of wasted cycles (structural corruption), not all of them. One piece of the old roadmap has shipped: Go writes now run AST-backed lint rules at the write boundary and surface warnings before the edit lands, while the broader repository smell rules run as a ratcheted CI gate. Type checking and fuller language-specific analysis remain outside that boundary.

What This Means For Agents

Context windows stop being a bottleneck. An agent reading context gets exactly the imports and types visible to the function it’s working on. Not the entire file. Not the entire repo. The minimum viable context, computed by the graph.

Errors become structural, not textual. Not “build failed on line 847.” Instead: the write was rejected because this node’s syntax is invalid. Here’s the draft. Here’s the error. Fix it.

Navigation becomes traversal. “Who calls this function?” is ls callers/, not a regex search across a codebase. “What does this function depend on?” is cat context, not reading five files to trace the import chain.

The agent’s workspace is always consistent. Invalid writes are caught at the boundary. The source tree is never in a broken state. CI doesn’t discover structural errors — the filesystem prevents them.

Any agent works — with a system prompt, not an SDK. Agents that write entire files need to learn to write to individual source nodes instead. That’s real integration cost. But the cost is a system prompt (Mache generates one via PROMPT.txt in agent mode), not a client library. Unlike SWE-agent’s approach of building new tools on top of the filesystem, Mache changes what the filesystem contains. If an agent can read and write files, it can use Mache.

The Bigger Picture

Mache ships with its own NFS backend and works standalone on your laptop today. For production workloads, I’m building Leyline — a high-performance Rust data plane that’s a drop-in replacement for the built-in backend, designed for many parallel agents on the same codebase. Loss-tolerant transport, zero-copy storage, atomic state updates, automatic versioning via jj. Mache and Leyline connect via C FFI — Mache is the logic, Leyline is the physics.

That’s a separate post. For now: Mache, your laptop, one command.

Try It

Repo Link: https://github.com/agentic-research/mache

git clone https://github.com/agentic-research/mache.git
cd mache && task build

mache --agent -d ~/your-project

# New terminal:
cd /tmp/mache/your-project-*/
cat PROMPT.txt
claude

Supported languages: Go, Python, JavaScript, TypeScript, SQL, Rust, HCL/Terraform, YAML.

License: Apache 2.0.

What I’m Measuring

I’ve described the failure loop anecdotally — watching agents retry five, six, seven times on a single function edit. That’s real, but anecdotes aren’t evidence.

Here’s what I plan to measure:

  • Wasted CI cycles. Run SWE-bench tasks with and without Mache. Count build failures caused by syntax errors Mache would have caught at write time.
  • Context token efficiency. Compare tokens consumed per task when the agent reads source + context files versus full source files.
  • Iteration count. Edit-test cycles needed to reach a correct patch.
  • Time to first valid patch. Wall clock from task start to first passing test.

I don’t have these numbers yet. When I do, they’ll either validate the architecture or tell us where it’s wrong. Either way, we’ll publish them.

We spent twenty years building the IDE because humans can’t work with raw bytes.

We gave agents raw bytes and wondered why they kept failing.

Mache fixes that. One command. Apache 2.0. Let’s build the tracks.

A note on methodology: this post, like my primary research, was produced via a “Principal Investigator + AI Lab” methodology. I provide the core discoveries, strategic direction, and critical analysis, and I collaborate with AI assistants to synthesize and articulate the final text.