Skip to main content
Output policy controls whether output data is displayed to humans in TTY mode while still returning it to agents via --json, --format, or --verbose.

Overview

By default, all command output is displayed to everyone ('all'). Set outputPolicy: 'agent-only' to suppress data output in human/TTY mode while still returning structured data to agents.
cli.command('deploy', {
  outputPolicy: 'agent-only',
  run() {
    // Agents get the structured data; humans see nothing (or just CTAs/errors)
    return { id: 'deploy-123', url: 'https://staging.example.com' }
  },
})

Use Cases

Internal Commands

Commands designed for agent-only use that produce verbose machine-readable output:
cli.command('sync', {
  outputPolicy: 'agent-only',
  run() {
    return {
      synced: true,
      files: 142,
      bytes: 8_432_123,
      checksum: 'a3f5e9c2...',
    }
  },
})
# Human mode (TTY)
$ my-cli sync
# (no output)

# Agent mode (piped or --json)
$ my-cli sync --json
# → {"ok":true,"data":{"synced":true,"files":142,...}}

Commands with Side Effects

Commands that perform actions but don’t need to display data:
cli.command('publish', {
  outputPolicy: 'agent-only',
  run(c) {
    return c.ok(
      { version: '1.2.3', published: true },
      {
        cta: {
          commands: [
            { command: 'status', description: 'View publication status' },
          ],
        },
      },
    )
  },
})
# Human mode: sees CTAs but not the data
$ my-cli publish
# Next:
#   my-cli status – View publication status

# Agent mode: sees full output
$ my-cli publish --json
# → {"ok":true,"data":{"version":"1.2.3","published":true},...}

Inheritance

Set outputPolicy on a group or root CLI to inherit across all children:
const internal = Cli.create('internal', {
  description: 'Internal commands',
  outputPolicy: 'agent-only',
})

internal.command('sync', { run: () => ({ synced: true }) }) // inherits agent-only
internal.command('status', {
  outputPolicy: 'all', // overrides to show output
  run: () => ({ ok: true }),
})

CLI-Level Policy

Set outputPolicy at the CLI level to apply to all commands by default:
Cli.create('my-cli', {
  description: 'My CLI',
  outputPolicy: 'agent-only',
})
  .command('deploy', { run: () => ({ deployed: true }) }) // inherits agent-only
  .command('status', {
    outputPolicy: 'all', // override for this command
    run: () => ({ ok: true }),
  })
  .serve()

Behavior Details

Human Mode (TTY)

When outputPolicy: 'agent-only' and stdout is a TTY:
  • Data output is suppressed — return value is not displayed
  • Errors are still shownerror() calls display normally
  • CTAs are still shownok() and error() CTAs display normally
  • --json overrides — explicit format flags show data
  • --verbose overrides — full envelope is shown

Agent Mode (Non-TTY)

When stdout is not a TTY (piped, redirected, or consumed by an agent):
  • Data is always included — regardless of outputPolicy
  • Full envelope format — agents always see structured output

Forcing Data Display

Humans can override agent-only with explicit format flags:
$ my-cli deploy --json
# → {"ok":true,"data":{"id":"deploy-123",...}}

$ my-cli deploy --format yaml
# → ok: true
# → data:
# →   id: deploy-123
# →   url: https://staging.example.com

$ my-cli deploy --verbose
# → ok: true
# → data:
# →   id: deploy-123
# →   url: https://staging.example.com
# → meta:
# →   command: deploy
# →   duration: 3200ms

Policy Values

ValueDescription
'all'Displays to both humans and agents (default)
'agent-only'Suppresses data output in human/TTY mode while still returning it to agents

When to Use

Use 'agent-only' for:
  • Commands designed for agent orchestration
  • Internal commands that produce verbose machine-readable output
  • Commands where the side effect matters more than the return value
  • Commands that use CTAs to guide users instead of showing raw data
Use 'all' (default) for:
  • Commands where the output is the primary value (queries, reports)
  • Commands humans invoke directly
  • Commands with concise, human-readable output

Build docs developers (and LLMs) love