← Back to blog

opentine v0.22.0: rewind what the run actually recorded

0xcircuitbreaker··5 min read

A run artifact becomes more useful when it can help you intervene. v0.22.0 adds tine rewind: preview how recorded file changes can be restored to a chosen point, then explicitly apply the recoverable plan.

The important word is recorded. Rewind is not a filesystem snapshot, and it does not invent missing history.

Start with a plan

python -m pip install --upgrade "opentine==0.22.0"

# No writes: target the state before the run
tine rewind run.tine --json

# No writes: target the state just after step index 3
tine rewind run.tine@3 --root . --json

A step can be an index or a step ID. With no step, rewind targets the state before the run. With a step, it targets the state immediately afterward.

The JSON report separates restore, unchanged, conflict, unrecoverable, and refused lists. Those distinctions matter: a valid artifact is not necessarily a complete record of every file's previous content.

Restore known history—not a guess

Whole-content Write actions can be replayed forward. Edit, MultiEdit, and str_replace operations are applied or undone only when the inserted text occurs exactly once. Shell or patch changes, redacted history, and whole-file creation without prior-state evidence can be unrecoverable. The plan reports why.

After reviewing the plan and backing up local work, --apply opts into writes:

tine rewind run.tine@3 --root . --apply --json

Writes are atomic per file and confined beneath the selected root. Outside-root paths and symbolic-link paths are refused. A conflicting current state prevents writes and exits 1 unless --force overrides the conflict check. Force can overwrite later edits; it cannot reconstruct missing evidence. Do not mistake per-file atomic writes for a filesystem-wide rollback transaction.

Receive live telemetry too

This release includes v0.21's live OTLP receiver:

tine serve --otlp --otlp-port 4318 --otlp-idle 30

It accepts OTLP/HTTP JSON traces and logs, including gzip, and groups spans by trace ID and logs by session. A trace becomes a saved run when its root span arrives, after the idle interval, or when Ctrl-C flushes pending groups. It uses the existing import path: values are redacted and source billing is distrusted.

The receiver is unauthenticated and defaults to localhost. It is not an authenticated public collector. Body limits apply before and after decompression; protobuf is refused with a hint to select http/json.

Preserve the boundaries

Rewind restores recoverable working-tree content. Forking branches run history. Replay reuses or reruns execution according to its mode. Live telemetry brings in external evidence. These operations complement one another without providing the same guarantees.

Python support remains 3.11–3.14, portable files remain .tine v2, and repositories remain v3. Read the rewind guide, live receiver guide, and upgrade guide. The official GitHub release, PyPI package, and tagged changelog provide the release record.