> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/wevm/incur/llms.txt
> Use this file to discover all available pages before exploring further.

# Output

> Learn about output formats, envelopes, and call-to-actions

## Overview

Incur normalizes all command output into a structured **envelope** with consistent shape. The envelope includes:

* **Data** — the command's return value
* **Metadata** — command name, duration, and CTAs
* **Error details** — when the command fails

By default, incur uses **TOON** format for output, which is up to **60% more token-efficient** than JSON for agents.

## Output Envelope Structure

Every command produces an output envelope with a consistent structure.

### Success Envelope

```typescript theme={null}
{
  ok: true,
  data: <command return value>,
  meta: {
    command: "my-cli deploy",
    duration: "42ms",
    cta?: { ... }  // optional
  }
}
```

### Error Envelope

```typescript theme={null}
{
  ok: false,
  error: {
    code: "NOT_AUTHENTICATED",
    message: "Token not found",
    retryable: false,  // optional
    fieldErrors: [...]  // optional, for validation errors
  },
  meta: {
    command: "my-cli deploy",
    duration: "12ms",
    cta?: { ... }  // optional
  }
}
```

## Return Values

By default, commands return data directly:

```typescript theme={null}
cli.command('status', {
  run() {
    return { clean: true, branch: 'main' }
  },
})
```

```bash theme={null}
$ my-cli status
clean: true
branch: main
```

Use `--verbose` to see the full envelope:

```bash theme={null}
$ my-cli status --verbose
ok: true
data:
  clean: true
  branch: main
meta:
  command: status
  duration: 8ms
```

## Using `c.ok()` and `c.error()`

Use `c.ok()` and `c.error()` to attach CTAs or signal structured errors.

### `c.ok()`

Return success with optional metadata:

```typescript theme={null}
cli.command('deploy', {
  run(c) {
    return c.ok(
      { deployed: true, url: 'https://staging.example.com' },
      {
        cta: {
          commands: [
            { command: 'logs', description: 'View deployment logs' },
            { command: 'status', description: 'Check status' },
          ],
        },
      }
    )
  },
})
```

```bash theme={null}
$ my-cli deploy
deployed: true
url: https://staging.example.com

Suggested commands:
  my-cli logs  # View deployment logs
  my-cli status  # Check status
```

### `c.error()`

Return a structured error:

```typescript theme={null}
cli.command('deploy', {
  run(c) {
    if (!authenticated()) {
      return c.error({
        code: 'NOT_AUTHENTICATED',
        message: 'Token not found',
        retryable: false,
        cta: {
          commands: [
            { command: 'login', description: 'Log in to continue' },
          ],
        },
      })
    }
    return { deployed: true }
  },
})
```

```bash theme={null}
$ my-cli deploy
Error (NOT_AUTHENTICATED): Token not found

Suggested commands:
  my-cli login  # Log in to continue
```

## Call-to-Actions (CTAs)

CTAs tell users (human or agent) what commands to run next. They appear after successful or failed commands.

### String CTAs

Simplest form — just the command name:

```typescript theme={null}
return c.ok(
  { items: [...] },
  {
    cta: {
      commands: ['get 1', 'list closed'],
    },
  }
)
```

```bash theme={null}
Suggested commands:
  my-cli get 1
  my-cli list closed
```

### Object CTAs

Provide structured arguments and options with descriptions:

```typescript theme={null}
return c.ok(
  { items: [...] },
  {
    cta: {
      commands: [
        {
          command: 'get',
          args: { id: 1 },
          description: 'View item details',
        },
        {
          command: 'list',
          args: { state: 'closed' },
          description: 'View closed items',
        },
      ],
    },
  }
)
```

```bash theme={null}
Suggested commands:
  my-cli get 1  # View item details
  my-cli list closed  # View closed items
```

### Type-Safe CTAs

CTAs are fully type-inferred. If your CLI has registered commands, the `command` field is typed as a union of command names:

```typescript theme={null}
cli
  .command('get', { ... })
  .command('list', { ... })
  .command('deploy', {
    run(c) {
      return c.ok(
        { deployed: true },
        {
          cta: {
            commands: [
              { command: 'get' },     // ✅ typed as 'get' | 'list' | 'deploy'
              { command: 'status' },  // ❌ type error if 'status' isn't registered
            ],
          },
        }
      )
    },
  })
```

## Output Formats

Incur supports multiple output formats. Use `--format <fmt>` or `--json` to override the default.

### TOON (default)

