OCP is meant to be written by any tool that runs agents. This page maps thirteen tools and frameworks onto OCP 0.3: what each records, where an exporter can hook in, and what it can and cannot fill.
For each tool below we wrote an illustrative OCP 0.3 document from its public source or docs, with invented values, and checked it with loopmath ocp validate: all thirteen conform, with no errors and no warnings. These are mappings, not shipped exporters; where loopmath already reads a tool, its section says so. Sources were read on 2026-09-23 and are listed with each tool; tools change, so check them against the current version.

Reference implementation

loopmath writes, reads, validates and migrates OCP. It reads Claude Code and Codex logs directly and writes 0.3 (loopmath graph --format ocp). Eight adapters (loopmath adapt) read Pi, OpenCode, OMP, bb, Paseo, Orca, Atrium and OpenTelemetry GenAI data and write 0.2, which loopmath run import upgrades to 0.3. The Paseo and Orca adapters carry no tokens, and the Atrium adapter reads events only. It has no adapter yet for LangGraph, CrewAI or the OpenAI Agents SDK.

At a glance

Hooks and cost. Where to read a tool from, and what it records per attempt. What structure it exposes. How a tool marks retries, how its work fits together, and how results are judged. “Priced by exporter” means the tool records tokens but no dollars; an exporter prices them and records the price table in cost.tariff.

Where 0.3 loses information

Every mapping validates, but some records have no exact place in 0.3 yet:
  • Several models in one attempt. OpenCode, OMP, Codex and Claude Code sessions can switch models midway. OCP has one model per attempt, so an exporter splits the attempt or keeps the per-model split in ext.
  • Relations without a core edge kind. Handoffs (Agents SDK), forks (bb, Pi, Codex) and cross-agent messages (bb, Atrium, Orca) are written as dep or spawn edges, or in ext.
  • Control flow beyond gate and repair. A 0.3 workflow is acyclic, and control.repair sends one gate’s rejection back to one piece. LangGraph graphs with several loops, and imperative workflow scripts, are approximated.
  • API retries. Retries of a single model request are not attempts. They belong in cost.requests or ext. Retries a framework makes on purpose (CrewAI guardrails, Orca dispatch retries, Pi workflow retry()) are attempts with a cause.
  • Free-text verdicts. Verdict values are a closed set. Orca decision-gate resolutions and OpenTelemetry evaluation labels are free text, so an exporter maps them or records a score or event instead.
Cached input. OCP’s input_tokens is uncached input. Codex, the OpenTelemetry GenAI conventions, LangChain and LangGraph, and the OpenAI Agents SDK count cache reads inside input. Their exporters subtract.Reasoning. OCP’s output_tokens includes reasoning, and reasoning_tokens is a breakdown of it. Where a tool reports reasoning apart from output, its exporter adds it in.

By tool

Two things come from outside every tool below. run.task and run.acceptance_rule come from the exporter’s configuration or the orchestrator, since no tool records a user’s acceptance rule. And run.provenance says how the configuration was chosen, which the logs alone do not show: keep what the orchestrator knows. A run whose configuration the user’s habit chose is {kind: logged, chooser: habit}; one chosen for it by a recommender, the user or a planner is designed, even when it is exported from logs afterwards. When the choice is not known, leave provenance out.

Claude Code

  • Hook in: a hook script (SubagentStart and SubagentStop, Stop, SessionEnd, PostToolUse) for identity, effort, gates and file paths, plus either the per-agent transcripts or an OTLP receiver for tokens.
  • Fills: one attempt per session and per subagent; model (verified) and effort (reported, from hooks and OTel); the full token split per agent from transcripts, including 5-minute and 1-hour cache buckets (measured); dollars from OTel cost_usd; spawn edges from subagent records or OTel parent ids (verified); launch edges across claude -p sessions through the OTel trace parent; artifact edges from Write, Edit and Read paths; a verdict when a blocking hook ran a check.
  • Gaps: nothing links a retried agent to the earlier one, so there is no attempt cause. The OTel route loses the cache buckets. A workflow script is imperative, so the configuration is inferred (heuristic).
  • loopmath 0.1: reads transcripts natively and writes 0.3 with measured cost, spawn and artifact edges; its otel-genai adapter reads Claude Code traces.

Codex CLI

  • Hook in: a poller over rollout files (the richest source), an OTLP receiver, or the codex exec --json stream for runs the orchestrator starts.
  • Fills: one attempt per thread; model and effort per turn (reported); input, cached input, cache writes, output and reasoning tokens (measured; uncached input is input_tokens minus cached_input_tokens); spawn edges from the parent thread id (verified); files written.
  • Gaps: no gate or verdict object; files read are not recorded; no dollars outside an OTel estimate, so an exporter prices tokens with a tariff.
  • loopmath 0.1: reads rollouts natively and writes 0.3 with spawn lineage and launch origins.

OpenCode

  • Hook in: a plugin on session, message and file events, or a poller over opencode export, the opencode serve HTTP server, or opencode run --format json.
  • Fills: one attempt per session; model (verified) and its variant as effort (reported); input, cache reads and writes, output and reasoning tokens (measured); dollars as the harness computed them; spawn edges from child sessions’ parent id; files written.
  • Gaps: no acceptance signal; no cache retention buckets; one session can mix models.
  • loopmath 0.1: adapter (opencode), which keeps the per-model split in ext.

