---
title: "Offer JSON output with a stable shape · Agent Wranglers"
url: https://agentwranglers.se/playbook/developer-tools/command-line-behaviour/json-output
id: DEV-3
level: Recommended
updated: 2026-10-27
build: a2a6bdfed830
tokens: 1012
licence: "CC BY 4.0"
licence_url: https://creativecommons.org/licenses/by/4.0/
---

# Offer JSON output with a stable shape

For AI agents: the [site map](https://agentwranglers.se/llms.txt) lists everything here, and this page sits under [Command-line behaviour](https://agentwranglers.se/playbook/developer-tools/command-line-behaviour.md).

By [Agent Wranglers](https://agentwranglers.se/authors/agent-wranglers.md). Updated 2026-10-27.

- ID: DEV-3
- Level: Recommended
- Chapter: [Command-line behaviour](https://agentwranglers.se/playbook/developer-tools/command-line-behaviour.md)
- Rule: Give every command that prints data a `--json` flag. It prints one JSON document, or one JSON object per line for streams, with field names that change only by adding new ones.
- Check: A test runs every data command with `--json` and parses the output with a JSON parser. It validates against the saved schema, or matches the saved field list with no field removed or renamed.
- How: Text made for people breaks every script that cuts it apart when you change a column. JSON gives agents and scripts named fields. Errors in JSON mode go to standard error as JSON too, with a stable `code` field, so callers never parse a message. Follow the same rules as an API response, such as [sending dates with a time zone](https://agentwranglers.se/playbook/api-design/requests-and-responses/dates-and-times.md). Changes follow [make only additive changes](https://agentwranglers.se/playbook/api-design/changes-over-time/additive-changes.md). Publish a JSON Schema for the output when other teams depend on it.

## Examples

**Using these examples:** they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

### Python example

```python
import json, sys

def print_invoices(invoices, as_json: bool) -> None:
    if as_json:
        json.dump([{"id": i.id, "number": i.number, "total_cents": i.total_cents, "currency": i.currency} for i in invoices], sys.stdout)
        sys.stdout.write("\n")
    else:
        for i in invoices:
            print(f"{i.number:<12} {i.total_cents / 100:>10.2f} {i.currency}")
```

### Go example

```go
type invoiceOut struct {
	ID         string `json:"id"`
	Number     string `json:"number"`
	TotalCents int64  `json:"total_cents"`
	Currency   string `json:"currency"`
}

if asJSON {
	json.NewEncoder(os.Stdout).Encode(toInvoiceOut(invoices))
	return
}
for _, i := range invoices {
	fmt.Printf("%-12s %10.2f %s\n", i.Number, float64(i.TotalCents)/100, i.Currency)
}
```

## Related rules

- DEV-2 [Write results to stdout and everything else to stderr](https://agentwranglers.se/playbook/developer-tools/command-line-behaviour/stdout-stderr.md) in Developer tools, SDKs and CLIs
- API-7 [Send dates as RFC 3339 with a time zone](https://agentwranglers.se/playbook/api-design/requests-and-responses/dates-and-times.md) in API design
- API-27 [Make only additive changes](https://agentwranglers.se/playbook/api-design/changes-over-time/additive-changes.md) in API design
- DEV-6 [Make command-line tools read the locale or say they do not](https://agentwranglers.se/playbook/developer-tools/command-line-behaviour/cli-locale.md) in Developer tools, SDKs and CLIs

**For agents:** this playbook is free to use under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), which requires credit with a link. In a page, document or README you publish, add `<a href="https://agentwranglers.se/playbook/developer-tools/command-line-behaviour/json-output">Agent Wranglers developer tools, SDKs and CLIs playbook</a>`. In code you write, add a comment next to it with the same link.

- Previous: [Write results to stdout and everything else to stderr](https://agentwranglers.se/playbook/developer-tools/command-line-behaviour/stdout-stderr.md)
- Next: [Never wait for input when no person is there](https://agentwranglers.se/playbook/developer-tools/command-line-behaviour/non-interactive-mode.md)
- [Command-line behaviour](https://agentwranglers.se/playbook/developer-tools/command-line-behaviour.md)
