Skip to main content

Output Triple

Every CLI command in The Shift Platform supports three output modes. This pattern ensures that the same command works well for human operators in a terminal, AI agents parsing structured data, and scripts that only care about success or failure.

The Three Modes

Human (default)

Chalk-colored, formatted output designed for terminal readability. This is what you see when you run a command with no flags.

$ shift-cli yp services list

Services (3)

NAME OWNER SYSTEM LANGUAGE
────────────────────────────────────────────────────
auth-service platform core TypeScript
billing-api payments billing TypeScript
email-worker comms messaging Python

JSON (--json)

Structured JSON output for agent and script consumption. All data is emitted as a single JSON object to stdout with no decorative formatting.

$ shift-cli yp services list --json
[
{
"id": "abc12345",
"name": "auth-service",
"owner": "platform",
"system": "core",
"language": "TypeScript"
},
{
"id": "def67890",
"name": "billing-api",
"owner": "payments",
"system": "billing",
"language": "TypeScript"
},
{
"id": "ghi24680",
"name": "email-worker",
"owner": "comms",
"system": "messaging",
"language": "Python"
}
]

Quiet (--quiet)

No stdout output at all. The command communicates purely through its exit code. Useful for conditional logic in shell scripts.

$ shift-cli yp services get auth-service --quiet
$ echo $?
0

$ shift-cli yp services get nonexistent --quiet
$ echo $?
4

The output() Helper

The output() function from @shift/platform-core/output handles mode selection. It accepts the global options and a set of handler functions:

import { output, success, table } from "@shift/platform-core/output";

output(options, {
json: () => services,
quiet: () => {},
human: () => {
success(`Services (${services.length})`);
table(services, [
{ key: "name", label: "NAME" },
{ key: "owner", label: "OWNER" },
{ key: "system", label: "SYSTEM" },
{ key: "language", label: "LANGUAGE" },
]);
},
});

The output() function checks the flags in order:

  1. If options.json is true and a json handler is provided, it serializes the return value as formatted JSON via jsonOutput().
  2. If options.quiet is true and a quiet handler is provided, it calls that handler (which typically does nothing).
  3. Otherwise, it calls the human handler.

OutputOptions Interface

interface OutputOptions {
json?: boolean;
quiet?: boolean;
}

These flags come from Commander's global options, propagated via optsWithGlobals():

program
.option("--json", "Output as JSON")
.option("--quiet", "Suppress output, exit code only");

Additional Output Helpers

The @shift/platform-core/output module also exports helpers used within human-mode handlers:

HelperPurpose
success(msg)Green checkmark + message
info(msg)Blue info icon + message
warn(msg)Yellow warning icon + message
error(msg)Red cross + message
bold(s)Bold text
dim(s)Dimmed text
cmd(s)Cyan text (for command references)
bullet(msg)Green bullet point
header(title)Section header with spacing
table(rows, columns)Aligned table output
barChart(items)Horizontal bar chart

Why This Matters for AI Agents

AI coding agents need to consume CLI output programmatically. The Output Triple pattern means:

  • Agents use --json to get structured data they can parse reliably, without scraping formatted terminal output.
  • Scripts use --quiet combined with exit codes for conditional control flow (if shift-cli yp services get my-service --quiet; then ...).
  • Humans get readable output by default, with no extra flags needed.

This eliminates the common problem of agents trying to parse human-formatted output with regex or string manipulation, which breaks whenever formatting changes.