Most CLIs can be automated if you fight them. You find the undocumented flag that skips the wizard, you parse a table that was formatted for a human, and then a release changes the column widths and your script goes quietly wrong.
Pithy’s CLI is built the other way around, because the kit is agent-drivable by design rather than by accident. Humans and agents drive the same commands, and the machine path is the specified one rather than the escape hatch.
Three rules, and they hold everywhere.
1. Full flags. Nothing is prompt-only
Every value a prompt would ask for has a flag that supplies it. There is no question the CLI can ask that a flag cannot answer, and no command whose only path to a value is a human typing it.
Where a capability’s config option has no default, --set key=value supplies it, repeatably. That is not a workaround — an option with no default is the capability’s statement that the answer is yours to give, and --set is where you give it.
2. No required prompt
--json suppresses every prompt in the CLI. So does the absence of a TTY.
What matters is what happens next, and it is the same answer every time: the command refuses, and names the flag. It does not pick a default, and it does not proceed with a value nobody gave.
$ pithy add auth --json
{"error":{"message":"auth requires secrets and email, which api does not compose.","action":"Run pithy add auth --with-prerequisites, or compose them first: pithy add secrets, then pithy add email."}}That is the whole design decision, and it is worth stating plainly: composing capabilities nobody asked for is not a thing to do behind an adopter’s back, and reporting Done. on a project that cannot boot is worse. A prompt where there is somebody to ask, and a flag where there is not.
The same rule covers pithy init (which scaffolds with the flags it was given and writes no credentials), pithy add --worker in a project with several Workers, and pithy provision --confirm for a production environment — that last one meaning a headless production provision happens only when a person wrote the confirmation phrase into the pipeline on purpose.
3. --json everywhere, one line, one object
Every command takes --json. The payload goes to stdout as a single line; everything else — progress, warnings, the update notifier — goes to stderr, so a pipeline capturing stdout gets clean input and a readable log at the same time.
A failure is one {"error": …} line on stderr and a non-zero exit. Exit codes has the contract, including how a command that died partway through reports what it changed on the way.
The payload is documented per command, and the documentation is gated. A test in the kit reads every command page and holds it to naming every key that command’s --json payload emits. A key added without a docs line fails the build in front of whoever added it, which is what keeps the reference from drifting the way hand-written reference usually does.
The one exception
pithy remove is destructive, and it is manual and interactive only. Passing --json fast-fails before anything changes.
That is not an oversight to be worked around. Automated teardown of an environment is a real need and it has a real command — the pithy feature lifecycle, which creates and destroys ephemeral environments per branch and runs headless end to end. Removing a capability from a checked-in Worker is a different act, and it stays a deliberate one.
What this buys an agent
An agent driving this CLI can scaffold a project, compose capabilities, migrate, provision, deploy, and read back the state of every environment — without a screenshot, a browser, or a heuristic about when a command has finished.
Three things make that work in practice:
- Idempotence. Every lifecycle command is safe to re-run. A second
pithy add authchanges nothing; a secondpithy migrateprintsNothing to migrate.;pithy provisionadopts a resource of the right name rather than creating a second one. An agent that loses track of what it already did can simply run the command again. - Errors carry the remedy. Every failure has an
actionfield naming the command, config key or account step that resolves it. An agent can act on the error rather than searching for what it means. pithy doctor --jsonis one call for the whole state. What is composed, what is bound, what has drifted, what is not provisioned yet, and which of those are findings rather than steps not yet taken. It is the first thing to run when the model of the project and the project disagree.
Point your agent at these docs
The documentation is also available over MCP, so an agent can search and fetch these pages rather than guessing at flag names from its training data.
Search these docs from an agent has the URL and a config snippet per client.