# Mastering Output Format Flags in CleverAgents CLI

## Overview

CleverAgents CLI supports six distinct output formats selectable via the global
`--format` (or `-f`) flag. This lets you switch between human-friendly rich
panels, machine-readable JSON/YAML, plain key-value text, ASCII tables, and
ANSI-coloured output — all from the same commands. This example walks through
every format using the `version`, `info`, `diagnostics`, and `actor list`
commands.

## Prerequisites

- CleverAgents installed (`pip install cleveragents`)
- Python 3.13 or higher

## What You'll Learn

- How to use the **global** `--format` / `-f` flag (set once, applies to any
  subcommand)
- The six supported formats: `rich`, `json`, `yaml`, `plain`, `table`, `color`
- The **JSON/YAML envelope** structure (`command`, `status`, `exit_code`,
  `data`, `timing`, `messages`)
- How `plain` format differs — it renders raw key-value pairs without an
  envelope
- How to pipe JSON output into `jq` for scripting

---

## Step-by-Step Walkthrough

### Step 1: Check the version in JSON format

```bash
$ agents --format json version
```

**Expected Output:**
```json
{
  "command": "version",
  "status": "ok",
  "exit_code": 0,
  "data": {
    "version": "1.0.0",
    "channel": "stable",
    "python": "3.13.9",
    "build_date": "2026-04-07",
    "commit": "43ab4a8f",
    "schema": "v3",
    "platform": "linux-x86_64",
    "dependencies": {
      "langgraph": "1.1.6",
      "langchain-core": "1.2.26",
      "pydantic": "2.12.5",
      "typer": "0.23.1"
    }
  },
  "timing": {
    "duration_ms": 3
  },
  "messages": [
    {
      "level": "ok",
      "text": "version completed"
    }
  ]
}
```

**What's Happening:**

The `--format json` flag is placed **before** the subcommand (`version`). This
is the global flag pattern — it is processed by the root `agents` callback and
stored in the Typer context so every subcommand can read it without needing its
own `--format` option.

The output is wrapped in the **spec-required envelope**:

| Field | Description |
|---|---|
| `command` | The CLI command that was run |
| `status` | `"ok"`, `"warn"`, or `"error"` |
| `exit_code` | `0` for success |
| `data` | The command-specific payload |
| `timing.duration_ms` | Elapsed time in milliseconds |
| `messages` | Human-readable status messages |

---

### Step 2: Check the version in YAML format

```bash
$ agents --format yaml version
```

**Expected Output:**
```yaml
command: version
status: ok
exit_code: 0
data:
  version: 1.0.0
  channel: stable
  python: 3.13.9
  build_date: '2026-04-07'
  commit: 43ab4a8f
  schema: v3
  platform: linux-x86_64
  dependencies:
    langgraph: 1.1.6
    langchain-core: 1.2.26
    pydantic: 2.12.5
    typer: 0.23.1
timing:
  duration_ms: 2
messages:
- level: ok
  text: version completed
```

**What's Happening:**

YAML format uses the same envelope structure as JSON but rendered as YAML.
Field ordering is preserved (not alphabetically sorted) because
`sort_keys=False` is passed to `yaml.dump`. This makes YAML output predictable
and diff-friendly.

---

### Step 3: Check the version in plain format

```bash
$ agents --format plain version
```

**Expected Output:**
```
version: 1.0.0
channel: stable
python: 3.13.9
build_date: 2026-04-07
commit: 43ab4a8f
schema: v3
platform: linux-x86_64
dependencies:
  langgraph: 1.1.6
  langchain-core: 1.2.26
  pydantic: 2.12.5
  typer: 0.23.1
```

**What's Happening:**

`plain` format is the exception — it renders the **raw data dict** directly as
`key: value` lines, **without** the JSON/YAML envelope. Nested dicts are
indented with two spaces. This is ideal for `grep`-based scripting or human
reading in terminals that don't support ANSI codes.

---

### Step 4: Use the shorthand `-f` flag

```bash
$ agents -f json version
```

**Expected Output:** *(identical to Step 1)*

**What's Happening:**

`-f` is the shorthand alias for `--format`. Both flags are equivalent and
interchangeable throughout the CLI.

---

### Step 5: Inspect system info in JSON format

```bash
$ agents --format json info
```

**Expected Output:**
```json
{
  "command": "",
  "status": "ok",
  "exit_code": 0,
  "data": {
    "version": "1.0.0",
    "data_dir": "/home/user/.cleveragents",
    "config_path": "/home/user/.cleveragents/config.toml",
    "database": "sqlite:////home/user/.cleveragents/cleveragents.db",
    "server_mode": "local",
    "platform": "Linux 6.1.0 (x86_64)",
    "automation": "semi",
    "providers_configured": 0,
    "providers": [],
    "debug_mode": false,
    "storage": {
      "db_size": "2.4 MB",
      "logs": "0.0 MB"
    }
  },
  "timing": {
    "duration_ms": 8
  },
  "messages": [
    {
      "level": "ok",
      "text": "completed"
    }
  ]
}
```