Pi

  • Hook in: a Pi extension on session, agent, turn and tool events, or the session JSONL files after the fact.
  • Fills: model per message (verified), thinking level as effort (reported), input, cache reads and writes (including a 1-hour bucket), reasoning and output tokens, and dollars per message.
  • Gaps: core Pi has no subagents, gates or dependencies; add-on packages supply them, and their run files were not examined. A fork has no core edge kind.
  • loopmath 0.1: adapter (pi): one attempt per session, measured tokens and dollars, no edges.

OMP

  • Hook in: a hook or extension on session, agent, turn, tool and retry events, or a poller over session files.
  • Fills: model and thinking level per session; input, cache reads and writes, and output tokens; dollars; subagent child sessions with per-spawn effort.
  • Gaps: ordinary task children have no durable parent key, so spawn edges are heuristic (verified for the vibe runtime); no verdicts; auto_retry events are API retries, not attempts.
  • loopmath 0.1: adapter (omp).

bb

  • Hook in: a bb backend plugin, the HTTP and WebSocket API, or read-only access to its database for backfill.
  • Fills: one attempt per thread; model and reasoning level overrides (reported); input, cached input, output and reasoning tokens per thread; spawn and fork lineage (verified).
  • Gaps: no dollars; queued messages between threads have no core edge kind; no native run boundary (by convention, a root thread is a run). Input includes cache reads for Codex threads.
  • loopmath 0.1: adapter (bb), with launch edges to joined vendor sessions (heuristic).

Paseo

  • Hook in: a daemon WebSocket client or a server plugin. A poller over the agent files works for backfill but gets no tokens.
  • Fills: one attempt per agent with its provider, model and thinking option (reported); spawn edges from the parent-agent label; tokens and dollars only from live usage events.
  • Gaps: no persisted usage; no verdicts, dependencies or artifacts; the parent label can be edited later.
  • loopmath 0.1: adapter (paseo), without tokens.

Orca

  • Hook in: a poller over its orchestration database or the CLI’s --json commands. The plugin API exposes only worktree and status events.
  • Fills: tasks with declared dependencies (dep edges, verified); one attempt per dispatch, with a typed retry pointer for cause; model and effort from the worker launch (reported); decision gates, worker outcomes and merge-ready messages as verdicts (reported); files modified.
  • Gaps: usage is kept per session and worktree, never per dispatch, so per-attempt cost is always allocated; decision-gate options are free text.
  • loopmath 0.1: adapter (orca), without tokens; it does not yet read dependencies or retry pointers.

Atrium

  • Hook in: a poller over the CLI’s --json output. Its database schema is documented as internal.
  • Fills: tasks as nodes and runs as attempts (reported); a task moved to done as a verdict (reported).
  • Gaps: no public record of tokens, cost, model or effort; cost has to come from the wrapped harness’s own logs. Only the public docs were read; there is no public source.
  • loopmath 0.1: adapter (atrium), which reads its timeline into events only.

LangGraph

  • Hook in: a checkpointer wrapper (steps, forks, interrupts, routing) plus a callback handler for per-call usage and model, or OTLP export.
  • Fills: the compiled graph as a declared workflow (verified) and dep edges; one attempt per node step, with repair rounds from routing; model (verified) and effort (reported); input, cache reads and writes, output and reasoning tokens (measured, after subtracting cached input); router decisions as reported verdicts.
  • Gaps: individual retries under a retry policy are not persisted; graphs with several loops or non-gate routers can only be approximated as a 0.3 workflow; no dollars.
  • loopmath 0.1: no adapter.

CrewAI

  • Hook in: a listener on CrewAI’s event bus.
  • Fills: tasks and their declared context as dep edges (verified); one attempt per task try, with guardrail retries as attempts caused by a failed gate; guardrail results as verified verdicts; model and reasoning effort (reported); per-call usage from LLM call events; output files as artifacts.
  • Gaps: usage keys depend on the provider, so the split needs normalizing; no dollars; human-input feedback is a directive, not a verdict.
  • loopmath 0.1: no adapter.

OpenAI Agents SDK

  • Hook in: a tracing processor registered with add_trace_processor, or run and agent hooks.
  • Fills: one run per trace and one attempt per agent span; model (verified) and reasoning effort from model settings (reported); input, cached input, cache writes, output and reasoning tokens per request (measured, after subtracting cached input); handoffs and agents used as tools as edges; guardrail tripwires as verdicts.
  • Gaps: no files and no dollars; a handoff has no core edge kind; a tripwire ends the run rather than repairing it.
  • loopmath 0.1: no adapter.

OpenTelemetry GenAI

  • Hook in: an OTLP receiver, or a Collector file exporter read afterwards.
  • Fills: one attempt per agent invocation; model and the reasoning level sent to the provider; input, cache reads and writes, output and reasoning tokens (after subtracting cached input); spawn and launch edges from span parents; evaluation results as verdicts (reported).
  • Gaps: the conventions define no cost, attempts, retry causes, declared dependencies or gates, and every attribute is still in development, so an exporter should pin the version it follows.
  • loopmath 0.1: adapter (otel-genai), used for Claude Code and Codex traces.

Add your tool

If you maintain an agent tool or have written an exporter, add it here. Open an issue or a pull request with the tool, where the exporter hooks in, and an example document that passes loopmath ocp validate. See Contributing.

Privacy