# CLI contract
This document defines the stable Texio 0.x command-line contract. Changes that
break documented syntax, output schemas, or exit-code meanings require a minor
version release and release-note migration guidance.
## Input and output
`FILE` accepts a UTF-8 Markdown path. Use `-` to read the document from stdin
for `headings`, `section`, and non-writing `replace` operations. `--from -`
reads replacement content from stdin; a command cannot use stdin for both the
document and its replacement.
Normal results go to stdout. Diagnostics go to stderr. Commands never prompt.
```text
texio headings FILE [--json]
texio section FILE HEADING [--body-only] [--json]
```
Replacement always requires one explicit mode:
- `--write` atomically updates a filesystem path.
- `--dry-run` prints a unified diff and changes nothing.
- `--stdout` prints the complete updated document and changes nothing.
`--write` is rejected when the document is read from stdin.
## JSON
`headings --json` returns an array of objects with `level` and `title`.
`section --json` returns an object with `heading`, `level`, and `content`.
Output is one compact JSON value followed by a newline.
Pass `--error-format json` anywhere in a command to emit runtime failures as one
JSON object on stderr:
```json
{"error":{"code":"section_not_found","message":"section not found: Missing"}}
```
The error object and its string `code` are stable. Runtime codes are `usage`,
`input`, `section_not_found`, `ambiguous_section`, and `write`. Command-line
syntax errors are generated by the argument parser and remain human-readable.
## Exit codes
| 0 | Success |
| 2 | Invalid command line or unsafe input/output combination |
| 3 | Input could not be read as UTF-8 Markdown |
| 4 | Requested section was not found |
| 5 | Section name was ambiguous |
| 6 | Atomic write failed |
Successful `--dry-run` exits with 0 even when the preview contains changes.