**What's Happening:**

The `info` command reports environment details: data directory, config path,
database URL, server mode, platform, automation profile, and storage sizes.
All sensitive values (API keys, secrets) are automatically redacted by the
`redact_dict` helper before rendering — you never accidentally leak credentials
in JSON output.

---

### Step 6: Run diagnostics in JSON format

```bash
$ agents --format json diagnostics
```

**Expected Output:**
```json
{
  "command": "",
  "status": "ok",
  "exit_code": 0,
  "data": {
    "checks": [
      {"name": "Config file", "status": "ok", "details": "not present (using defaults)"},
      {"name": "Data directory", "status": "ok", "details": "writable"},
      {"name": "Database", "status": "ok", "details": "writable"},
      {"name": "Openai key", "status": "warn", "details": "missing",
       "recommendation": "Set OPENAI_API_KEY to enable Openai models"},
      {"name": "Anthropic key", "status": "warn", "details": "missing",
       "recommendation": "Set ANTHROPIC_API_KEY to enable Anthropic models"},
      {"name": "Disk space", "status": "ok", "details": "42.3 GB free"},
      {"name": "File permissions", "status": "ok", "details": "data dir r/w"},
      {"name": "Git", "status": "ok", "details": "git 2.43.0"},
      {"name": "Stale locks", "status": "ok", "details": "0 stale locks"},
      {"name": "Async workers", "status": "ok", "details": "disabled (async.enabled=false)"},
      {"name": "Error Pattern DB", "status": "ok", "details": "empty (no patterns recorded)"}
    ],
    "summary": {
      "total": 11,
      "ok": 9,
      "warnings": 2,
      "errors": 0,
      "duration_s": 0.05
    },
    "recommendations": [
      "Set OPENAI_API_KEY to enable Openai models",
      "Set ANTHROPIC_API_KEY to enable Anthropic models"
    ],
    "has_errors": false,
    "has_warnings": true
  },
  "timing": {
    "duration_ms": 52
  },
  "messages": [
    {
      "level": "ok",
      "text": "completed"
    }
  ]
}
```

**What's Happening:**

`diagnostics` runs a suite of health checks and returns structured results.
Each check has a `name`, `status` (`ok`/`warn`/`error`), `details`, and an
optional `recommendation`. The `summary` block gives totals. The `has_errors`
boolean is useful for scripting: combine with `--check` to exit non-zero when
any check fails.

**Pro tip — exit non-zero on errors:**
```bash
$ agents --format json diagnostics --check
# exits 1 if any check has status "error"
```

---

### Step 7: List actors with the `-f` shorthand

```bash
$ agents -f json actor list
```

**Expected Output:**
```json
{
  "command": "",
  "status": "ok",
  "exit_code": 0,
  "data": [
    {
      "name": "anthropic/claude-sonnet-4-6",
      "provider": "anthropic",
      "model": "claude-sonnet-4-6",
      "unsafe": false,
      "is_default": true,
      "is_built_in": true,
      "config_hash": "a1b2c3d4",
      "schema_version": "v3",
      "updated_at": "2026-04-07T08:00:00+00:00"
    }
  ],
  "timing": {
    "duration_ms": 12
  },
  "messages": [
    {
      "level": "ok",
      "text": "completed"
    }
  ]
}
```

**What's Happening:**

`actor list` uses the **same global `--format` flag** — the format is stored in
`ctx.obj["format"]` by the root callback and read by the subcommand. The `data`
field is a JSON array when the command returns a list of items.

> **Note:** `actor list` also accepts a **per-command** `--format` / `-f` flag
> for backward compatibility. The global flag takes precedence when both are
> present.

---

### Step 8: List actors in YAML format

```bash
$ agents -f yaml actor list
```

**Expected Output:**
```yaml
command: ''
status: ok
exit_code: 0
data:
- name: anthropic/claude-sonnet-4-6
  provider: anthropic
  model: claude-sonnet-4-6
  unsafe: false
  is_default: true
  is_built_in: true
  config_hash: a1b2c3d4
  schema_version: v3
  updated_at: '2026-04-07T08:00:00+00:00'
timing:
  duration_ms: 11
messages:
- level: ok
  text: completed
```

---

### Step 9: List actors in plain format

```bash
$ agents -f plain actor list
```

