I’ve been designing software for about twenty years now. Some of this software has been the kind a person sits in front of, web apps, native apps, mobile, desktop, smartwatch, VR headset. Some of it has been for other developers — APIs, libraries, CLIs. Software that helps people build software. Either way the audience is human.
I really like the way Joe Armstrong talks about minimum viable program. His argument is that a program solves exactly one problem well — remove any feature and it breaks, add any and it’s unnecessary. The example he opens with is newticket, a small script Peter Högfeldt wrote at Ericsson in 1986 that made a text file with the right metadata and which still ran decades later because nobody had to keep editing it.
It’s a useful frame because most of what I’ve learned about software in twenty years comes down to a similar idea: good software is software the user can pick up without thinking, and most of what makes that possible is removing things from the path.
Software for agents is a new audience to design for. The question that won’t leave me alone is what UX means for an audience that doesn’t have hands or eyes, that reads text, pastes URLs, runs bash. The friction lives in different places. The discipline is the same.
Tool use
The first answer the industry landed on was structured tool calling. You define a tool — a name, a description, a JSON schema for its arguments — and the model decides when to call it. OpenAI shipped function calling in 2023, Anthropic followed with tool use, and most agent frameworks since have been some variation on that pattern.
Mario Zechner’s pi-mono is one of the more interesting recent takes on it. Tools register on the fly: an extension can call pi.registerTool() mid-session, the tool becomes immediately callable, and the agent can write a new tool, hot-reload it, and start using it without leaving the loop. Armin Ronacher wrote about the design here. The boundary between “tools the agent has” and “tools the agent writes for itself” gets thinner.
Tools registered this way still live inside whatever framework you’re running, though. Move to a different host and the registrations don’t move with you. Anthropic’s Model Context Protocol is the layer that tries to fix that — a standard protocol any agent can speak, framed as “USB-C for AI applications”: servers expose tools and resources, clients consume them, the same MCP server works from Claude Code, from a custom client, from whatever shows up next year. You’re no longer married to a framework’s registry.
The portability comes at a cost. Every tool definition takes up context. Every call is a round-trip with intermediate JSON the model has to generate and parse. At enough tools, the registration block fills the window before the agent has done any work, and the multi-step pipelines that dispatch through MCP bounce out to the model on every step. Anthropic’s own engineering team has argued that the answer is to wrap MCP tools in code execution and let the model call them programmatically. Once you notice that, the question of whether the schema layer earns its place at all isn’t far behind.
Bash
The most portable thing of all is bash. The model writes a shell command, the shell runs it, you read back the output. No schema, no protocol, no SDK. David Crawshaw made the case that an agent is essentially a for loop around an LLM call, and that find, cat, and grep -R are how it actually navigates a codebase. Anthropic’s code execution piece makes a related point: large outputs get filtered before the model sees them, multi-step pipelines run without re-sampling, the context window isn’t choked with intermediate JSON.
The model is now good enough at writing code that the abstraction-as-a-tool layer often costs more than it saves. A schema is a contract the model has to memorise; a bash command is something the model can write. As models get better at code, the surface area where structured tools clearly beat shell access keeps shrinking.
Schemas still earn their place — auth, side-effect controls, audit trails, predictable cost. But the direction of travel is clear enough that “give the agent a shell” has stopped sounding heretical.
Composition
The smallest thing I’ve built in this direction is fold, a script that packs a directory of text files into one self-describing markdown file and unfolds it back. It’s useful even on its own, before any hosting or install protocol enters the picture — markdown is the lingua franca of agent context, and a single markdown file is portable in a way a folder isn’t. You can paste a file into a chat. You can fetch a file from a URL. Fold makes a folder behave like a file, without losing the structure that made the folder useful in the first place. One job, no admin UI, no config file, plain markdown from the outside. Armstrong’s minimum viable program, applied to context bundles.
A markdown file at a URL still has a problem, though. The recipient has to know what to do with it; an agent handed a URL doesn’t necessarily know to curl it, write it to disk, install it as a skill. Portdown wraps the markdown as a self-installing polyglot — the same file reads as markdown when pasted to an agent, and runs as bash when piped through bash with a path. Three layers stacked into one artifact: a small bash header that opens a heredoc and tells the script where to write, the markdown content in the middle, and an optional post-script for things like “now unfold this into a directory.” The install travels with the artifact, and the artifact is the install.
Seeds puts them together. Take a folder, fold it, portdown it, host it at a five-character URL. Any agent can paste the URL and the bundle lands locally with one line of bash. Fold and portdown are local utilities; seed.show is the external layer that makes the URL part work — a Cloudflare Worker with a KV store, free-tier-friendly, ephemeral by default. Every seed expires 30 days after the last access, which keeps it cheap and keeps the URL pool fresh. The recipient doesn’t install anything in the conventional sense; the artifact handles the install itself, and the only thing the user pastes is the URL.
There’s a question hovering over all of this. If agents are good at writing code, and bash is the most portable substrate, what’s the registry? Where does an agent go to find the small utility that does the one thing it needs? I don’t think it’s an app store, and it might not even be a registry in the traditional sense. The agent writes the tool, runs it, throws it away. Or it folds the result into a seed, hands it to another agent, and the second agent unpacks and runs.
The medium is text and bash. Tools come and go. Sometimes one agent passes a folder to another via a URL; sometimes a single agent writes a script for itself, runs it once, and forgets it. The “registry” might just be the agents themselves, holding context and sharing it when there’s a reason to.
UX for agents is still UX. The audience is different and the friction lives in different places, but the discipline is exactly the same.