[TOON](https://github.com/toon-format/toon) is a token-efficient format designed for agents. It strips braces, quotes, and redundant keys.

```bash theme={null}
$ my-cli status
clean: true
branch: main
files[2]: a.txt,b.txt
```

### JSON

Standard JSON with indentation:

```bash theme={null}
$ my-cli status --json
{
  "clean": true,
  "branch": "main",
  "files": ["a.txt", "b.txt"]
}
```

### YAML

YAML format:

```bash theme={null}
$ my-cli status --format yaml
clean: true
branch: main
files:
  - a.txt
  - b.txt
```

### Markdown

Tables for flat objects and arrays:

```bash theme={null}
$ my-cli users --format md
| id | name  | email           |
|----|-------|------------------|
| 1  | Alice | alice@example.com|
| 2  | Bob   | bob@example.com  |
```

### JSONL

Newline-delimited JSON, useful for streaming:

```bash theme={null}
$ my-cli logs --format jsonl
{"type":"chunk","data":"connecting..."}
{"type":"chunk","data":"streaming logs"}
{"type":"done","ok":true}
```

## Format Priority

Formats are resolved in this order:

1. Explicit `--format` or `--json` flag
2. Command-level `format` option
3. CLI-level `format` option
4. Default (`toon`)

```typescript theme={null}
Cli.create('my-cli', {
  format: 'json',  // CLI-level default
})
  .command('deploy', {
    format: 'yaml',  // Overrides CLI default
    run() {
      return { deployed: true }
    },
  })
```

```bash theme={null}
$ my-cli deploy
# Uses YAML (command-level override)

$ my-cli deploy --json
# Uses JSON (flag override)
```

## Output Policy

Control when output data is displayed with `outputPolicy`.

### `'all'` (default)

Displays to both humans and agents:

```typescript theme={null}
cli.command('deploy', {
  outputPolicy: 'all',  // default
  run() {
    return { deployed: true }
  },
})
```

### `'agent-only'`

Suppresses data in TTY mode, but still returns it to agents:

```typescript theme={null}
cli.command('deploy', {
  outputPolicy: 'agent-only',
  run() {
    // Agents get the data; humans see nothing (unless --verbose or --json)
    return { id: 'deploy-123', url: 'https://staging.example.com' }
  },
})
```

```bash theme={null}
$ my-cli deploy
# (no output in terminal)

$ my-cli deploy --json
{"id":"deploy-123","url":"https://staging.example.com"}
```

Inheritance:

* CLI-level `outputPolicy` applies to all commands
* Group-level `outputPolicy` overrides CLI-level
* Command-level `outputPolicy` overrides group-level

## Streaming Output

Use `async *run` to stream chunks incrementally:

```typescript theme={null}
cli.command('logs', {
  async *run() {
    yield 'connecting...'
    yield 'streaming logs'
    yield { progress: 50 }
    yield { progress: 100 }
    return c.ok(undefined, {
      cta: {
        commands: [{ command: 'status', description: 'Check status' }],
      },
    })
  },
})
```

With default TOON format, each chunk is printed as a line:

```bash theme={null}
$ my-cli logs
connecting...
streaming logs
progress: 50
progress: 100

Suggested commands:
  my-cli status  # Check status
```

With `--format jsonl`, each chunk becomes a structured event:

```bash theme={null}
$ my-cli logs --format jsonl
{"type":"chunk","data":"connecting..."}
{"type":"chunk","data":"streaming logs"}
{"type":"chunk","data":{"progress":50}}
{"type":"chunk","data":{"progress":100}}
{"type":"done","ok":true,"meta":{"command":"logs","duration":"42ms"}}
```

## Error Handling

Errors are automatically captured and normalized:

### Thrown Errors

```typescript theme={null}
run() {
  throw new Error('Something went wrong')
}
```

```bash theme={null}
$ my-cli deploy
Error: Something went wrong
```

### Structured Errors

Use `c.error()` for custom error codes:

```typescript theme={null}
run(c) {
  return c.error({
    code: 'DEPLOY_FAILED',
    message: 'Could not connect to server',
    retryable: true,
  })
}
```

```bash theme={null}
$ my-cli deploy --verbose
ok: false
error:
  code: DEPLOY_FAILED
  message: Could not connect to server
  retryable: true
meta:
  command: deploy
  duration: 12ms
```

### Validation Errors

Validation errors include field-level details:

```bash theme={null}
$ my-cli deploy
Error: missing required argument <env>
```

With `--verbose`:

```bash theme={null}
$ my-cli deploy --verbose
ok: false
error:
  code: VALIDATION_ERROR
  message: Required
  fieldErrors:
    - path: env
      expected: string
      received: undefined
      message: Required
meta:
  command: deploy
  duration: 3ms
```

## Next Steps

<CardGroup cols={2}>
  <Card title="CLI Creation" icon="terminal" href="/core-concepts/cli-creation">
    Learn how to create and configure CLIs
  </Card>

  <Card title="Middleware" icon="layer-group" href="/features/middleware">
    Explore middleware for composable hooks
  </Card>
</CardGroup>
