Hacker News new | ask | show | jobs
by anonym29 16 days ago
If you really want a minimal agent that you heavily customize, just skip pi (130+ transitive dependencies on the "minimal" pi-coder package) and write your own. You learn a bunch, and it's not hard. You can even ask another LLM to help you get started.
5 comments

I wrote my own harness in Emacs and it’s completely ridiculous how well it works. Auto-compact is the only missing feature on my list. Claude‘s approach, if I understand it correctly, invalidates a lot of cached context, and I‘m thinking about a more cache-friendly strategy.
Claude is very cache friendly, however there have been some inconsistencies with non anthropic endpoints that led to cache breakages
Exactly! I just vibe coded (with GPT Sol and Claude whatever-number) my own agent, it's trivial to add now any feature I want - simply ask more powerful model to do it for you. I am happy with end result, however it looks indeed these tools are trained to increase token count - they do quite stupid token-spending steps while making code, but the code itself is also a bit weird - it's like they intentionally do code which is hard to modify on your own without using exactly those authoring models. Interestingly, when I am using DeepSeek with OpenCode, I don't see that - it understands my intent well enough and overall code quality is not bad. I recently switched to local Gemma 4, and I often switch (in opencode) to just that less powerful model, because it understands my intent and has enough skills to provide good quality solution although it's rather for small size projects, and for not coding from scratch, but it's also free and private. It feels slower than any big cloud model, so my model switching is probably most quickest path to robust end result :)
That’s certainly doable, but then you need to create all the add-ons you would have added to Pi. IMO, Pi stands in that sweet spot between being very minimal while still offering a catalog of pluggable functionality that you can add to it. Sure, you could vibe code all those things for your custom agent as well, but why recreate what is essentially Pi all over again (the main loop with all the extension hooks, etc.)? Pi is the “standard” batteries-not-included agent, where you can add from a catalog of pre-defined batteries. I recommend starting with Pi and then using an LLM to code custom extensions where the catalog doesn’t have something you want.
Pi has way too many batteries included, including a bunch I don't want, and lacked the batteries I did want. Pi is a bit like the movie Idiocracy in that the idea is much better than the execution.

Incidentally, I also have zero supply chain attack surface as I have zero dependencies in my agent, just go stdlib. Pi, again, has 130+ transitive dependencies asking me to trust the security of my system to 150+ additional people I've never met in exchange for a bunch of bloat I do not want.

Agreed that the node cesspool is a risk. That said, what batteries does Pi have that you don’t want?
Bloated TUI library, unified multi-provider LLM layer, bloated RPC and SDK modes, the entire plugin framework, the list goes on and on.

For reference, pi-coding-agent, by itself (not including dependencies, tests, or pi-ai, pi-tui, pi-agent-core, etc), is ~41,653 SLOC taking up ~1658.9 KiB across 163 files.

My agent, excluding dependencies (all go stdlib) and tests, is 3 files, 946 SLOC, taking up 36.3 KiB, and includes a basic TUI and an XMPP transport channel (including TLS for XMPP), with dynamically configurable delivery to and receipt from either or both, including allowlists for XMPP message partners. It has tool calling, a permission model with whitelisting and interactive permission querying on a per-tool basis, full thinking support, including the ability to toggle hiding or showing it across either or both transports repeatedly throughout an individual session, the same tools as pi comes with out of the box, plus web search, and a tool to vet, build, and git commit golang projects all in one go, stopping if errors are observed. Configurable model and endpoint, too.

Incidentally, the open source xmpp server (prosody) and metasearch engine (SearXNG) are both self-hosted, too.

Sure, if your fundamental issue is “bloat,” you can always write a less general-purpose system that is smaller. No doubt about that.
I guess better phrasing would be auditability, ease of codebase comprehension, coverage of just the features I want. My agent isn't meant to be for X users across Y providers with Z extensible plugins, it's meant for exactly one user, with exactly one provider, and to minimize the amount of trust granted to third parties.
This is a truly underrated approach IMO
Any tips on how to get started?
I have written a few myself to get an understanding.

To learn yourself:

<$20 on a cloud AI api for a chunk of tokens and have the AI teach you. "help me write an AI Agent using (language) and walk me through the steps"

Realize that these agent are REPL/while loops that maintain a conversation state and then based upon the tagging syntax like <TOOL:bash:uptime>uptime for system run time</TOOL> and the agent extracts the tool and then does sub commands.

The build your own Claude Code track on Codecrafters is free while in beta.

https://app.codecrafters.io/catalog

At a minimum, you need an inference endpoint: either cloud or local.

If going local, llama.cpp is going to be the more beginner friendly local inference engine that supports more processor types (AMD GPUs, Intel GPUs, CPUs, anything that supports Vulkan, not just Nvidia). LM Studio is a nice wrapper for this if you'd rather avoid cloning repo and compiling yourself, provided you don't mind closed source software; it's much less enshittified than Ollama.

If going local, you will also need model weights in the right format for your inference engine, and with a model that can fit on your hardware. This is going to be .GGUF files if you're using llama.cpp or a wrapper for it like LM Studio.

From there, pick a language, go look up the OpenAI /chat/completions API format (or Anthropic's "Responses" API format), create a DS or array or slice to store messages, and build a loop that accepts user input, formats it according to the API format, sends it to the inference server, retrieves and parses the response, adds the response to the DS/array/slice, and repeat.

There's a lot more beyond this - tool calling, other API formats (optionally), MCP servers, transport layers besides terminal stdin/stdout, permission models, starting with a system message, clearing your message stack correctly (hint: don't reset it mid tool-call), message compaction, web searching and page fetching, semantic search RAG over embeddings, memory layers - way too much to cover exhaustively in a single message.

Quick self-correction: "Responses" is a newer OpenAI API format, "Messages" is the Anthropic format.