Designing a CLI for AI agents

The geenius-mvp CLI has two users: a human at a terminal and an AI agent in a tool-use loop. They want different things. The human wants a wizard; the agent wants structured data, deterministic behavior, and errors it can act on without guessing. Designing for the second user made the CLI better for both.

One call for total discovery

An agent's first problem is discovery: what can this tool even do? Instead of making it grep help text, pnpm new --list --json returns the entire capability surface in one call. Here is a trimmed slice of the real output:

{
  "tool": "geenius-mvp",
  "version": "0.1.0",
  "types": {
    "webapp": { "backend": true, "singlePage": false },
    "website-blog": { "backend": false, "singlePage": false }
  },
  "stacks": {
    "react": "Vite + React + shell (all types)",
    "static": "HTML + JS + vanilla CSS BEM (website types only)"
  },
  "dbs": {
    "convex": {
      "features": ["example", "records", "activity", "api-keys",
        "team", "billing", "admin", "inbox", "feedback", "ai",
        "uploads", "mcp"],
      "idiom": "reactive queries, Better Auth"
    }
  },
  "layouts": ["sidebar", "header", "windows", "macos"],
  "deployProviders": ["cloudflare", "vercel", "netlify",
    "surge", "heroku", "github-pages"],
  "notes": {
    "mcp": "mcp feature implies api-keys; gives each app an MCP server with OAuth 2.1 for chat apps",
    "afterScaffold": ["pnpm install",
      "cd apps/<slug> && npx convex dev --once (convex only)",
      "pnpm exec tsc --noEmit", "pnpm deploy <slug>"]
  }
}

Types, stacks, per-db feature pools, all 100 designs with categories, 18 accents, layouts, deploy providers, and even the recommended next steps after scaffolding. The manifest is generated from the same modules the scaffolder executes — the design catalog is parsed out of the shell's chrome.ts, the feature pool derives from one FEATURES object — so it cannot drift from reality.

The @geenius-mvp:result line

Long-running commands print human-readable progress, which is noise to a parser. So with --json, scaffold and deploy end with a single marked line: @geenius-mvp:result followed by a JSON object containing the slug, directory, port, enabled features, and next steps — or, for deploy, the live URL. An agent parses exactly one line and ignores everything above it. Exit code 0 means success; non-zero means the printed error tells you what to change.

Doctor checks that hand you the fix

pnpm doctor --json inspects environment readiness, and every failing check includes the exact command that repairs it. This is the pattern that matters most for agent loops: an error message that names its fix collapses a whole debugging excursion into one tool call. The agent reads the failure, runs the printed command, and retries. The same discipline runs through the scaffolder — flags are validated with the fix in every error — and through deploy, where failures print the failing provider step inline.

AGENTS.md as the canonical playbook

Structured output covers the mechanics, but agents also need judgment: which pattern to clone, which rules never to violate. That lives in AGENTS.md — a 60-second quickstart, the full CLI surface, the recipe for building a real domain, and a section of rules learned the hard way, like never running convex dev --configure=new on an app that already has a .env.local, because that mints a duplicate cloud project. CLAUDE.md and every agent entry point defer to it, and repo policy is that any CLI behavior change updates AGENTS.md in the same commit.

Non-interactive by default, validated flags with the fix in every error, idempotent deploys, stable exit codes.

None of this is exotic engineering. It is the discipline of treating your CLI's output as an API — because for your fastest-growing user base, it is one.

← All posts