Coding-agents
-
Every Feature Opens a Maintenance Account
Coding agents have developed a dangerous little habit. You ask for one change, and somewhere near the end they offer to add three more.
Would you like a configuration flag? A JSON output mode? A retry option? Maybe a dashboard while we’re here?
The agent can build it. The tests and relevant files are already in the context. So why not?
Just one more feature, one more prompt. You know what I’m talking about.
Then six months later the flag is still there. Somebody relies on the JSON shape. The retry behavior conflicts with a new timeout. The dashboard has a dependency that needs a security update. The agent that offered to build all of it has moved on with its life, mostly because it never had one.
You still own the feature.
That’s the part we need to consider. Every feature is another record in a maintenance ledger.
A Feature Is a Standing Promise
We tend to think of a feature as the code that implements it. Add the function, connect the interface, write the tests, merge the change. Feature complete.
That’s the construction phase. The feature itself is a promise that begins after the merge.
If you add a CLI flag, you’re promising that scripts can keep using it. If you expose a JSON response, you’re promising something about its shape. If you store a new piece of data, you’re promising to preserve, migrate, export, and eventually delete it correctly. If you connect another service, you’re promising to notice when its API changes.
The code might be thirty lines. The promise has no line count.
This is why tiny features get expensive. The implementation fits in one file, but the behavior crosses documentation, tests, support, deployment, security, and every future change near that boundary. Agents are very good at showing us the thirty lines. They’re much less likely to show us the next three years.
The Opening Balance Looks Great
Before coding agents, implementation cost acted as a filter. Not always a good one, but a filter.
Someone had to estimate the work, find time in a sprint, write the code, and get it reviewed. A small convenience feature might lose simply because nobody wanted to spend two days on it. Frustrating, sure, but it forced the question: is this worth building?
Now the estimate is twenty minutes. The agent has already inspected the codebase. It can update the model, add the command, generate the tests, and fix the type errors without needing another meeting. The old cost-benefit calculation collapses, because almost everything looks worth building when you only count the first implementation.
So we say yes more often.
That’s not automatically bad. Plenty of useful software never existed because construction cost too much. Cheaper implementation lets small teams solve problems that used to require a real budget. Good for us, but the maintenance math didn’t collapse along with it.
The feature still adds another path through the system. It still creates behavior that can regress. It still has users, even if the only user is you on a Sunday afternoon six months from now.
The opening balance is cheap. The account stays open.
What Accumulates
Maintenance is easy to wave away because no single piece sounds overwhelming. It’s just one more test. One more paragraph in the docs. One more migration. Then the interest starts adding up:
- Compatibility: Existing callers depend on behavior you considered an implementation detail.
- Testing: Every supported path needs coverage, fixtures, and updates when neighboring code changes.
- Documentation: The feature needs to be discoverable, accurate, and removed from the docs if it goes away.
- Dependencies: A tiny feature can introduce a library that now participates in every upgrade and security review.
- Operations: New jobs, tables, queues, or API calls need logs, failure handling, and a recovery story.
- Support: Someone has to answer why it behaved differently on another machine.
- Removal: Deleting it later means finding its users, migrating their data, and deciding how long compatibility lasts.
None of these costs are unique to generated code. We’ve always paid them. The difference is volume. Agents let us open maintenance accounts much faster than we close them.
A Ten-Minute Flag Is Still an Interface
Let me give you an example.
You have a command that prints a human-readable table. An agent offers to add
--json. That sounds great. It probably is great. The code serializes the existing records, the tests compare a sample payload, and the whole change lands before lunch.Then someone pipes that output into another script.
Now field names matter. Null behavior matters. Ordering might matter even though you never promised it. A renamed internal property breaks an external workflow. Adding a timestamp creates noisy diffs. Removing a field requires a compatibility decision.
The flag didn’t add another display format. It created an API.
Would you still build it? Probably. I like useful CLI tools, and machine-readable output is usually worth supporting. The point isn’t to reject the feature. The point is to recognize the account you’re opening. Once you see it as an interface instead of a ten-minute patch, you define the schema deliberately, document what’s stable, avoid exposing fields that should stay internal, and decide whether versioning matters before somebody’s automation answers that question for you.
Same code. Better ownership.
Backlogs Hide the Statements
One reason maintenance gets away from us is that backlogs are organized around changes, not promises.
The issue says “add export support.” It rarely says:
Maintain this export format for as long as anyone depends on it, update it whenever the underlying model changes, keep its documentation accurate, and provide a safe way to retire it later.
That would look ridiculous in an issue title. It’s still what the issue means.
Agents make backlogs disappear quickly, which feels fantastic. I’ve watched them knock out work that would have sat around for months. But a closed issue can become an open obligation. A project with fifty completed features isn’t necessarily healthier than one with twenty. It might just have thirty more things that can break.
Price the Account Before You Open It
I don’t want a meeting for every CLI flag. The whole advantage of these tools is that we can move fast.
We can still take thirty seconds to ask better questions before accepting the extra code:
- Who will depend on this? A person clicking a button creates a different promise than a script parsing output.
- What new state or interface does it introduce? Stored data and public schemas are much harder to remove than local calculations.
- What has to stay compatible? Name the stable boundary instead of letting users guess.
- How will we know it broke? Tests help, but logs, validation, and recovery may matter more.
- What ongoing work does it create? Dependencies, docs, migrations, provider changes.
- What would cause us to close the account? Decide now whether it’s experimental, permanent, or removable.
If the answers are cheap too, build it. If the feature creates a permanent public contract for a minor convenience, nope, not going in.
Cheap Construction Needs Better Restraint
I’m not interested in making software expensive again. Faster implementation is good. More people turning an idea into a working tool is good. Small teams getting leverage that used to belong to large companies is very good.
We just need to stop treating features as free.
I’d appreciate a follow. You can subscribe with your email below. The emails go out once a week, or you can find me on Mastodon at @[email protected].
AI Programming Software-development Coding-agents Maintenance
-
Pi and Hermes Are Trying to Solve Different Problems
I went looking for a talk from Mario Zechner, the creator of Pi, because I wanted to understand why someone would build another coding agent when we already have a pile of them. I found: a talk called “Building pi in a World of Slop.”
Zechner described Pi as a minimal, extensible coding agent that should fit your workflows instead of forcing you into its workflow. He also made a point that should be printed on the box of every AI coding tool: code is not free. The model can produce it quickly, sure. You still own the review, the maintenance, the weird edge cases, and the next person trying to understand it six months later.
That framing explains Pi better than any feature list does.
I’ve also been reading about Hermes Agent, from Nous Research. Hermes is a useful comparison because it’s also an open, provider-flexible agent harness. But it isn’t trying to be Pi with a few extra switches turned on.
Pi and Hermes are trying to solve different problems.
Pi Gives You a Small Place to Start
Pi is a terminal coding harness with a deliberately small default: read files, write files, edit files, run shell commands. Underneath that CLI is a set of TypeScript packages for model access, the agent loop, sessions, and the terminal UI. You can use the CLI, run it through JSON/RPC, or embed the SDK in something else.
That last part is the point.
Pi deliberately leaves out things a lot of agent products treat as table stakes: MCP in the core, subagents, plan mode, permission popups, to-do lists, background shell work. This can look like a missing-feature list if you evaluate it like Claude Code or another finished product.
I don’t think that’s the right test.
Those omissions are Pi’s design. It’s saying: a harness should give you a stable loop, a tool boundary, sessions, and enough extension points to build the workflow you actually need. Then it should get out of the way.
Want MCP? Add it. Want a planning workflow? Make one. Want agents that coordinate over a message bus, work in separate git worktrees, or run in a weird internal deployment? You own the composition. Pi has extensions and packages for that, and now an explicitly experimental orchestration package, but none of it is presented as the one true way to work.
That’s a compelling idea if you’re building a specialized system. It’s also work. Both things can be true.
Hermes Starts With the System
Hermes starts from almost the opposite direction. It’s an integrated autonomous-agent platform with persistent memory, learned skills, built-in delegation, MCP support, scheduling, multiple execution environments, and surfaces that extend beyond the terminal into messaging and desktop interfaces.
Hermes is asking a larger question: what does an agent need to keep working over time, across channels, with memory of what it has already learned?
That’s not just a bigger Pi configuration.
When Hermes includes persistent memory and skill creation, it’s making those things part of the product contract. When it includes subagents and scheduling, it’s giving you an operating model for delegation and recurring work. You get more out of the box, and you inherit more of the system’s assumptions.
For a lot of people, that’s exactly right. If you want an agent to run continuously, show up in Slack or Telegram, remember prior work, and execute recurring workflows, building all of that from Pi primitives would be a very committed hobby.
Good for you, but I think most teams shouldn’t volunteer for that job unless the control model is part of what they’re building.
The Comparison That Matters
Here’s the version I keep coming back to:
Pi Hermes Default posture Minimal programmable harness Integrated autonomous-agent platform Core workflow You compose the pieces The product ships an opinionated system Multi-agent work Extensions, packages, or your own topology Built-in delegation and parallel work Memory Session primitives and JSONL history Persistent memory and skill-learning features Best fit A workflow or control plane you need to own A capable agent system you want to operate This isn’t a scorecard. Hermes isn’t “better” because it has more rows filled in, and Pi isn’t “purer” because it has fewer.
The question is where you want the complexity to live.
With Pi, much of it lives in the system you build around the harness. You have to decide how agents coordinate, what gets remembered, which tools are safe, and how approval works. In exchange, the result can fit your environment instead of being a very configurable version of someone else’s environment.
With Hermes, more of that complexity is already in the platform. You spend less time assembling basic capabilities, but you should understand its memory model, delegation model, security posture, and operational boundaries before you give it real work.
Neither choice removes responsibility. It just changes the shape of it.
Don’t Build a Harness Because It Sounds Fun
Agent harnesses are one of those things that sound like a great weekend project. You wire up a model, give it a few tools, add memory, spawn a couple subagents, and suddenly you have a tiny digital organization running in your terminal.
Then Monday happens.
The agent needs a permission model. It needs observability. It needs a way to recover from bad state. It needs sensible defaults for credentials and logs. It needs evaluation. It needs someone to own the changes when a provider API shifts or an extension becomes a security problem.
That’s why I like the Pi and Hermes comparison. It makes the tradeoff visible.
Use Hermes when you want an agent platform. It already has an opinion about the features an always-on, multi-surface agent needs.
Use Pi when the workflow itself is the product, or when the product assumptions are exactly what you need to escape. Pi’s small core is valuable because it leaves room for a different control plane.
And if all you need is a better code-review prompt or a way to query one internal system, build that inside the harness you already use. A skill, extension, or MCP server is usually a better answer than inventing an agent platform because you wanted one new capability.
This is the same point I landed on in a recent post: you think you want to build your own harness, but what you usually want is a wrapper around the one you already have.
Code is not free. Neither is a harness.
Sources & References
- “Building pi in a World of Slop” — Mario Zechner (talk) — Pi’s design philosophy, workflow fit, and the cost of generated code.
- Pi documentation — current product scope, installation, extensions, and operating modes.
- Pi usage documentation — default tool surface and deliberate core omissions.
- Pi monorepo — TypeScript package architecture and experimental orchestrator package.
- Hermes Agent documentation — persistent memory, skills, delegation, MCP, execution environments, and surfaces.
- Hermes Agent repository — open-source project and implementation reference.
I’d appreciate a follow. You can subscribe with your email below. The emails go out once a week, or you can find me on Mastodon at @[email protected].
-
Your Coding Agent Should Not Own Your Editor
Every coding agent wants to become the place where you work. It starts life as a command-line tool. Then it grows a chat interface, a diff viewer, a permission system, a terminal, a model picker, and eventually an editor integration. Meanwhile, every editor has to build a separate adapter for every agent its users might want. Ten editors, ten agents, and suddenly you’re staring at a hundred bespoke pairings nobody wants to maintain.
We’ve seen before, it’s called a shared boundary.
That’s what the Agent Client Protocol (ACP) is. An agent implements ACP once. An editor implements ACP once. Now you can run the agent inside the editor without either product having to swallow the other whole. It sounds like plumbing because it is plumbing. Plumbing is also the thing that makes ecosystems possible.
ACP in One Sentence
ACP is an open protocol for communication between an AI coding agent and the application presenting that agent to you.
Let’s be specific:
- The client is usually the editor or IDE. It owns the interface, your local environment, and the interaction with you.
- The agent is the coding-agent process. It owns the model loop, the conversation state, and the tool-use logic.
That word agent carries a lot of baggage, so it’s worth nailing down. In everyday AI talk it can mean the raw model, a harness like Claude Code or Opencode that wraps a model, or a subagent that a larger agent spawns to handle a subtask. ACP means the narrow one: the coding-agent process, the harness itself. You’re almost never talking to the model directly in this picture. You talk to the harness, and it drives the model on the other side. An ACP agent also isn’t a subagent. Subagents are an internal detail of whatever the harness does behind its own loop, invisible to the protocol. ACP draws its boundary one level up, between the editor and the whole coding-agent process, not between an agent and its helpers.
In the common local setup, the editor launches the agent as a subprocess and they trade newline-delimited JSON-RPC messages over stdin and stdout.
flowchart LR U[Developer] <--> C[ACP client<br/>Editor or IDE] C <-->|JSON-RPC over stdio| A[ACP agent<br/>Coding-agent process] A <--> M[Model provider] A <--> T[MCP servers and tools] C <--> W[Workspace, buffers, terminals]The whole design is in that picture: the editor and the agent stay separate programs. The agent doesn’t rebuild a serious code-review UI. The editor doesn’t reimplement the reasoning loop. Each side keeps the part it already understands.
The LSP Analogy Only Gets You Halfway
The usual pitch borrows from the Language Server Protocol, and the economics do rhyme. Before LSP, editors built language support one language at a time. After, one language server worked across many editors. ACP applies the same trick to agents: agents stop maintaining an integration per editor, editors stop maintaining one per agent, and you can swap agents without changing where you review code.
But don’t take the analogy too literally. A language server answers bounded questions. Where is this symbol defined? What completions apply here? A coding agent is a long-running, stateful thing. It streams text, announces plans, calls tools, asks permission, edits files, starts processes, and sometimes needs to be interrupted mid-turn. So ACP has to standardize more than request-and-answer. It standardizes enough of the experience of supervising an agent for the client to render it well.
What Happens in a Session
A connection opens with
initialize, where both sides negotiate a version and advertise capabilities. This is deliberately not all-or-nothing. Both programs are expected to cope with optional features being absent.Then the client opens a conversation with
session/newand gets a session ID back. One connection can carry several independent sessions. The client sends your message withsession/prompt, and while the agent works it streamssession/updatenotifications: assistant chunks, thoughts and progress, a plan and edits to that plan, tool calls and their status, mode changes. If a tool call needs a sign-off, the agent sendssession/request_permissionand the editor shows you the choice. Cancel a turn and the client firessession/cancel.That bidirectional flow is the whole difference between ACP and a thin chat API. The agent isn’t just handing back text. It’s exposing a structured account of what it’s doing so the editor can turn that into something you can watch and steer.
The Editor Stops Being a Chat Window
An agent in a plain terminal sees the files on disk. An editor knows more than disk. It has unsaved buffers, syntax highlighting, diagnostics, symbol navigation, a diff UI, and a model of what you’re reviewing right now. ACP’s filesystem methods let the agent ask the client to read or write text including editor state that hasn’t hit disk yet. Its terminal methods let the agent request a command, get a handle, read bounded output, wait for exit, or kill it, while the editor keeps ownership of the process and shows output in its own native terminal.
That split is a lot healthier than every agent inventing its own janky approximation of an IDE. The agent brings intent and execution. The editor brings visibility and control.
ACP and MCP Are Not the Same Thing
People mix these up because both use JSON-RPC and both show up in agent tooling. They sit on different boundaries.
- MCP answers: what can the agent use? Databases, issue trackers, browsers, internal APIs.
- ACP answers: where and how do you work with the agent?
They’re complementary. During
session/new, the ACP client can hand MCP server config to the agent, which then connects to those servers itself. Tools arrive through MCP. Agent work arrives through ACP. Clean.The Interface Is Becoming Its Own Layer
Strip away the JSON-RPC and the method names and the idea is simple: the coding agent and the interface you use to supervise it are different products. Improve the editor without waiting on every agent vendor. Stay in the environment where your code, terminal, and review workflow already live.
We should want coding agents to get better. We should also want the things we use to control them to get better. Those two will move faster if they’re allowed to move apart. That’s the actual promise of ACP. Not one universal agent, but a boundary that stops any single agent from owning the entire way we work.
Sources & References
- Agent Client Protocol introduction and architecture — overview, subprocess model, sessions, permissions, and the relationship to LSP and MCP.
- ACP v1 overview, session setup, and prompt turn — methods, streaming updates, cancellation, and MCP handoff.
- ACP filesystem and terminal methods — unsaved editor state, tracked writes, and process control.
- The ACP Registry is Live — distribution for compatible agents and clients.
I’d appreciate a follow. You can subscribe with your email below. The emails go out once a week, or you can find me on Mastodon at @[email protected].