DEV Community

Marta Karaś
Marta Karaś

Posted on

Building a CLI for Humans and AI Agents

Most CLIs are built for humans. Some are built for scripts. We built one for both — and for AI agents too.

DeployHQ CLI (dhq) is a Go command-line tool for the DeployHQ deployment platform. It manages projects, servers, deployments, and releases. But what makes it different is that it was designed from day one to work equally well when a human is typing, when a shell script is piping, or when an AI agent is orchestrating.

Here's what that looks like in practice.

The Output Contract

The single most important design decision: stdout is always data, stderr is always human text.

# Human sees a nice table on stderr, data goes to stdout
dhq projects list

# Pipe it and get JSON automatically — no flag needed
dhq projects list | jq '.data[].name'
Enter fullscreen mode Exit fullscreen mode

When stdout is a TTY, you get a formatted table. When it's piped, you get JSON. No --json flag required (though you can use it explicitly).


Field Selection with --json

Most CLIs give you --json and dump everything. We give you --json <fields>:

# Only get what you need
dhq deployments list -p my-app --json identifier,status,timestamps.duration

# An agent requesting just the deployment ID and status
dhq deploy -p my-app -s prod --use-latest --json identifier,status
Enter fullscreen mode Exit fullscreen mode

This matters for agents because tokens cost money. A full deployment object might be 50+ fields. An agent checking status needs two.


Breadcrumbs: Teaching Agents What To Do Next

Every JSON response includes a breadcrumbs array — suggested next commands based on what just happened:

{
  "data": { "identifier": "abc123", "status": "completed" },
  "breadcrumbs": [
    "dhq deployments logs abc123 -p my-app",
    "dhq deployments show abc123 -p my-app --json"
  ]
}
Enter fullscreen mode Exit fullscreen mode

An AI agent doesn't need to memorize your API. It reads the breadcrumbs and knows what's possible next. This turns a stateless CLI into a guided workflow.


Agent Detection

The CLI detects when it's being used by an agent:

export DEPLOYHQ_AGENT=1      # Explicit agent mode
export CLAUDE_CODE=1          # Auto-detected
export CI=true                # Auto-detected
Enter fullscreen mode Exit fullscreen mode

In agent mode, the CLI adjusts its behavior — suppressing interactive prompts, defaulting to structured output, and including richer metadata.


JSONL Capture

Set DEPLOYHQ_OUTPUT_FILE=log.jsonl and every command's output gets appended as a JSONL line. Useful for:

  • Agent audit trails
  • CI pipeline debugging
  • Replaying what happened during an automated workflow

Non-Interactive Auth

Three env vars, no browser popup:

export DEPLOYHQ_ACCOUNT=myaccount
export DEPLOYHQ_EMAIL=me@example.com
export DEPLOYHQ_API_KEY=abc123
Enter fullscreen mode Exit fullscreen mode

This is table stakes for CI, but it matters even more for agents. An AI agent can't click "Authorize" in a browser.


Exit Codes That Mean Something

  • 0 — success
  • 1 — failure (with structured error in JSON)
  • Empty results return 0 with empty data — that's not an error

Simple, but surprisingly rare. Many CLIs return 0 on errors or don't include error details in their JSON output.


The Go SDK Inside

The CLI wraps a public Go SDK at pkg/sdk/ with 97 methods. The SDK has zero internal imports — it's designed to be extractable as a standalone module:

client := sdk.NewClient("account", "email", "apikey")
projects, err := client.ListProjects()
Enter fullscreen mode Exit fullscreen mode

If you're building Go tooling around DeployHQ, you can use the SDK directly without shelling out to the CLI.


What We Learned

Building for agents changed how we think about CLIs:

  1. Structured output isn't optional — if your CLI can't produce JSON, agents can't use it reliably
  2. Field selection saves tokens — agents pay per token, don't make them parse 50 fields to get 2
  3. Breadcrumbs beat documentation — agents don't read man pages, but they read JSON responses
  4. Non-interactive is non-negotiable — if it needs a human to click something, agents can't use it
  5. Piped detection is free UX — detect TTY vs pipe and adjust automatically

The future of CLIs isn't human OR machine. It's both.


Links:

Top comments (0)