What I learned building an opinionated and minimal coding agent
mariozechner.at
mariozechner.at
I'm so aligned on your take on context engineering / context management. I found the default linear flow of conversation turns really frustrating and limiting. In fact, I still do. Sometimes you know upfront that the next thing you're to do will flood/poison the nicely crafted context you've built up... other times you realise after the fact. In both cases, you didn't have that many alternatives but to press on... Trees are the answer for sure.
I actually spent most of Dec building something with the same philosphy for my own use (aka me as the agent) when doing research and ideation with LLMs. Frustrated by most of the same limitations - want to build context to a good place then preserve/reuse it over and over, fire off side quests etc, bring back only the good stuff. Be able to traverse the tree forwards and back to understand how I got to a place...
Anyway, you've definitely built the more valuable incarnation of this - great work. I'm glad I peeled back the surface of the moltbot hysteria to learn about Pi.
My attempt - a minimalist graph format that is a simple markdown file with inline citations. I load MIND_MAP.md at the start of work, and update it at the end. It reduces context waste to resume or spawn subagents. Memory across sessions.
I was using table structure with column 1 as a key, and col 2 as the data, and told the agents to match key before looking at Col 2. It worked, but sometimes it failed spectacularly.
I’m going to try this out. Thanks for sharing your .md!
I just posted a Show HN re my graph storage for research chat sessions - curious on your thoughts!
Would you mind publishing the `PROJECT_MIND_MAPPING.md` file that's referenced in `MIND_MAP.md'?
This is great work, I am looking forward how it evolves in the future. So far Claude Code seems best despite its bugs given the generous subscription, but when the market corrects and the prices will get closer to API prices, then probably the pay-per-token premium with optimized experience will be a better deal than to suffer Claude Code glitches and paper cuts.
The realization is that at the end agent framework kit that is customizable and can be recursively improved by agents is going to be better than a rigid proprietary client app.
I think it’s more likely that the API prices will decrease over time and the CC allowances will only become more generous. We’ve been hearing predictions about LLM price increases for years but I think the unit economics of inference (excluding training) are much better than a lot of people think and there is no shortage of funding for R&D.
I also wouldn’t bet on Claude Code staying the same as it is right now with little glitches. All of the tools are going to improve over time. In my experience the competing tools aren’t bug free either but they get a pass due to underdog status. All of the tools are improving and will continue to do so.
I think this is absolutely true. There will likely be caps to stop the people running Ralph loops/GasTown with 20 clients 24/7, but for general use they will probably start to drop the API prices rather than vice-versa.
> We’ve been hearing predictions about LLM price increases for years but I think the unit economics of inference (excluding training) are much better than a lot of people think
Inference is generally accepted to be a very profitable business (outside the HN bubble!).
Claude Code subscriptions are more complicated of course but I think they probably follow the general pattern of most subscription software - lots of people who hardly use it, and a few who push it very hard can they lose money on. Capping the usage solves the "losing money" problem.
And I'm personally very happy that Peter's project gets all the hype. The pi repo already gets enough vibesloped PRs from openclaw users as is, and its still only 1/100th of what the openclaw repository has to suffer through.
See here OpenCode.
Seriously. Is creator not aware that "pi" absolutely invokes the name of another very important thing? sigh.
Google doesn't even provide a tokenizer to count tokens locally. The results of this stupidity can be seen directly in AI studio which makes an API call to count_tokens every time you type in the prompt box.
Sometimes I wonder who is drawing more power, my laptop or the TPU cluster on the other side.
At least for Codex, the agent runs commands inside an OS-provided sandbox (Seatbelt on macOS, and other stuff on other platforms). It does not end up "making the agent mostly useless".
"But that is annoying and will slow me down!" Yes, and so will recovering from disastrous tool calls.
Lol, good luck to you!
Even if you get people to sit and press a button every time the agent wants to do anything, you're not getting the actual alertness and rigor that would prevent disasters. You're getting a bored, inattentive person who could be doing something more valuable than micromanaging Claude.
Managing capabilities for agents is an interesting problem. Working on that seems more fun and valuable than sitting around pressing "OK" whenever the clanker wants to take actions that are harmless in a vast majority of cases.
You're right it's an interesting problem that seems fun to work on. Hopefully we'll get better harnesses. For now I'm checking everything.
Secure, yes? Annoying, also yes. Very error-prone too.
I’m not sure why everyone seems to have forgotten about Unix permissions, proper sandboxing, jails, VMs etc when building agents.
Even just running the agent as a different user with minimal permissions and jailed into its home directory would be simple and easy enough.
`chroot` is literally the first thing I used when I first installed a local agent, by intuition (later moved on to a container-wrapper), and now I'm reading about people who are giving these agents direct access to reply to their emails and more.
I don't think there is such a good heuristic. The user wants the agent to do the right thing and not to do the wrong thing, but the capabilities needed are identical.
> `chroot` is literally the first thing I used when I first installed a local agent, by intuition (later moved on to a container-wrapper), and now I'm reading about people who are giving these agents direct access to reply to their emails and more.
That's a good, safe, and sane default for project-focused agent use, but it seems like those playing it risky are using agents for general-purpose assistance and automation. The access required to do so chafes against strict sandboxing.
Here's the macOS kernel-enforced sandbox profile that gets applied to processes spawned by the LLM: https://github.com/openai/codex/blob/main/codex-rs/core/src/...
I think skepticism is healthy here, but there's no need to just guess.
The startup process which sets up the original socket would have to be privileged, of course, but only for the purpose of setting up the initial connection. The running LLM harness process would not have any ability to break out of the sandbox after that.
As for spawning unsandboxed processes, that would require a much more sophisticated system whereby the harness uses an API to request permission from the user to spawn the process. We already have APIs like this for requesting extra permissions from users on Android and iOS, so it's not in-principle impossible either.
In practice I think such requests would be a security nightmare and best avoided, since essentially it would be like a prisoner asking the guard to let him out of jail and the guard just handing the prisoner the keys. That unsandboxed process could do literally anything it has permissions to do as a non-sandboxed user.
The point is that Codex can (by default) run commands on its own, without approval (e.g., running `make` on the project it's working on), but they're subject to the imposed OS sandbox.
This is controlled by the `--sandbox` and `--ask-for-approval` arguments to `codex`.
What's the difference between resetting a container or resetting a VPS?
On local machine I have it under its own user, so I can access its files but it cannot access mine. But I'm not a security expert, so I'd love to hear if that's actually solid.
On my $3 VPS, it has root, because that's the whole point (it's my sysadmin). If it blows it up, I wanna say "I'm down $3", but it doesn't even seem to be that since I can just restore it from an backup.
- Minimal, configurable context - including system prompts [2]
- Minimal and extensible tools; for example, todo tasks extension [3]
- No built-in MCP support; extensions exist [4]. I'd rather use mcporter [5]
Full control over context is a high-leverage capability. If you're aware of the many limitations of context on performance (in-context retrieval limits [6], context rot [7], contextual drift [8], etc.), you'd truly appreciate Pi lets you fine-tune the WHOLE context for optimal performance.
It's clearly not for everyone, but I can see how powerful it can be.
---
[1] https://lucumr.pocoo.org/2026/1/31/pi/
[2] https://github.com/badlogic/pi-mono/tree/main/packages/codin...
[3] https://github.com/mitsuhiko/agent-stuff/blob/main/pi-extens...
[4] https://github.com/nicobailon/pi-mcp-adapter
[5] https://github.com/steipete/mcporter
[6] https://github.com/gkamradt/LLMTest_NeedleInAHaystack
The Claude sub is the only think keeping me on Claude Code. It's not as janky as it used to be, but the hooks and context management support are still fairly superficial.
Reading HN I feel a bit out of touch since I seem to be "stuck" on Cursor. Tried to make the jump further to Claude Code like everyone tells me to, but it just doesn't feel right...
It may be due to the size of my codebase -- I'm 6 months into solo developer bootstrap startup, so there isn't all that much there, and I can iterate very quickly with Cursor. And it's mostly SPA browser click-tested stuff. Comparatively it feels like Claude Code spends an eternity to do something.
(That said Cursor's UI does drive me crazy sometimes. In particular the extra layer of diff-review of AI changes (red/green) which is not integrated into git -- I would have preferred that to instead actively use something integrated in git (Staged vs Unstaged hunks). More important to have a good code review experience than to remember which changes I made vs which changes AI made..)
I think the ability to change models is critical. Some models are better at designing frontend than others. Some are better at different programming languages, writing copy, blogs, etc.
I feel sabotaged if I can’t switch the models easily to try the same prompt and context across all the frontier options
When I was using it a lot, I created a startup hook that just dumped a file listing into the context, or the actual full code on very small repos.
I also got some gains from using a custom edit tool I made which can edit multiple chunks in multiple files simultaneously. It was about 3x faster. I had some edge cases where it broke though, so I ended up disabling it.
We're making this better very soon! In the coming weeks hopefully.
I see in your public issue tracker that a lot of people are desperate simply for an option to turn that thing off ("Automatically accept all LLM changes"). Then we could use any kind of plugin really for reviews with git.
Personally, I found Cursor to be too inaccurate to be useful (possibly because I use Julia, which is relatively obscure) – Opus has been roughly the right level for my "pair programming" workflow.
I will very quickly @- the parts of the code that are relevant to get the context up and running right away. Seems in Claude that's harder..
(They also have their own, "Composer 1", which is just lightning fast compared to the others...and sometimes feels as smart as Opus, but now and then don't find the solution if it's too complicated and I have to ask Opus to clean it up. But if there's simple stuff I switch to it.)
They are improving this use case too with their enhanced blame. I think it was mentioned in their latest update blog.
You'll be able to hover over lines to see if you wrote it, or an AI. If it was an AI, it will show which model and a reference to the prompt that generated it.
I do like Cursor quite a lot.
(if one already exists, someone needs to tell the public Cursor issue tracker)
I hadn't realized that Pi is the agent harness used by OpenClaw.
I only wish the author changed his stance on vendor extensions: https://github.com/badlogic/pi-mono/discussions/254
This makes it even more baffling why anthropic went with bun, a runtime without any sandboxing or security architecture and will rely in apple seatbelt alone?
If you're worried about a hostile agent, then indeed sandboxing is not enough. In the worst case, an actively malicious agent could even try to escape the sandbox with whatever limited subset of commands it's given.
If you're worried about prompt injection, then restricting access to unfiltered content is enough. That would definitely involve not processing third-party input and removing internet search tools, but the restriction probably doesn't have to be mechanically complete if the agent has also been instructed to use local resources only. Even package installation (uv, npm, etc) would be fine up to the existing risk of supply-chain attacks.
If you're worried about stochastic incompetence (e.g. the agent nukes the production database to fix a misspelled table name), then a sandbox to limit the 'blast radius' of any damage is plenty.
If your fear is exfiltration of your browser sessions and your computer joining a botnet, or accidental deletion of your data, then a sandbox helps.
If your fear is the llm exfiltrating code you gave it access to then a sandbox is not enough.
I'm personally more worried about the former.
In practice, it seems to me that the sandbox is only good enough to limit file system access to a certain project, everything else (code or secret exfiltration, installing vulnerable packages, adding prompt injection attacks for others to run) is game if you’re in YOLO mode like pi here.
Maybe a finer grained approach based on capabilities would help: https://simonwillison.net/2025/Apr/11/camel/
I built shellbox (https://shellbox.dev) to make this trivial -- Firecracker microVMs managed entirely over SSH. Create a box, point your agent at it, let it run wild. You can duplicate a box before a risky operation (instant, copy-on-write) and delete it after.
Billing stops when the SSH session disconnects.
No SDK, no container config, just ssh. Any agent that can run shell commands works out of the box.
I've been running OpenClaw (which sits on top of similar primitives) to manage multiple simultaneous workflows - one agent handles customer support tickets, another monitors our deployment pipeline, a third does code reviews. The key insight I hit was exactly what you describe: context engineering is everything.
What makes OpenClaw particularly interesting is the workspace-first model. Each agent has AGENTS.md, TOOLS.md, and a memory/ directory that persists across sessions. You can literally watch agents learn from their mistakes by reading their daily logs. It's less magic, more observable system.
The YOLO-by-default approach is spot on. Security theater in coding agents is pointless - if it can write and execute code, game over. Better to be honest about the threat model.
One pattern I documented at howtoopenclawfordummies.com: running multiple specialized agents beats one generalist. Your sub-agent discussion nails why - full observability + explicit context boundaries. I have agents that spawn other agents via tmux, exactly as you suggest.
The benchmark results are compelling. Would love to see pi and OpenClaw compared head-to-head on Terminal-Bench.
I'm working with it for about 2 weeks now and absolutely love it. I can't think of going back to Claude Code CLI, Codex or similar tools.
Here's my experience in a nutshell: https://ewaldbenes.com/en/blog/the-only-coding-agent-you-ll-...
Re: security, I think I need to make an AI credential broker/system. The only way to securely use agents is to never give them access to a credential at all. So the only way to have the agent run a command which requires credentials, is to send the command to a segregated process which asks the user for permission, then runs it, then returns status to the agent. It would process read-only requests automatically but write requests would send a request to the user to authorize. I haven't yet found somebody else writing this, so I might as well give it a shot
Other than credentialed calls, I have Docker-in-Docker in a VM, so all other actions will be YOLO'd. I think this is the only reasonable system for long-running loops.
This is a problem that model context protocol solves
Your MCP server has the creds, your agent does not.
No difference between that and using the bash tool - except you can keep the keys on the MCP server
I’m on a $100/mo plan, but the codex bar makes it look like I’m burning closer to $500 every 30 days. I tried going local with Qwen 3 (coding) on a Blackwell Pro 6000, and it still feels a beat behind, either laggy, or just not quite good enough for me to fully relinquish Claude Code.
Curious what other folks are seeing: any success stories with other agents on local models, or are you mostly sticking with proprietary models?
I’m feeling a bit vendor-locked into Claude Code: it’s pricey, but it’s also annoyingly good
Anyway, more on the actual article what he’s done is really cool and features a lot of stuff that has proven to work at the forefront of automatic programming – he has a massive test suite against all major model providers, he runs his agent against known eval suites as well.
The YOLO mode is also good, but having a small ‘baby setting mode’ that’s not full-blown system access would make sense for basic security. Just a sensible layer of "pls don't blow my machine" without killing the freedom :)
# Read-only mode (no file modifications possible)
pi --tools read,grep,find,ls -p "Review the code in src/"
Otherwise, "yolo mode" inside a sandbox is perfectly reasonable. A basic bubblewrap configuration can expose read-only system tools and have a read/write project directory while hiding sensitive information like API keys and other home-directory files.https://github.com/willswire/dotfiles/blob/main/claude/.clau...
I built on ADK (Agent Development Kit), which comes with many of the features discussed in the post.
Building a full, custom agent setup is surprisingly easy and a great learning experience for this transformational technology. Getting into instruction and tool crafting was where I found the most ROI.
> If you're uncomfortable with full access, run pi inside a container or use a different tool if you need (faux) guardrails.
I'm sick of doing this. I also don't want faux guardrails. What I do want is an agent front-end that is trustworthy in the sense that it will not, even when instructed by the LLM inside, do anything to my local machine. So it should have tools that run in a container. And it should have really nice features like tools that can control a container and create and start containers within appropriate constraints.
In other words, the 'edit' tool is scoped to whatever I've told the front-end that it can access. So is 'bash' and therefore anything bash does. This isn't a heuristic like everyone running in non-YOLO-mode does today -- it’s more like a traditional capability system. If I want to use gVisor instead of Docker, that should be a very small adaptation. Or Firecracker or really anything else. Or even some random UART connection to some embedded device, where I want to control it with an agent but the device is neither capable of running the front-end nor of connecting to the internet (and may not even have enough RAM to store a conversation!).
I think this would be both easier to use and more secure than what's around right now. Instead of making a container for a project and then dealing with installing the agent into the container, I want to run the agent front-end and then say "Please make a container based on such-and-such image and build me this app inside." Or "Please make three containers as follows".
As a side bonus, this would make designing a container sandbox sooooo much easier, since the agent front-end would not itself need to be compatible with the sandbox. So I could run a container with -net none and still access the inference API.
Contrast with today, where I wanted to make a silly Node app. Step 1: Ask ChatGPT (the web app) to make me a Dockerfile that sets up the right tools including codex-rs and then curse at it because GPT-5.2 is really remarkably bad at this. This sucks, and the agent tool should be able to do this for me, but that would currently require a completely unacceptable degree of YOLO.
(I want an IDE that works like this too. vscode's security model is comically poor. Hmm, an IDE is kind of like an agent front-end except the tools are stronger and there's no AI involved. These things could share code.)
One cool thing is that you can run a vscode service on these containers and open the port up to the outside world, then code in and watch a project come to life.
I work on internal LLM tooling for a F100 at $DAYJOB and was nodding vigorously while reading this, especially when it comes to things like letting users freely switch between models, and the affordances you need to be able to provide good UX around streaming and tool calling, which seem barely thought-out in things like the MCP spec (which at least now has a way to get friendly display names for tools since the last time I looked at it).
This is how I prototyped all of mine. Console.Write[Line].
I am currently polishing up one of the prototypes with WinForms (.NET10) & WebView2. Building something that looks like a WhatsApp conversation in basic winforms is a lot of work. This takes about 60 seconds in a web view.
I am not too concerned about cross platform because a vast majority of my users will be on windows when they'd want to use this tool.
The primary motivation for winforms was getting easy access to OS-native multiline input controls, clipboard, audio, image handling, etc. I could have just put kestrel in the console app and served it as a pure web app, but this is a bit more clunky from a UX perspective (separate browser window, permissions, etc.).
Small and observable is excellent.
Letting your agent read traces of other sessions is an interesting method of context trimming.
Especially, "always Yolo" and "no background tasks". The LLM can manage Unix processes just fine with bash (e.g. ps, lsof, kill), and if you want you can remind it to use systemd, and it will. (It even does it without rolling it's eyes, which I normally do when forced to deal with systemd.)
Something he didn't mention is git: talk to your agent a commit at a time. Recently I had a colleague check in his minimal, broken PoC on a new branch with the commit message "work in progress". We pointed the agent at the branch and said, "finish the feature we started" and it nailed it in one shot. No context whatsoever other than "draw the rest of the f'ing owl" and it just.... did it. Fascinating.
Also please note this is nowhere on the terminal bench leaderboard anymore. I'd advise everyone reading the comments here to be aware of that. This isn't a CLI to use. Just a good experiment and write up.
https://github.com/mitsuhiko/agent-stuff/tree/main
Perhaps benchmarks aren't the best judge.
That's the main point of sub-agents, as far as I can tell. They get their own context, so it's much cheaper. You divide tasks into chunks, let a sub-agent handle each chunk. That actually ties in nicely with the emphasis on careful context management, earlier in the article.
I would add subagents though. They allow for the pattern where the top agent directs / observe a subagent executing a step in a plan.
The top agent is both better at directing a subagent, and it keeps the context clean of details that don't matter - otherwise they'd be in the same step in the plan.
Or you use any of the packages people provide, like this one: https://github.com/nicobailon/pi-subagents
Build https://github.com/offline-ant/pi-tmux and am happy with it.
edit: referring to Anthropic and the like
Also data, see https://news.ycombinator.com/item?id=46637328
(this is also why all the labs, including some chinese ones, are subsidising / metoo-ing coding agents)
One thing I do find is that subagents are helpful for performance -- offloading tasks to smaller models (gpt-oss specifically for me) gets data to the bigger model quicker.
You can sandbox off the data.
Not only did you build a minimal agent, but the framework around it so anyone can build their own. I'm using Pi in the terminal, but I see you have web components. Any tips or creating a "Chat mode" where the messages are like chat bubbles? It would be easier to use on mobile.
They are locked in this naive, horrible framework that would be embarrassing to open source even if they had the permission to do it.
The whole point of react is to update the real browser DOM (or rather their custom ASCII backend, presumably, in this case) only when the content actually changes. When that happens, surely you'd spurt out some ASCII escape sequences to update the display. You're not constrained to do that in 16ms and you don't have a vsync signal you could synchronise to even if you wanted to. Synchronising to the display is something the tty implementation does. (On a different machine if you're using it over ssh!)
Given their own explanation of react -> ascii -> terminal, I can't see how they could possibly have ended up attempting to render every 16ms and flickering if they don't get it done in time.
I'm genuinely curious if anybody can make this make sense, because based on what I know of react and of graphics programming (which isn't nothing) my immediate reaction to that post was "that's... not how any of this works".
It doesn't answer the question, though. Ink throttles to at most 30fps (not 60 as the 16ms quote would suggest, though the at most is far more important). That's done to prevent it churning out vast amounts of ASCII, preventing issues like [1], not as some sort of display sync behaviour where missing the frame deadline would be expected to cause tearing/jank (let alone flickering).
I don't mean to be combative here. There must be some real explanation for the flickering, and I'm curious to know what it is. Using Ink doesn't, on it's own, explain it AFAICS.
Edit: I do see an issue about flickering on Ink [2]. If that's what's going on, the suggestion in one of the replies to use alternate screen sounds reasonable and nothing to do with having to render in 16ms. There are tons of TUI programs out there that manage to update without flickering.
Who's Using Ink?
Claude Code - An agentic coding tool made by Anthropic.Using alternate screen might help, and is probably desirable anyway, but really the right approach is not to clear the screen (or erase lines) at all but just write out the lines and put a clear to end-of-line (ansiEscapes.eraseEndLine) at the end of each one, as described in [3]. That should be a pretty simple patch to Ink.
Likening this to a "small game engine" and claiming they need to render in 16ms is pretty funny. Perhaps they'll figure it out when this comment makes it into Claude's training data.
[1] https://github.com/vadimdemedes/ink/blob/e8b08e75cf272761d63...
[2] https://www.npmjs.com/package/ansi-escapes
[3] https://stackoverflow.com/a/71453783
[4] https://github.com/vadimdemedes/ink/blob/e8b08e75cf272761d63...
The agent I'm writing shares some ideas with Pi but otherwise departs quite drastically from the core design used by Claude Code, Codex, Pi etc, and it seems to have yielded some nice benefits:
• No early stopping ("shall I continue?", "5 tests failed -> all tests passed, I'm done" etc).
• No permission prompts but also no YOLO mode or broken Seatbelt sandboxes. Everything is executed in a customized container designed specifically for the model and adapted to its needs. The agent does a lot of container management to make this work well.
• Agent can manage its own context window, and does. I never needed to add compaction because I never yet saw it run out of context.
• Seems to be fast compared to other agents, at least in any environment where there's heavy load on the inferencing servers.
• Eliminates "slop-isms" like excessive error swallowing, narrative commenting, dropping fully qualified class names into the middle of source files etc.
• No fancy TUI. I don't want to spend any time fixing flickering bugs when I could be improving its skill at the core tasks I actually need it for.
It's got downsides too, it's very overfit to the exact things I've needed and the corporate environment it runs in. It's not a full replacement for CC or Codex. But I use it all the time and it writes nearly all my code now.
The agent is owned by the company and they're starting to ask about whether it could be productized so I suppose I can't really go into the techniques used to achieve this, sorry. Suffice it to say that the agent design space is far wider and deeper than you'd initially intuit from reading articles like this. None of the ideas in my agent are hard to come up with so explore!
When building something minimal, especially in areas like agent-based tooling or assistants, the challenge isn’t only about reducing surface area — it’s about focusing that reduction around what actually solves a user’s problem.
A minimal agent that only handles edge cases, or only works in highly constrained environments, can feel elegant on paper but awkward in practice. Conversely, a slightly less minimal system that still maintains clarity and intent often ends up being more useful without being bloated.
In my own experience launching tools that involve analysis and interpretation, the sweet spot always ends up being somewhere in the intersection of: - clearly scoped core value, - deliberately limited surface, and - enough flexibility to handle real user variation.
Curious how others think about balancing minimalism and practical coverage when designing agents or abstractions in their own projects.