# Machine-Readable Output Strategy

Pre-v1 design: a single `--json` mode across engine commands so tools and CI can parse results without scraping human-oriented text.

## Goals

- **One flag, consistent contract:** `--json` on compile, build, help, drill (and any other top-level engine commands) emits structured data on stdout.
- **Humans vs machines:** default behavior keeps progress, errors, and narrative on stderr where appropriate and normal data on stdout; JSON mode concentrates machine-parseable output on stdout.
- **Stable shapes** for diagnostics and build artifacts so editors, linters, and CI can branch on `code`, paths, and line/column.

## Default vs `--json`

| Stream | Default | With `--json` |
|--------|---------|----------------|
| stderr | Errors, warnings, info (human-readable) | Same category of messages; formatting may stay human-oriented or be duplicated in JSON on stdout (implementation choice — prefer one JSON document on stdout for errors/warnings when `--json` is set). |
| stdout | Command-specific human output | **Structured JSON**, single document per invocation where possible. |

The precise split (e.g. whether stderr stays verbose when `--json` is on) is an implementation detail; the invariant is that **stdout JSON is sufficient for machines** to determine success, diagnostics, and structured results.

## Error and warning format

Diagnostics use the `@error` type structure — the same schema used by DSL-level `throw`. Example:

```json
{
  "errors": [
    {
      "code": "E001",
      "key": "unresolved-import",
      "message": "cannot find module 'validaton'",
      "help": "did you mean './validation'?",
      "origin": "syntax",
      "location": { "file": "ci.ops", "line": 3, "col": 6 }
    }
  ],
  "warnings": [
    {
      "code": "E008",
      "key": "unused-import",
      "message": "import 'std.log' is never used",
      "help": "remove the unused @use declaration",
      "origin": "resolve",
      "location": { "file": "ci.ops", "line": 4, "col": 1 }
    }
  ]
}
```

Fields:

- **`code`** — `e###` (user) or `E###` (engine). See [error-catalog.md](./error-catalog.md).
- **`key`** — kebab-case human-readable identifier.
- **`message`** — what went wrong.
- **`help`** — what to do about it.
- **`origin`** — auto-populated (`custom`, `syntax`, `resolve`, `emit`, `runtime`, etc.).
- **`location`** — `file`, `line`, `col` when applicable; omit or null for global errors.
- **`context`** — optional structured metadata (related locations, expected vs actual values).
- **`stack`** — optional structured error stack (present on rethrown errors).

## Build results

Example success payload:

```json
{
  "status": "ok",
  "files": [
    { "path": ".ops/ci/root.op.sh", "type": "root" },
    { "path": ".ops/ci/tag.op.sh", "type": "group" }
  ],
  "duration_ms": 142
}
```

- **`status`** — e.g. `ok` | `error` (align with exit codes).
- **`files`** — emitted artifacts with a **`type`** discriminator (`root`, `group`, etc.).
- **`duration_ms`** — optional timing for observability.

Failure under `--json` should still emit a parseable document (errors array and non-zero exit), not only stderr text.

## Help and drill

- **`help --json`:** structured descriptions of flags, subcommands, and global options — mirrors `--help` content but as JSON objects/arrays.
- **`drill --json`:** structured **groups**, **dependencies**, and **pipeline surface** (steps, ops, parameters as exposed by drill). Enables CI and codegen to introspect pipelines without running bash.

The JSON schema should **mirror** the human-readable `--help` and drill output semantically so documentation and tooling stay aligned.

## Exit codes

| Code | Meaning |
|------|---------|
| `0` | Success |
| `1` | Compilation error (syntax, type, secret rules, etc.) |
| `2` | Resolution error (imports, ops not found, environment) |
| Other | Reserved for implementation-defined categories (runtime failure, I/O, cancelled runs) — **TBD** before v1; document any new codes in this file when stabilized |

## Open points (pre-v1)

- Whether `--json` implies “quiet stderr” or “duplicate diagnostics on stdout only.”
- Version field on the root JSON object (`"version": 1`) for forward compatibility.
- Exact JSON schema for `drill` (nested graph vs flat file list).
