# Implementations

> How the records of common agent tools map onto OCP 0.3, what each can fill, and where an exporter hooks in.

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.

> **Note:** 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.

| Tool | Hook point | Tokens per attempt | Dollars |
|---|---|---|---|
| [Claude Code](#claude-code) | Hooks, transcripts, OpenTelemetry | Yes, with cache buckets | Yes (OTel) |
| [Codex CLI](#codex-cli) | Rollout files, OTel, `exec --json` | Yes | Priced by exporter |
| [OpenCode](#opencode) | Plugin, export, server | Yes | Yes |
| [Pi](#pi) | Extension, session files | Yes, with cache buckets | Yes |
| [OMP](#omp) | Hooks, session files | Yes | Yes |
| [bb](#bb) | Plugin, API, database | Yes, per thread | Priced by exporter |
| [Paseo](#paseo) | Daemon events, plugin | Live events only | Live events only |
| [Orca](#orca) | Database or CLI poller | Allocated only | Estimated |
| [Atrium](#atrium) | CLI poller | None public | None public |
| [LangGraph](#langgraph) | Checkpointer and callbacks | Yes | Priced by exporter |
| [CrewAI](#crewai) | Event listener | Yes | Priced by exporter |
| [OpenAI Agents SDK](#openai-agents-sdk) | Tracing processor | Yes | Priced by exporter |
| [OpenTelemetry GenAI](#opentelemetry-genai) | OTLP receiver | Yes | Not defined |

**What structure it exposes.** How a tool marks retries, how its work fits together, and how results are judged.

| Tool | Retries with a cause | Work graph | Verdicts |
|---|---|---|---|
| [Claude Code](#claude-code) | No | Spawn | Blocking hooks |
| [Codex CLI](#codex-cli) | No | Spawn | None native |
| [OpenCode](#opencode) | No | Spawn | None |
| [Pi](#pi) | With add-on packages | With add-on packages | With add-on packages |
| [OMP](#omp) | No | Spawn (inferred) | None |
| [bb](#bb) | No | Spawn, fork | Workflows plugin |
| [Paseo](#paseo) | No | Spawn | None |
| [Orca](#orca) | Yes | Dependencies, spawn | Yes |
| [Atrium](#atrium) | Runs per task | None | Task done |
| [LangGraph](#langgraph) | Rounds from routing | Declared graph | Router branches |
| [CrewAI](#crewai) | Guardrail retries | Declared task context | Guardrails |
| [OpenAI Agents SDK](#openai-agents-sdk) | No | Handoffs, agents as tools | Guardrail tripwires |
| [OpenTelemetry GenAI](#opentelemetry-genai) | No | Span parents | Evaluation events |

"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.

> **Warning:** **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

### Mapping

- **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.

### Sources, seen 2026-09-23

- [Hooks](https://code.claude.com/docs/en/hooks.md)
- [Monitoring usage](https://code.claude.com/docs/en/monitoring-usage.md)
- [Subagents](https://code.claude.com/docs/en/sub-agents.md)
- [Workflows](https://code.claude.com/docs/en/workflows.md)

### Codex CLI

### Mapping

- **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.

### Sources, seen 2026-09-23

- [protocol.rs](https://raw.githubusercontent.com/openai/codex/main/codex-rs/protocol/src/protocol.rs)
- [session_telemetry.rs](https://raw.githubusercontent.com/openai/codex/main/codex-rs/otel/src/events/session_telemetry.rs)
- [exec_events.rs](https://raw.githubusercontent.com/openai/codex/main/codex-rs/exec/src/exec_events.rs)
- [Hooks](https://learn.chatgpt.com/docs/hooks)
- [Advanced configuration](https://learn.chatgpt.com/docs/config-file/config-advanced)
- [config.md](https://raw.githubusercontent.com/openai/codex/main/docs/config.md)

### OpenCode

### Mapping

- **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`.

### Sources, seen 2026-09-23

- [session.ts](https://raw.githubusercontent.com/anomalyco/opencode/dev/packages/schema/src/v1/session.ts)
- [Agents](https://opencode.ai/docs/agents/)
- [CLI](https://opencode.ai/docs/cli/)
- [Plugins](https://opencode.ai/docs/plugins/)

### Pi

### Mapping

- **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.

### Sources, seen 2026-09-23

- [Session format](https://raw.githubusercontent.com/earendil-works/pi/main/packages/coding-agent/docs/session-format.md)
- [Message types](https://raw.githubusercontent.com/earendil-works/pi/main/packages/coding-agent/docs/message-types.md)
- [JSON mode](https://raw.githubusercontent.com/earendil-works/pi/main/packages/coding-agent/docs/json.md)
- [Extensions](https://raw.githubusercontent.com/earendil-works/pi/main/packages/coding-agent/docs/extensions.md)
- [@tintinweb/pi-subagents](https://www.npmjs.com/package/@tintinweb/pi-subagents)
- [@quintinshaw/pi-dynamic-workflows](https://www.npmjs.com/package/@quintinshaw/pi-dynamic-workflows)

### OMP

### Mapping

- **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`).

### Sources, seen 2026-09-23

- [Session](https://raw.githubusercontent.com/can1357/oh-my-pi/main/docs/session.md)
- [Task tool](https://raw.githubusercontent.com/can1357/oh-my-pi/main/docs/tools/task.md)
- [Hooks](https://raw.githubusercontent.com/can1357/oh-my-pi/main/docs/hooks.md)
- [Stats](https://raw.githubusercontent.com/can1357/oh-my-pi/main/packages/stats/README.md)

### bb

### Mapping

- **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`).

### Sources, seen 2026-09-23

- [schema.ts](https://raw.githubusercontent.com/get-bb/bb/main/packages/db/src/schema.ts)
- [thread-origin-kind.ts](https://raw.githubusercontent.com/get-bb/bb/main/packages/domain/src/thread-origin-kind.ts)
- [shared-types.ts](https://raw.githubusercontent.com/get-bb/bb/main/packages/domain/src/shared-types.ts)
- [Provider bridge protocol](https://raw.githubusercontent.com/get-bb/bb/main/docs/provider-bridge-protocol.md)
- [System overview](https://raw.githubusercontent.com/get-bb/bb/main/docs/system-overview.md)
- [Workflows plugin](https://raw.githubusercontent.com/get-bb/bb/main/.bb/skills/verify-bb/features/plugin-workflows.md)
- [Plugin SDK](https://raw.githubusercontent.com/get-bb/bb/main/packages/plugin-sdk/README.md)

### Paseo

### Mapping

- **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.

### Sources, seen 2026-09-23

- [Data model](https://raw.githubusercontent.com/getpaseo/paseo/main/docs/data-model.md)
- [Agent lifecycle](https://raw.githubusercontent.com/getpaseo/paseo/main/docs/agent-lifecycle.md)
- [agent-sdk-types.ts](https://raw.githubusercontent.com/getpaseo/paseo/main/packages/server/src/server/agent/agent-sdk-types.ts)
- [Architecture](https://raw.githubusercontent.com/getpaseo/paseo/main/docs/architecture.md)
- [Plugins](https://raw.githubusercontent.com/getpaseo/paseo/main/docs/plugins.md)

### Orca

### Mapping

- **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.

### Sources, seen 2026-09-23

- [Latest release](https://api.github.com/repos/stablyai/orca/releases/latest)
- [Orchestration types](https://raw.githubusercontent.com/stablyai/orca/main/src/main/runtime/orchestration/types.ts)
- [Core tables](https://raw.githubusercontent.com/stablyai/orca/main/src/main/runtime/orchestration/db/schema/create-core-tables-sql.ts)
- [Attempt observation types](https://raw.githubusercontent.com/stablyai/orca/main/src/main/runtime/orchestration/db/attempt-observation-types.ts)
- [Claude usage types](https://raw.githubusercontent.com/stablyai/orca/main/src/main/claude-usage/types.ts)
- [Codex usage types](https://raw.githubusercontent.com/stablyai/orca/main/src/main/codex-usage/types.ts)
- [Automation types](https://raw.githubusercontent.com/stablyai/orca/main/src/shared/automations-types.ts)
- [Automation run attribution](https://raw.githubusercontent.com/stablyai/orca/main/src/main/codex-usage/codex-automation-run-attribution.ts)
- [Plugin events](https://raw.githubusercontent.com/stablyai/orca/main/src/shared/plugins/plugin-events.ts)
- [CLI orchestration](https://raw.githubusercontent.com/stablyai/orca/main/docs/site/content/docs/cli/orchestration.mdx)
- [Usage tracking](https://raw.githubusercontent.com/stablyai/orca/main/docs/site/content/docs/agents/usage-tracking.mdx)
- [Automations](https://raw.githubusercontent.com/stablyai/orca/main/docs/site/content/docs/cli/automations.mdx)

### Atrium

### Mapping

- **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.

### Sources, seen 2026-09-23

- [getatrium.dev](https://getatrium.dev/)
- [Tasks](https://getatrium.dev/docs/concepts/tasks)
- [Agents](https://getatrium.dev/docs/concepts/agents)
- [CLI](https://getatrium.dev/cli)
- [Configuration](https://getatrium.dev/docs/reference/configuration)
- [Observatory](https://getatrium.dev/docs/panes/observatory)

### LangGraph

### Mapping

- **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.

### Sources, seen 2026-09-23

- [Checkpoint base](https://raw.githubusercontent.com/langchain-ai/langgraph/main/libs/checkpoint/langgraph/checkpoint/base/__init__.py)
- [types.py](https://raw.githubusercontent.com/langchain-ai/langgraph/main/libs/langgraph/langgraph/types.py)
- [Pregel main](https://raw.githubusercontent.com/langchain-ai/langgraph/main/libs/langgraph/langgraph/pregel/main.py)
- [LangChain AI message](https://raw.githubusercontent.com/langchain-ai/langchain/master/libs/core/langchain_core/messages/ai.py)
- [LangChain usage callback](https://raw.githubusercontent.com/langchain-ai/langchain/master/libs/core/langchain_core/callbacks/usage.py)
- [Trace with OpenTelemetry](https://docs.langchain.com/langsmith/trace-with-opentelemetry)
- [langgraph on PyPI](https://pypi.org/project/langgraph/)

### CrewAI

### Mapping

- **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.

### Sources, seen 2026-09-23

- [task.py](https://raw.githubusercontent.com/crewAIInc/crewAI/main/lib/crewai/src/crewai/task.py)
- [usage_metrics.py](https://raw.githubusercontent.com/crewAIInc/crewAI/main/lib/crewai/src/crewai/types/usage_metrics.py)
- [crew_output.py](https://raw.githubusercontent.com/crewAIInc/crewAI/main/lib/crewai/src/crewai/crews/crew_output.py)
- [task_output.py](https://raw.githubusercontent.com/crewAIInc/crewAI/main/lib/crewai/src/crewai/tasks/task_output.py)
- [base_events.py](https://raw.githubusercontent.com/crewAIInc/crewAI/main/lib/crewai/src/crewai/events/base_events.py)
- [llm_events.py](https://raw.githubusercontent.com/crewAIInc/crewAI/main/lib/crewai/src/crewai/events/types/llm_events.py)
- [llm_guardrail_events.py](https://raw.githubusercontent.com/crewAIInc/crewAI/main/lib/crewai/src/crewai/events/types/llm_guardrail_events.py)
- [task_events.py](https://raw.githubusercontent.com/crewAIInc/crewAI/main/lib/crewai/src/crewai/events/types/task_events.py)
- [llm.py](https://raw.githubusercontent.com/crewAIInc/crewAI/main/lib/crewai/src/crewai/llm.py)
- [Capture telemetry logs](https://docs.crewai.com/en/enterprise/guides/capture_telemetry_logs)
- [crewai on PyPI](https://pypi.org/project/crewai/)

### OpenAI Agents SDK

### Mapping

- **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.

### Sources, seen 2026-09-23

- [usage.py](https://raw.githubusercontent.com/openai/openai-agents-python/main/src/agents/usage.py)
- [span_data.py](https://raw.githubusercontent.com/openai/openai-agents-python/main/src/agents/tracing/span_data.py)
- [processor_interface.py](https://raw.githubusercontent.com/openai/openai-agents-python/main/src/agents/tracing/processor_interface.py)
- [tracing/__init__.py](https://raw.githubusercontent.com/openai/openai-agents-python/main/src/agents/tracing/__init__.py)
- [spans.py](https://raw.githubusercontent.com/openai/openai-agents-python/main/src/agents/tracing/spans.py)
- [lifecycle.py](https://raw.githubusercontent.com/openai/openai-agents-python/main/src/agents/lifecycle.py)
- [model_settings.py](https://raw.githubusercontent.com/openai/openai-agents-python/main/src/agents/model_settings.py)
- [guardrail.py](https://raw.githubusercontent.com/openai/openai-agents-python/main/src/agents/guardrail.py)

### OpenTelemetry GenAI

### Mapping

- **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.

### Sources, seen 2026-09-23

- [GenAI registry](https://raw.githubusercontent.com/open-telemetry/semantic-conventions-genai/main/model/gen-ai/registry.yaml)
- [GenAI events](https://raw.githubusercontent.com/open-telemetry/semantic-conventions-genai/main/model/gen-ai/events.yaml)
- [semantic-conventions-genai](https://github.com/open-telemetry/semantic-conventions-genai)
- [GenAI attribute registry](https://opentelemetry.io/docs/specs/semconv/registry/attributes/gen-ai/)

## 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](https://orchestrationcontextprotocol.io/community/contributing).
