Pi 1.0 Just Hit #1 on Hacker News. The Agent That Hated MCP Now Ships It. Earendil released Pi 1.0, a minimal MIT-licensed terminal coding agent harness, which reached #1 on Hacker News with over 1,200 points. The release adds MCP support after a year of public criticism of the protocol, but routes tool calls through a WASM JavaScript sandbox called Codemode so that only distilled results re-enter the model's context, avoiding the 550–1,400 tokens per tool schema that MCP normally consumes. The company also shipped Pi Durable, an experimental framework for long-running, crash-resistant agents with per-tool replay policies and exactly-once request submission. Pi 1.0 sat at 1 on Hacker News today with 1,200+ points. Pi Durable, its sibling release, is also in the top 10. The part that got people typing: the agent that spent over a year dunking on MCP now supports MCP. Here's what actually shipped, and why I think the design matters more than the drama. Pi https://earendil.com/posts/pi-1-0/ is a deliberately minimal terminal coding agent harness. It works with models from every major provider, it's MIT licensed, and Earendil says "hundreds of thousands" of people use it weekly. Earendil founded by Armin Ronacher of Flask fame, with Accel and Balderton backing took Pi over in spring 2026. Original creator Mario Zechner is a shareholder and still steers the tech. The philosophy, straight from the 1.0 post: We wait until something has proven itself, and only then do we consider adopting it; weighing its true functionality against its inherent added complexity. That's why the "things we said no to" list is longer than the feature list. It's also why this release is interesting: they said yes to something they'd refused for a year. Install: curl -fsSL https://pi.dev/install.sh | sh The old complaint was simple: MCP burns your context window. Tool schemas load up front, and the cost adds up fast. The commonly cited number is 550 to 1,400 tokens per tool definition. Zechner's go-to example was Perplexity, where three MCP servers reportedly ate 143k of a 200k window. Pi's answer isn't "load the schemas and live with it." It's Codemode . The model gets a JavaScript sandbox WASM, running inside the harness . It discovers tools through docs, writes code that calls them like an SDK, chains calls in parallel, filters the output, and only the distilled result re-enters context . The example in the announcement https://earendil.com/posts/you-said-no-mcp/ combines the Linear MCP server with a sentiment classifier to find frustrated commenters across 167 open issues. That's 167 issues processed in parallel, none of it touching the model's context except the final answer. That's the real point. MCP stays the wire protocol. The interface to the model changes from "here are 40 tool schemas" to "here's a programmable environment." Tool results stop being prompt tax. Their stated reasons for the change: the July 2026 spec revision made MCP more stateless, and the sandbox they needed anyway for non-LLM models made MCP support a small addition. A year of public criticism also pushed the protocol somewhere better. That's how it's supposed to work. My take: this is the right architecture. Anything that makes the model read tool output it doesn't need is a bug. Calling it a "protocol problem" was always half true. Much of it was a harness problem. Shipped the same day: Pi Durable https://earendil.com/posts/pi-durable/ , an experimental framework for agents that are long-running, crash-resistant, and reachable from multiple surfaces terminal, Slack, whatever . Some numbers and design choices worth knowing: The crash semantics are the thing I like. Tools declare a replay policy: js const searchIssues = defineTool { name: "search issues", description: "Search the issue tracker", parameters: Type.Object { query: Type.String } , replay: "safe", // re-runs after crash execute: async args, api = { return { content: { type: "text", text: await tracker.search args.query } , }; }, } ; replay: "safe" tools re-run after a crash. Anything not marked a deploy, a payment does not re-run. The model is told the call was interrupted instead. Interrupted model requests are resent, and a requestId gives you exactly-once submission so retry logic can't double-fire work. Approvals are a hook that stores a decision in a memo, first write wins: js hooks: hook ToolTask, { beforeTool: async call, api, context = { if call.name == "deploy" return undefined; let approved = await api.memo