# Document

> The top-level object, the producer block, identifiers, timestamps and vocabularies.

An OCP document is one JSON object that describes one orchestration run.

```json Smallest valid document
{
  "ocp": "0.3",
  "producer": { "name": "my-orchestrator" },
  "privacy": { "profile": "metadata_only" },
  "run": { "id": "run_01" },
  "nodes": []
}
```

## Top-level fields

- `ocp` (\"0.3\", required): Protocol version. This schema validates exactly version 0.3; v0.2 documents validate against ocp-v0.2.schema.json and v0.1 documents against ocp-v0.schema.json. A v0.3 reader accepts all three.

- `producer` ([Producer](https://orchestrationcontextprotocol.io/specification/0.3/schema#producer), required)

- `privacy` ([Privacy](https://orchestrationcontextprotocol.io/specification/0.3/schema#privacy), required)

- `run` ([Run](https://orchestrationcontextprotocol.io/specification/0.3/schema#run), required)

- `groups` ([Group](https://orchestrationcontextprotocol.io/specification/0.3/schema#group)[]): Optional named visual/organizational scopes, such as projects. Grouping is orthogonal to dependency structure.

- `nodes` ([Node](https://orchestrationcontextprotocol.io/specification/0.3/schema#node)[], required): The units of work. A gate is a node whose kind is `gate`.

- `edges` ([Edge](https://orchestrationcontextprotocol.io/specification/0.3/schema#edge)[]): Directed edges over node ids. `dep` and `fan_in` edges together must form a DAG; `spawn`, `launch` and `artifact` edges record discovered lineage and may form cycles.

- `attempts` ([Attempt](https://orchestrationcontextprotocol.io/specification/0.3/schema#attempt)[]): Flat list of tries, each pointing at its node. Attempts are records, not counters; a retry is a new attempt.

- `artifacts` ([Artifact](https://orchestrationcontextprotocol.io/specification/0.3/schema#artifact)[]): Files (or other addressable outputs) that one attempt produced and other attempts consumed. The handoff objects between attempts; the run records who wrote and who read them, never their content.

- `events` ([Event](https://orchestrationcontextprotocol.io/specification/0.3/schema#event)[]): Optional append-only provenance log, ascending in time.

- `ext` ([Ext](https://orchestrationcontextprotocol.io/specification/0.3/schema#ext))

## Requirements

- A document MUST be a JSON object ([E002](https://orchestrationcontextprotocol.io/specification/0.3/conformance#e002)) whose `ocp` field names a supported version ([E003](https://orchestrationcontextprotocol.io/specification/0.3/conformance#e003)), and it MUST validate against that version's schema ([E010](https://orchestrationcontextprotocol.io/specification/0.3/conformance#e010)).
- `nodes`, `edges`, `attempts`, `artifacts`, `events` and `groups` MUST be arrays when present ([E104](https://orchestrationcontextprotocol.io/specification/0.3/conformance#e104)).
- Ids MUST be unique within their array: node ids ([E100](https://orchestrationcontextprotocol.io/specification/0.3/conformance#e100)), attempt ids ([E101](https://orchestrationcontextprotocol.io/specification/0.3/conformance#e101)), group ids ([E102](https://orchestrationcontextprotocol.io/specification/0.3/conformance#e102)) and artifact ids ([E103](https://orchestrationcontextprotocol.io/specification/0.3/conformance#e103)). Ids are scoped to the producer and SHOULD stay stable when the same run is written again.
- Every timestamp MUST be an ISO 8601 / RFC 3339 date-time with an explicit offset. The schema checks the shape only, not that the date and time exist ([checker limits](https://orchestrationcontextprotocol.io/specification/0.3/conformance#checker-limits)).
- A consumer MUST ignore fields it does not know, at every level.
- Every entity MAY carry an `ext` object for producer-specific data; see [Extensions](https://orchestrationcontextprotocol.io/specification/0.3/extensions).

## Vocabularies

String vocabularies are open sets with a recommended list: a producer MAY write other values, a consumer MUST accept them, and a checker MAY warn ([W200](https://orchestrationcontextprotocol.io/specification/0.3/conformance#w200)). These are closed enums, and a value outside them is an error:

| Field | Values |
|---|---|
| Evidence tier of an inferred edge or label (`edge.tier`, `origin.tier`, `role.tier`, `phase.tier`, `modelRef.tier`, `artifact.kind.tier`) | `verified`, `heuristic`, `reported` |
| Tier of a signal or judgement (`signal.tier`, `preference.tier`, `task.labeled_by.tier`) | `verified`, `reported`, `heuristic`, `asserted` |
| `privacy.profile` | `metadata_only`, `full` |
| `attempt.status` | `queued`, `working`, `done`, `failed`, `rejected`, `canceled`, `settled_unverified`, `lost` |
| `outcome.result` | `done`, `failed`, `rejected`, `canceled`, `settled_unverified`, `lost` |
| `signal.kind` | `verdict`, `score`, `event` |
| `configuration.source` | `usual`, `alternative`, `exploration`, `user_edit`, `habit`, `designed` |
| `provenance.kind` | `logged`, `designed` |
| `signal.better`, `signal.scale` | `higher`, `lower`; `linear`, `log`, `fraction` |
| `acceptance_rule.score.better`, `acceptance_rule.score.scale` | `higher`, `lower`; `linear`, `log`, `fraction` |
| `rescue.basis` | `measured`, `expected` |

Free-text fields (titles, reasons, receipts, details, evidence notes) are short labels written by the producer, and the schema caps them at 500 characters. It does not cap other strings, such as `task.features` values, setting `options` and `ext` payloads. Under `metadata_only` a string MUST NOT contain prompt, completion or transcript text, whether capped or not; see [Privacy](https://orchestrationcontextprotocol.io/specification/0.3/privacy).

## Producer

The producer block names the software that wrote the document, so a consumer can group runs by where they came from and trace a bad field back to its source.

- `name` (string, required): The emitting software (plugin or converter), e.g. `my-orchestrator-ocp`. loopmath's log extractor names itself `loopmath` (`dagr` in documents written before its rename), optionally suffixed after a non-word character, e.g. `loopmath/graph`; that name switches on the extractor-only rule E171 (cost.basis `measured`).

  At most 200 characters.

- `version` (string): At most 100 characters.

- `framework` (string): The orchestration framework the run executed under, e.g. `my-orchestrator`, `claude-code`, `langgraph`, `crewai`.

  At most 200 characters.

- `framework_version` (string): At most 100 characters.

- `source_contract` (string): Upstream native format this document was derived from, e.g. `my-orchestrator/1.2`.

  At most 200 characters.

- `emitted_at` ([Timestamp](https://orchestrationcontextprotocol.io/specification/0.3/schema#timestamp))

- `capabilities` (object): Elements this producer can emit. A false value promises that the corresponding element is absent from this document. Unknown boolean keys are producer extensions.

  *properties*

  - `groups` (boolean)

  - `events` (boolean)

  - `artifacts` (boolean)

  - `edges_dep` (boolean)

  - `edges_spawn` (boolean)

  - `edges_launch` (boolean)

  - `edges_artifact` (boolean)

  - `cost_usd` (boolean)

  - `cost_tokens` (boolean)

  - `outcome_evidence` (boolean)

  - `task` (boolean)

  - `configuration` (boolean)

  - `signals` (boolean)

  - `slate` (boolean)

  - `receipt` (boolean)

- `ext` ([Ext](https://orchestrationcontextprotocol.io/specification/0.3/schema#ext))

- `capabilities` says which elements the producer can write. A `false` value promises the element is absent from this document ([E180](https://orchestrationcontextprotocol.io/specification/0.3/conformance#e180)); a missing key means unknown.
- A producer SHOULD declare `capabilities` ([W180](https://orchestrationcontextprotocol.io/specification/0.3/conformance#w180)). Without it, a consumer cannot tell "this tool does not record edges" from "this run had no edges".
- A converter SHOULD set `source_contract` to the native format it read, so consumers can tell converted documents from native ones.
