Skip to main content

Local-first provenance for agent runs: content-addressed traces, fork, replay, and scoped resume.

Project description

opentine

opentine

Git for agent runs: record, verify, fork, replay, and diff execution history.
Portable .tine artifacts for native agents and external CLI harnesses.

PyPI License Python CI 0.1.x beta

Animated opentine terminal demo showing run capture and graph inspection


A tine is the prong of a fork. opentine forks agent runs.

Every run becomes a content-addressed graph of model calls, tool calls, outputs, errors, cache provenance, and transcript state. Save it as a .tine file, verify its checksum, fork from a known-good step, replay recorded work, rerun through an explicit harness, and diff the branch that worked against the branch that failed.

What You Can Do

# Inspect a saved execution tree.
tine show result.tine

# Check that the artifact body still matches its recorded checksum.
tine verify result.tine

# Branch from a step before a bad tool call.
tine fork failed.tine --from-step 3 --save retry.tine

# Reuse recorded steps without re-spending model/tool work.
tine replay result.tine --mode cache --save replayed.tine

# Compare the graph shape of two runs.
tine diff failed.tine retry.tine

The current 0.1.x public beta validates the core surface, Ollama, Codex CLI, and Kimi Code CLI through the gates listed in Release Validation. Other providers and harnesses are compatibility targets until their own live gates pass.

Install

pip install opentine

Core runtime dependencies install normally. Provider SDKs are optional extras, and OpenAI-compatible providers share the OpenAI SDK path.

pip install "opentine[anthropic]"
pip install "opentine[openai]"
pip install "opentine[google]"
pip install "opentine[compat]"

Quickstart

Write a native opentine agent:

from opentine import Agent
from opentine.models.anthropic import Anthropic

agent = Agent(model=Anthropic("claude-sonnet-4-20250514"))
run = agent.run_sync("What is opentine?")
run.save("result.tine")

Then inspect and branch the run:

tine show result.tine
tine verify result.tine
tine fork result.tine --from-step 0 --save forked.tine
tine replay result.tine --inspect
tine diff result.tine forked.tine

Example tree shape:

