When we built the runpane CLI, the first version was designed for humans. Install Pane, run some commands, done. Then we realized agents would be the primary users. That changed everything.
Most CLIs are built for people who can read help text, remember flags, and answer "Are you sure?" prompts. Agents can't do any of that. They need structured output, predictable behavior, and a way to figure out what's available without reading a docs site.
Here's what we learned.
1. json output on everything
Human-readable tables look nice, but agents can't reliably parse them. Column alignment, truncated strings, color codes, it all breaks. Every command in runpane has a --json flag that returns structured data.
# Human output: nice to look at, nightmare to parse
runpane panes list
# Agent output: structured, predictable, parseable
runpane panes list --jsonThis seems obvious in hindsight, but many popular CLIs still don't have JSON output. If you're building a CLI that agents will use, this is table stakes.
2. a self-discovery command
Agents shouldn't need to curl a docs page to figure out what your CLI can do. We added runpane agent-context, which prints a short summary of every command. Short is the key word. It needs to fit in an agent's context window without blowing the budget.
# Brief summary of all commands (small token footprint)
runpane agent-context --json
# Full details for one specific command (loaded on demand)
runpane agent-context --command "panes create" --jsonThe default is intentionally minimal. An agent reads the summary, decides which command it needs, then loads the full schema for just that command. This saves tokens and keeps the agent focused.
3. a public contract agents can read before installing
We publish the full command schema at a public URL: runpane.com/runpane-cli-contract.json. An agent can curl this before it installs anything. It can read the available commands, check the expected inputs and outputs, and decide if runpane is even useful before running a package manager.
This is more important than it sounds. Agents are cautious about installing packages. If they can verify the contract first, they're more likely to use it.
4. non-interactive by default for automation
Agents can't answer "Are you sure? (y/n)" prompts. Every command that changes something requires a --yes flag for non-interactive use. Without it, the command shows what it would do and exits. With it, it runs.
# This won't actually create anything without --yes
runpane panes create --repo active --name "my-task" --json
# This will
runpane panes create --repo active --name "my-task" --yes --jsonThe interactive setup wizard (runpane with no arguments) still works for humans. But agents skip straight to the non-interactive path.
5. bounded output by default
When an agent reads terminal output from a running session, it doesn't need 10,000 lines. It needs the last 80 or 200. We made output limits small by default and let agents increase them with --limit.
# What's on screen right now (compact)
runpane panels screen --panel <id> --limit 80 --json
# Recent scrollback (more context when needed)
runpane panels output --panel <id> --limit 200 --jsonAgents have limited context windows. Every extra line of output is tokens they could be using to think. Respecting the context window is the single most important thing you can do for agent UX.
6. a doctor command
Before an agent does anything, it should check that the environment is healthy. runpane doctor --json checks the wrapper version, the platform, the installed app, and whether the daemon is running. If something's wrong, the agent knows before it wastes time creating panes that will fail.
This is a small thing that saves a lot of debugging. Most CLIs have some version of this, but making it machine-readable with JSON and explicitly designing it as the first thing agents should run was a conscious decision.
7. same cli for humans and agents
We didn't build a separate "agent API." Humans and agents use the same runpane command. The difference is just flags: --json for structured output, --yes for non-interactive mode. If you know how to use runpane as a human, you know how to teach an agent to use it.
This also means we maintain one surface, not two. Bug fixes help both humans and agents. Docs cover both use cases.
the real lesson
Building a CLI for agents isn't fundamentally different from building a good CLI for humans. It's just stricter. Humans will tolerate inconsistent output, missing flags, and interactive prompts. Agents won't.
If your CLI has JSON output, a discovery mechanism, bounded defaults, non-interactive mode, and a health check, agents will figure out the rest. The principles aren't complicated. Most teams just haven't thought about them yet.
The runpane CLI is open source. Here are the actual files:
- daemon/server.ts handles CLI requests from agents
- services/cliToolRegistry.ts registers the available agent commands
- runpane-cli-contract.json is the public schema agents read before installing
Steal whatever patterns are useful. The full source is on GitHub. If you're building something similar, I'm happy to talk through it on Discord.