← Back to blog

Migrating .tine artifacts from v1 to v2

0xcircuitbreaker··6 min read

Format migrations are trust exercises. The important question is not only whether the new reader understands the old file. It is whether you can predict exactly when bytes change and which clients can read the result.

opentine 0.2 makes that boundary explicit.

The compatibility rule

The rule is asymmetric:

  • opentine 0.2 reads v1 and v2 artifacts.
  • Loading v1 migrates it in memory and does not rewrite the source.
  • Saving that loaded run writes v2.
  • opentine 0.1.x cannot read a v2 artifact.

That last point is why migration is deliberate. If a teammate or production machine still runs 0.1.x, preserve the v1 source until that consumer has upgraded.

Inspect before writing

Start with a dry run. It verifies the source and reports the migration without changing the file.

tine verify old-run.tine
tine migrate old-run.tine --dry-run

To keep both versions, write a new artifact:

tine migrate old-run.tine --save old-run-v2.tine
tine verify old-run-v2.tine

Only use --in-place after every required consumer can read v2:

tine migrate old-run.tine --in-place

Saves are atomic in 0.2, so the destination is replaced only after the new artifact has been fully written.

Automatic migration in Python

The Python API follows the same rule:

from opentine import Run

run = Run.load("old-run.tine")  # v1 is migrated in memory
run.save("old-run-v2.tine")     # the saved artifact is v2

Reading is non-destructive. Saving is the upgrade boundary.

What v2 adds

Version 2 creates stable homes for six coordinated features:

  • migration provenance;
  • tags and searchable index data;
  • token usage, cost, and budget policy;
  • autosave draft state;
  • tine-sig/1 signatures;
  • field-level diff data.

Some metadata is intentionally mutable. Adding a tag should not change the content digest or invalidate a signature. Budget policy and draft state affect how a run was governed, so they live inside the protected content boundary.

Legacy 0.1.0 linear artifacts

The migration registry also includes a best-effort importer for the legacy linear 0.1.0 shape. Importing it recomputes step IDs because the old representation cannot supply the complete v2 graph identity.

Treat this as an import, not byte-for-byte preservation: keep the original, inspect the result, and verify the upgraded artifact before using it as a new baseline.

A safe team rollout

  1. Upgrade readers and automation to opentine 0.2.
  2. Verify representative v1 artifacts.
  3. Dry-run their migrations.
  4. Write v2 copies and run your normal inspection, fork, replay, and diff workflow.
  5. Update producers so new artifacts are v2.
  6. Retire v1-only consumers before migrating archives in place.

The format should make history more durable, not turn an upgrade into a data-loss event. That is why 0.2 reads the past automatically and writes the future explicitly.