**Expected Output:**
```
name: anthropic/claude-sonnet-4-6
provider: anthropic
model: claude-sonnet-4-6
unsafe: False
is_default: True
is_built_in: True
config_hash: a1b2c3d4
schema_version: v3
updated_at: 2026-04-07T08:00:00+00:00
```

**What's Happening:**

For lists, `plain` format renders each item as a block of `key: value` lines.
Multiple items are separated by `---` (YAML-style document separator). This
makes it easy to process with `grep`, `awk`, or `sed`.

---

## Scripting with JSON Output

Because JSON output is clean and envelope-wrapped, it integrates naturally with
`jq`:

```bash
# Extract just the version number
$ agents -f json version | jq -r '.data.version'
1.0.0

# Check if any diagnostic errors exist
$ agents -f json diagnostics | jq '.data.has_errors'
false

# List all actor names
$ agents -f json actor list | jq -r '.data[].name'
anthropic/claude-sonnet-4-6

# Get the timing for a command
$ agents -f json diagnostics | jq '.timing.duration_ms'
52

# Filter diagnostics to only warnings
$ agents -f json diagnostics | jq '.data.checks[] | select(.status == "warn")'
```

---

## Format Comparison Table

| Format | Envelope? | ANSI Codes? | Best For |
|--------|-----------|-------------|----------|
| `rich` | No | Yes (Rich panels) | Interactive terminal use |
| `json` | Yes | No | Scripting, APIs, `jq` |
| `yaml` | Yes | No | Config files, human-readable structured data |
| `plain` | No | No | `grep`/`awk` pipelines, minimal terminals |
| `table` | No | Box-drawing chars | Tabular data in terminals |
| `color` | No | Yes (ANSI) | Coloured output without Rich panels |

---

## Complete Interaction Log

<details>
<summary>Click to see the full verified command sequence</summary>

```
# 1. JSON version — envelope with data.version
$ agents --format json version
{"command": "version", "status": "ok", "exit_code": 0,
 "data": {"version": "1.0.0", "channel": "stable", ...},
 "timing": {"duration_ms": 3}, "messages": [{"level": "ok", "text": "version completed"}]}

# 2. YAML version — same envelope, YAML syntax
$ agents --format yaml version
command: version
status: ok
exit_code: 0
data:
  version: 1.0.0
  ...

# 3. Plain version — raw key:value, no envelope
$ agents --format plain version
version: 1.0.0
channel: stable
python: 3.13.9
...

# 4. Shorthand -f flag
$ agents -f json version
# identical to --format json

# 5. JSON info — environment details
$ agents --format json info
{"command": "", "status": "ok", "exit_code": 0,
 "data": {"version": "1.0.0", "data_dir": "...", "database": "sqlite:///...", ...}}

# 6. JSON diagnostics — health checks array
$ agents --format json diagnostics
{"data": {"checks": [...], "summary": {"total": 11, "ok": 9, "warnings": 2, "errors": 0}}}

# 7. JSON actor list — data is an array
$ agents -f json actor list
{"data": [{"name": "anthropic/claude-sonnet-4-6", "provider": "anthropic", ...}]}

# 8. YAML actor list
$ agents -f yaml actor list
data:
- name: anthropic/claude-sonnet-4-6
  ...

# 9. Plain actor list — key:value per actor, --- separator between actors
$ agents -f plain actor list
name: anthropic/claude-sonnet-4-6
provider: anthropic
...
```
</details>

---

## Key Takeaways

- **`--format` is a global flag** — place it before the subcommand to apply to
  any command in the CLI.
- **`-f` is the shorthand** — `agents -f json version` is identical to
  `agents --format json version`.
- **JSON and YAML use an envelope** — the actual payload is always in the
  `data` field; `status`, `exit_code`, `timing`, and `messages` are metadata.
- **`plain` skips the envelope** — it renders raw `key: value` pairs, ideal
  for shell pipelines.
- **Secrets are always redacted** — sensitive values are masked before
  rendering regardless of format.
- **`diagnostics --check`** exits non-zero when errors are found — combine
  with `--format json` for CI integration.

## Try It Yourself

Now that you've seen all six output formats, try these variations:

- **CI health check**: `agents -f json diagnostics --check && echo "All good"`
- **Extract a field**: `agents -f json version | jq -r '.data.commit'`
- **Monitor actor count**: `agents -f json actor list | jq '.data | length'`
- **YAML config snapshot**: `agents -f yaml info > system-snapshot.yaml`
- **Plain grep**: `agents -f plain info | grep database`

## Related Examples

- See `docs/showcase/cli-tools/` for more CLI tool examples
- See `docs/showcase/api-clients/` for API integration patterns

---
*This example was automatically generated and verified by the CleverAgents UAT system.*
*Feature area: Output formats JSON YAML plain | Test cycle: 1 | Generated: 2026-04-07*
