A producer turns what your tool knows about a run into one OCP document. There are three places to do that: Implementations lists where each common agent tool can be hooked, and what it can fill.

Map your records

1

Decide what a node and an attempt are

A node is a unit of work: a task, a subagent role, a step in a graph. An attempt is one try at a node: a session, a subagent run, one pass of a step. A retry is a new attempt at the same node, never an edit of the old one, and its cause says why it happened.
2

Choose stable ids

Ids are scoped to your producer. Derive them from your tool’s own ids, so writing the same run twice gives the same ids. A common pattern is <node>.a<n> for attempts.
3

Record the model and effort as your tool knows them

Always write model.raw, the label exactly as your tool had it. Add model.id only when you know the provider’s canonical id. Reasoning effort goes in effort, never in the model name.
4

Record cost per attempt, per stream

Write each token stream separately. OCP’s input_tokens is uncached input: if your source counts cache reads inside input, as Codex, the OpenTelemetry GenAI conventions, LangChain and the OpenAI Agents SDK do, subtract them. Set basis to measured only when the counts come from usage records of that attempt; if you split a session or daily total across attempts, write allocated. Dollars are optional; if you write usd, write the tariff you priced it with.
5

Record outcomes with their evidence

When an attempt ends, write its status and an outcome whose result matches it. Say how the result is known with evidence: a check that ran is verified, a reviewer’s verdict reported. via names the node that judged, and receipt holds a short label. See Evidence.
6

Add edges with their tier

If your tool knows the order or lineage of work, add edges: dep for “must finish first”, spawn when one attempt started another, artifact when one read what another wrote. Every edge carries a tier.
7

Declare capabilities

producer.capabilities says which elements you can write. A false promises the element is absent, so a reader can tell “not recorded” from “did not happen”.

A minimal producer

Standard library only. It writes a two-node run with a review, and passes loopmath ocp validate with no findings.
emit.py

Checklist

  • privacy.profile is set, and under metadata_only no field holds prompt, completion or transcript text.
  • Every free-text field is a short label. The schema caps label fields at 500 characters; strings it does not cap, such as task.features values, setting options and ext payloads, hold no transcript text either.
  • Timestamps carry an explicit offset.
  • Your own data sits in ext under a namespace you control, such as com.example.. See Extensions.
  • Documents validate in CI. See Validate.

Going further: the observation

The 0.3 observation fields make a run comparable with other runs: the task, the configuration that ran with its content-derived id, the signals the result was judged on, and the acceptance rule. They are optional. Fill run.task and run.signals when your tool knows the task and runs checks; fill run.configuration when your tool has a declared workflow, and compute its id with the canonical algorithm.

Privacy