← Back to blog

opentine v0.5.0: provenance across the agent ecosystem

0xcircuitbreaker··7 min read

opentine 0.5.0 is the ecosystem release: provenance can now enter from framework callbacks or existing traces, remain durable as an opentine artifact or repository run, and leave again as OpenTelemetry GenAI data.

The release is additive. Portable *.tine artifacts remain format v2, repository objects remain format v3, and upgrading the package requires no data migration.

Import a trace from the shell

The Python importers introduced with the repository layer now have a CLI front end. tine import accepts a file or - for standard input and writes a portable artifact, advances a ref in an existing repository, or does both in one operation.

tine import trace.otlp.json --format otel-json --save imported.tine
tine import spans.jsonl --format otel-spans --repo . --ref heads/imported
tine import agent.log --format langchain --save run.tine

The supported formats are otel-json, otel-spans, jsonl, langchain, llamaindex, autogen, crewai, and openai-agents. At least one of --save or --repo is required. A repository import opens an existing v3 repository, and its ref defaults to heads/main.

Imported traces become ordinary opentine runs. --save writes a portable v2 file; --repo records the same event graph in the v3 object store. Import does not introduce a third format or rewrite the source trace in place.

Record LangChain and LangGraph live

Post-hoc import is limited by whatever a framework chose to serialize. Version 0.5 adds an optional callback handler for recording LangChain and LangGraph while an invocation is running.

python -m pip install "opentine[langchain]==0.5.0"
from opentine import Repo
from opentine.integrations.langchain import OpenTineCallbackHandler

handler = OpenTineCallbackHandler(Repo.init("runs"))
graph.invoke({"question": "..."}, config={"callbacks": [handler]})
run_id = handler.run_id

LangGraph drives the same langchain-core callback protocol, so the handler can record chains, graph nodes, chat models, tools, retrievers, usage, parent relationships, and errors through one TraceEvent and Recorder path. One invocation becomes one finalized v3 run.

CrewAI is deliberately different in this release. It has no live callback adapter in 0.5; its serialized logs remain a post-hoc import path. The site and API should not imply otherwise.

Export verified history as OpenTelemetry GenAI

Interop now works in the other direction too. to_otel_genai renders a portable Run, a repository run, or TraceEvent records as GenAI spans. to_otel_genai_document wraps those spans in a complete OTLP/JSON document.

from opentine import Repo, to_otel_genai_document

repo = Repo.open(".")
run = repo.load_run("heads/main")
document = to_otel_genai_document(run, service_name="research-agent")

The exporter returns Python data. It does not send anything to a collector by itself, which keeps transport and credentials under the application's control.

Import and export share one set of gen_ai.* keys, so the structures they understand do not drift independently. The round trip preserves the fields consumed by the importer, but it is not a claim of byte-perfect losslessness: cost and billing use custom opentine.* attributes, null attributes are omitted, and timestamp precision has documented limits.

JSON output for shell and CI workflows

Five read commands can now replace their rich rendering with one documented JSON object:

tine show run.tine --json
tine verify run.tine --json
tine ls --json
tine search "tag:prod status:failed" --json
tine cost run.tine --json

The human output remains the default. Within the current major version, fields can be added but are not renamed or removed.

Exit status still matters. A failed verification or recorded budget breach emits its result object and exits with status 1. An error that prevents a result—such as a malformed filter or unreadable key file—remains a human-readable error with a nonzero exit.

Read the telemetry real systems emit

The OpenTelemetry importer now understands more than the classic gen_ai.prompt and gen_ai.completion attributes. It also reads message span events and log records, gen_ai.choice, structured input and output message attributes, the JSON-string form used by real SDKs, and common flattened OpenLLMetry and OpenInference shapes.

The classic prompt and completion path remains supported and takes precedence when both forms are present.

The wheel also ships py.typed, making the public annotations visible to PEP 561-aware type checkers. This changes package ergonomics, not stored data.

Upgrade without migrating artifacts

python -m pip install --upgrade "opentine==0.5.0"
python -c "import opentine; print(opentine.__version__)"
tine verify existing.tine
tine fsck --repo .

The compatibility gate now loads, reads, and verifies golden portable artifacts and a repository produced by the published 0.3.0 and 0.4.0 releases. Those two prior release lines stay readable under 0.5.

The new LangChain dependency is optional. opentine[all] does not include the LangChain or MCP extras, so install them explicitly when an environment needs every surface:

python -m pip install "opentine[all,mcp,langchain]==0.5.0"

Version 0.5 does not add model providers or price cards. Its work is at the boundary between runtimes, durable provenance, automation, and telemetry.

Install opentine 0.5.0 from PyPI, read the official v0.5.0 changelog, and inspect the tagged source for the complete release.