# fe3a767307a4  model=claude-sonnet-4-20250514  steps=3  cost=$0.0006  completed
|-- # 9e4b8c2a19dd think  "Planning the answer..."
|-- > 81bf0f67bb12 tool   search(query="opentine")
`-- + 6d4a0b270a5f done   "opentine records agent runs as portable artifacts..."

The Debugging Loop

Your agent fails after ten steps. Instead of rerunning everything:

tine show failed_run.tine
tine fork failed_run.tine --from-step 3 --save fixed_run.tine
tine diff failed_run.tine fixed_run.tine

That gives you the first three steps as known provenance, a new branch for the repair attempt, and a graph diff that shows what changed.

How It Works

Every .tine file stores a content-addressed DAG. Step IDs are full SHA-256 hashes over canonical immutable step payloads: parent links, kind, inputs, outputs, model/tool metadata, and errors.

Animated opentine run tree showing a root run, model and tool steps, a fork branch, retry path, and verified outcome

Core operations are graph operations:

Operation Meaning
Save/load Serialize the run graph, transcript, cache, manifest, policy metadata, and checksum.
Verify Recompute the SHA-256 checksum in metadata.integrity.
Fork Copy ancestors up to a chosen step and continue from there.
Replay Reuse recorded steps, or rerun through an explicit native runtime or harness.
Diff Compare two run graphs and show the common ancestor plus divergent steps.

Run.steps remains a stable traversal view, but the artifact stores a graph with parent_ids, named refs, and branch metadata.

Harnesses

opentine can wrap external CLI agents and record observable events as a .tine run:

tine run --harness codex --prompt "Inspect this repo"
tine run --harness kimi-code --prompt "Summarize README.md"
tine run --harness generic --harness-command "your-agent run" --prompt "Fix tests"
graph LR
    Task["user task"] --> Wrapper["opentine harness wrapper"]
    Wrapper --> Codex["Codex CLI"]
    Wrapper --> Kimi["Kimi Code"]
    Wrapper --> Generic["custom command"]
    Codex --> Artifact["portable .tine"]
    Kimi --> Artifact
    Generic --> Artifact
    Artifact --> Fork["fork"]
    Artifact --> Replay["replay"]
    Artifact --> Diff["diff"]

Python wrapper API:

from opentine.harnesses import CodexCLIHarness, OpentineHarness

harness = CodexCLIHarness()
wrapped = OpentineHarness(harness, autosave_path="latest.tine", autosave_steps=5)

run = wrapped.run_sync("Refactor auth middleware")
run.save("codex_run.tine")

forked = wrapped.fork(from_step=3)
forked.save("retry_from_step_3.tine")

Harness subprocesses are isolated by default. For logged-in CLIs, pass --harness-login-env to allow only PATH, home/config directory variables, and tool-specific config directory variables. opentine does not write pasted secrets to repo files.

Support Matrix

Status values are intentionally conservative:

Target Status Evidence
Native .tine v1 load/save/fork/diff/replay Validated Fast tests, golden fixture, and CLI smoke.
Artifact checksum verification Validated Run.verify_integrity(...), tine verify, and failure-path tests.
Secure tool defaults Validated Filesystem, symlink, network, shell, Python, env, redaction, and output-cap tests.
Ollama llama3.1 and qwen3 Validated Live gate passed for the current 0.1.x beta.
Codex CLI Validated Live harness gate passed for the current 0.1.x beta.
Kimi Code CLI Validated Live harness gate passed for the current 0.1.x beta.
Anthropic, OpenAI, Google Scoped Adapter contract tests; cloud live gates require user credentials.
Kimi API, DeepSeek, GLM, Groq, Together, Mistral, Qwen API Scoped OpenAI-compatible adapter shape; provider-specific live gates required.
LM Studio, vLLM, llama.cpp, LocalAI, Jan, Unsloth-compatible endpoints Scoped Endpoint-specific local live gates required.

Native Models

The native Agent API accepts any implementation of the Model protocol. Built-in adapters include:

from opentine.models.anthropic import Anthropic
from opentine.models.google import Google
from opentine.models.ollama import Ollama
from opentine.models.openai import OpenAI

agent = Agent(model=Anthropic("claude-sonnet-4-20250514"))
agent = Agent(model=OpenAI("gpt-4o"))
agent = Agent(model=Google("gemini-2.0-flash"))
agent = Agent(model=Ollama("llama3.1"))

Not every local model can call tools. Ollama models such as gemma, codellama, phi4, and deepseek-r1 advertise no tools capability; opentine detects this (Ollama(...).supports_tools), runs them without tools instead of crashing, and records a note in run.metadata["warnings"]. For tool-using agents pick a tools-capable model like llama3.1, qwen2.5, qwen3, or mistral.

OpenAI-compatible wrappers:

from opentine.models.compat import DeepSeek, GLM, Groq, Kimi, Mistral, Qwen, Together

agent = Agent(model=Kimi("moonshot-v1-8k"))
agent = Agent(model=DeepSeek("deepseek-chat"))
agent = Agent(model=Qwen("qwen-plus"))
agent = Agent(model=GLM("glm-4-flash"))
agent = Agent(model=Groq("llama-3.1-70b-versatile"))
agent = Agent(model=Together("meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo"))
agent = Agent(model=Mistral("mistral-large-latest"))

These wrappers make integration easy, but a provider is only counted as live-validated after its project validation gate passes.

Tools And Policies

Tools are plain Python callables with type hints:

from opentine.tools import fs, python, search, shell, web

agent = Agent(
    model=Ollama("llama3.1"),
    tools=[web.fetch, search.search, fs.read],
)

Defaults are restrictive:

  • Filesystem access is rooted, size-capped, and denies symlinks by default.
  • Network fetch blocks private, link-local, loopback, reserved, and multicast hosts by default.
  • Shell execution is disabled unless a ShellPolicy enables it.
  • Python execution is disabled unless a PythonPolicy enables it.
  • Harness subprocesses do not inherit the parent environment by default.
  • Saved artifacts redact common secret-bearing keys before writing.

See SECURITY_MODEL.md for the detailed model.

.tine Format

Top-level fields:

format_version, run_id, created_at, status, graph, refs, transcript, manifest, policies, cache, metadata.

Current compatibility promise: format_version == 1 only. Run.load() rejects missing, old, or future format versions instead of guessing. Migration support is future work.

Saved artifacts include:

{
  "metadata": {
    "integrity": {
      "algorithm": "sha256",
      "digest": "..."
    }
  }
}

This is an integrity checksum, not tamper-proof signing. A user who can edit the file can also rewrite the digest. HMAC/signature support is future work. See TINE_FORMAT.md.

CLI Reference

tine run <script.py>              Execute a Python script that produces a Run
tine run --harness codex          Execute an external harness and save the graph
tine ls                           List recent runs
tine show <run.tine>              Pretty-print the graph
tine verify <run.tine>            Verify the artifact checksum
tine replay <run.tine> --inspect  Print recorded events without replaying
tine replay <run.tine> --mode cache --save replayed.tine
tine fork <run.tine> --from-step 3 --save retry.tine
tine diff <run_a.tine> <run_b.tine>
tine resume <run.tine>            Resume only when the manifest declares support

MCP Server

opentine.mcp_server exposes saved runs to MCP clients:

  • list_runs: show recent .tine files
  • show_run: render a run as LLM-readable context
  • fork_run: fork a run from a step index
  • diff_runs: compare two runs
  • run://{run_id}: resource URI for a saved run

Run it with an MCP-compatible environment:

python -m opentine.mcp_server

The MCP dependency is optional; install the mcp package only for this server.

Release Validation

Opentine is a public 0.1.x open-source beta. Package metadata remains Development Status :: 4 - Beta.

Current local gates:

ruff check .
ruff format --check .
pytest tests -m "not live and not live_harness" -q
pytest tests -m "not live_harness" -q
python -m build --sdist --wheel --outdir dist
python -m twine check dist/*
python scripts/wheel_smoke.py

Current live gates:

pytest tests/test_live.py --provider ollama -q
pytest tests/test_live_harness.py -m live_harness --agent-harness codex -q
pytest tests/test_live_harness.py -m live_harness --agent-harness kimi-code -q

GitHub Actions runs the local gates on every push and pull request across Ubuntu, macOS, and Windows for Python 3.11–3.13, and uploads the built wheel/sdist as a downloadable opentine-dist artifact. Tagged v* releases additionally publish SHA256SUMS and a build-provenance attestation you can verify against the source workflow:

gh attestation verify opentine-0.1.1-py3-none-any.whl --repo 0xcircuitbreaker/opentine

Related docs:

Document What it covers
CHANGELOG.md Verified user-visible changes.
SUPPORT.md Supported Python versions and support levels.
TROUBLESHOOTING.md Common validation, harness, and policy failures.

Comparison

Git stores content-addressed source history. opentine stores content-addressed agent execution provenance.

LangGraph is the closest technical comparison for checkpoint replay and time travel, but it is framework/checkpointer-oriented rather than a standalone .tine artifact. LangSmith and CrewAI tracing are stronger observability/evaluation surfaces; opentine is a local provenance artifact and graph-operation layer.

The Name

A tine is a prong of a fork. The .tine extension stores serialized run graphs, and tine is the CLI command.

Contributing

git clone https://github.com/0xcircuitbreaker/opentine.git
cd opentine
uv sync --all-extras
uv run pytest tests -m "not live and not live_harness"
uv run ruff check .
uv run ruff format --check .

When Docker is available, python scripts/ci_docker.py rehearses the Ubuntu GitHub Actions matrix locally for Python 3.11, 3.12, and 3.13. GitHub Actions remains authoritative for macOS and Windows.

License

Apache-2.0. See LICENSE.

Built by the opentine contributors.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

opentine-0.1.1.tar.gz (334.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

opentine-0.1.1-py3-none-any.whl (54.4 kB view details)

Uploaded Python 3

File details

Details for the file opentine-0.1.1.tar.gz.

File metadata

  • Download URL: opentine-0.1.1.tar.gz
  • Upload date:
  • Size: 334.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for opentine-0.1.1.tar.gz
Algorithm Hash digest
SHA256 b57f3d2cbe34581e73877f2431303c7fbfcd0dcf13b16ba984975496644432db
MD5 e99ad40dec7e588efeafc864beb8897c
BLAKE2b-256 697da932b22b4c0c809b9894862f3500d2376f42ddf02433e293e9e203fdd107

See more details on using hashes here.

File details

Details for the file opentine-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: opentine-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 54.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for opentine-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 bb0a1f14ffbd02489f42d5478a82dea0a11a78562362b6133361e74ea6d26656
MD5 e76ab2cf9ca6133f0aee812f2d41cd1f
BLAKE2b-256 205fafc9e8a83b823e839b732c5d6cad78e9c8158036640db93be63450f2da63

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page