Reference · v0.44.0
CLI reference
From the pinned CLI source. Read upstream.
Current format policy: Portable .tine files default to v5 (since 0.42). --for-legacy writes v4. The .tine/ repository format is v3. tine evidence export writes v4.
CLI spellings
Since 0.16 related verbs are reachable under a noun group. A group spelling is rewritten to the old verb before parsing, so both take the same flags and give the same output and exit code. The old spellings keep working unchanged.
| Old spelling | New spelling |
|---|---|
tine init | tine repo init |
tine config | tine repo config |
tine worktree | tine repo worktree |
tine branch | tine repo branch |
tine reset | tine repo reset |
tine reflog | tine repo reflog |
tine archive | tine repo archive |
tine pack | tine repo pack |
tine migrate | tine repo migrate |
tine serve | tine repo serve |
tine du | tine repo storage du |
tine gc | tine repo storage gc |
tine repack | tine repo storage repack |
tine prune | tine repo storage prune |
tine compress | tine repo storage compress |
tine fsck | tine repo storage fsck |
tine reindex | tine repo storage reindex |
tine hook | tine repo integrate hook |
tine enable | tine repo integrate enable |
tine disable | tine repo integrate disable |
tine plugin | tine repo integrate plugin |
tine harnesses | tine repo integrate harnesses |
tine git | tine repo integrate git |
tine push | tine share push |
tine fetch | tine share fetch |
tine pull | tine share pull |
tine clone | tine share clone |
tine remote | tine share remote |
tine bundle | tine share bundle |
tine archive | tine share archive |
tine sign | tine trust sign |
tine keygen | tine trust keygen |
tine attest | tine trust attest |
tine evaluate | tine trust evaluate |
tine promote | tine trust promote |
tine verify-tag | tine trust verify-tag |
tine who | tine agent who |
tine actions | tine agent actions |
tine touched | tine agent touched |
tine blame | tine agent blame |
tine audit | tine agent audit |
tine migrate-v3 | tine repo migrate --to-v3 |
tine bundle verify FILE | tine verify FILE (FILE is a bundle, no other arguments) |
Since 0.17 log and show also front the read-only verbs. The folded flag is
rewritten to the old verb before parsing, so both spellings give the same output
and exit code; a flag the old verb does not take is a usage error (exit 2), as
are --cost with --price, --at without --price, and log --search with a
log option (--graph, --all, --oneline, --limit, --commit, --pr, REF).
| Old spelling | New spelling |
|---|---|
tine search QUERY | tine log --search QUERY |
tine ls | tine log --legacy |
tine ls --tag T --model M ... | tine log --tag T --model M ... (an ls filter implies --legacy) |
tine cost RUN | tine show RUN --cost |
tine price RUN [--at DATE] | tine show RUN --price [--at DATE] |
tine log without these flags is unchanged: it reads the v3 repository, while
--legacy lists the legacy .tine_runs index that tine ls lists.
tine stats --repo PATH is new in 0.36: run inside a v3 repository (or with
--repo), stats counts the repository's store (runs, events, blobs, objects,
canonical bytes, cost; --json adds a store object and scope: "v3-repository") instead of the legacy .tine_runs index. --group-by takes
model, status or day there; the ls filters and --deep stay legacy-only.
Elsewhere stats reads the legacy index exactly as before.
tine trust policy set|list|show|rm|default is new in 0.16 (no older spelling):
named trust policies for tine verify --policy NAME (see below).
tine agent id|show|trust|keys are unchanged. tine GROUP --help lists a group;
tine help --all lists every command.
tine hold add|list|release OID|REF is new in 0.35 (no older spelling): it
keeps objects and everything they reach from prune, gc --prune=now,
rewind --apply and remote deletes. Also new in 0.35: gc --prune=never|now
(default never until 0.39, which adds retention and makes it the default:
see tine retention show|check and REPOSITORY.md), verify --offline --hermetic (exit 6 where no OS sandbox
exists, Windows included), rewind --allow-control-dirs,
replay --trust-recorded-prompt and serve reseal --to aes4 --from aes2.
New flags in 0.37 (no new subcommands):
gc --level N/repack --level N: the pack compression level (zstd 1-22, default 19; zlib caps at 9). Auto-pack reads"auto_pack": {"level": N}from the repository'sconfig.json.archive create --archival: writes the archive with xz (storage codec 4, zlib where Python lackslzma), so a stock Python 3.11+ restores and verifies it with no optional package. opentine 0.36 and older cannot read codec 4, which is written only on this request.fsck --budget SECONDS/fsck --max-objects N: stop the object walk cleanly; the JSON report gainscheckedandcomplete(exit 0 when nothing checked failed), and stderr says how far it got.gcalso removes staging files left by killed writers once they are an hour old (reaped_tempin--json); live writers' files are never touched.
New in 0.38: tine rewind restores a workspace snapshot (a tree blob, SPEC
§1.5.7) exactly. tine rewind TREE_OID takes the tree id directly;
tine rewind RUN[@STEP] --tree uses the tree linked from that step
(outputs.tree, or the nearest earlier step with one). --repo DIR names the
repository holding the snapshot (default: the one containing --root). Dry run
by default; --apply writes every file, link and executable bit back byte for
byte and removes tracked paths the snapshot did not have, so changes made
through a shell are undone too. Writes go through the 0.35 O_NOFOLLOW
directory-descriptor writer; control files are refused without
--allow-control-dirs; ignored, version-control and omitted paths (too large
or unreadable at capture) are left alone; a file stored redacted is refused.
--json reports restore, remove, unchanged, refused and kept.
Errors, --json and exit codes (0.36)
Every leaf subcommand accepts --json. Commands with their own JSON payload
keep it unchanged; fleet up (with or without --dry-run) and
replay --dry-run/--inspect now emit one JSON object instead of ignoring the
flag. Any other command wraps its human output:
{"command": "fsck", "exit_code": 0, "output": "..."}
The v3 plumbing verbs (fsck, object, migrate-v3, fetch, push) always
print bare JSON; --json on them is a no-op. output.format = json turns on
only a command's own JSON, never the wrapper.
Errors go to stderr. Under --json, stdout carries only JSON: a failing command
that wrote no JSON of its own emits one error object (a usage error included)
and anything human it printed moves to stderr:
{"error": {"code": "not_found", "exit_code": 3, "message": "..."}}
| Exit | code | Meaning |
|---|---|---|
| 0 | — | ok |
| 1 | error | any other failure |
| 2 | usage | bad flags or arguments, or a refused flag combination |
| 3 | not_found | a run, ref or object that does not exist |
| 4 | verification_failed | a signature, digest or verdict did not hold |
| 5 | budget_exhausted | a budget or limit stopped the work |
| 6 | trust_required | needs a trust decision, or is unsupported here (verify --hermetic) |
Existing exit statuses keep their meaning; commands move to the specific codes
as they are revised, so a script should treat any non-zero status as failure
and read error.code for the reason.
New in 0.36: serve --oidc-issuer URL --oidc-audience AUD verifies OIDC bearer
tokens instead of the static token (--oidc-jwks-uri URL pins the key set,
otherwise it comes from the issuer's discovery document; every URL must be
https:// and none is ever taken from a token; --oidc-tenant-claim and
--oidc-roles-claim name the claims). The static token must now hold at least
32 bytes; serve --allow-weak-tokens starts with a shorter one while it is
rotated. After 5 consecutive failed authentications a client gets 429 with
Retry-After for a delay that doubles per failure (up to 5 minutes), and a 500
answers only {"error":"internal","request_id":...}, logging the exception.
New in 0.44: serve --quota-rate PER_SECOND [--quota-burst N] gives every
(tenant, subject) a token bucket; an upload or ref update over quota gets 429
with Retry-After. At most --quota-max-keys buckets (10,000) are held, the
least recently used evicted first. Clients retry a 429 at most 3 times,
honouring Retry-After up to 30 seconds and within the request deadline; a
0.34 client reports remote returned HTTP 429 and stops. serve --vsa-dir DIR
writes an in-toto SLSA Verification Summary Attestation
(https://slsa.dev/verification_summary/v1) for every admitted push to
DIR/<tenant>/<sha256>.json.
Default output format
tine config set output.format json # every command with --json now emits JSON
tine config get output.format # prints json; exit 1 when unset
tine config unset output.format
OPENTINE_OUTPUT=text tine show RUN # the env var wins over the file
tine show RUN --text # human output for this call only
output.format is text or json, stored only in the user's
$XDG_CONFIG_HOME/opentine/settings.json (written 0600; a repository cannot set
it). Precedence: an explicit --json or --text on the command, then
OPENTINE_OUTPUT, then the file, then text. Every command that has --json also
has --text; giving both is an error. Commands whose --json is only the
0.36 wrapper ignore the setting and never read the file. A value other than text/json in the env var
or the file, or a malformed file, stops the command with a one-line error (exit
- instead of guessing.
tine config set|get|unsetare the user settings;tine config KEY [VALUE]still edits the repository's porcelain keys. With no setting, every command's output is unchanged.
Op log and undo (0.36)
Every tine command that moves a local ref (branch, tag, reset, fork,
pull, rebase, cherry-pick, ...) appends one entry to the op log: op id,
command, actor, time and each ref's old -> new. The log is opentine-log/1, a
hash-chained record log in the C2SP tlog-tiles
layout under .tine/log/op/ (checkpoint, tile/<L>/<N>, tile/entries/<N>),
with an Ed25519 signed-note checkpoint; the
verifier key is in .tine/log/op/vkey.
tine op log [-n N] [--json]lists ops, newest first.tine op verify [--vkey KEY] [--json]recomputes every tile, the Merkle root, the hash chain and the checkpoint signature from local files only (it never touches the network).--vkeypins a key obtained out of band.tine undo [OP] [--force] [--json]puts back the refsOP(id, id prefix or index; default the latest) moved, as a new forward ref transaction that is itself logged (undoes), sotine undotwice redoes. It refuses (exit 1) when a ref was moved since by a later op (superseded) or by a writer that does not log, such as opentine 0.34 or a library caller (gap: the ref differs from the logged value, or its reflog has newer rows);--forceundoes anyway.
Offline verification (0.25)
tine verify RUN --offline # human report
tine verify RUN --offline --json --report r.json # tine-verify-report/2
tine verify RUN --offline --pubkey release.pub --strict
tine verify RUN --offline --attestation a.sigstore.json --trusted-root trusted_root.json \
--cert-identity ci@example.com --cert-oidc-issuer https://token.actions.githubusercontent.com
tine verify RUN --offline --action-policy policy.toml
Every check runs from local files only; a socket connect or DNS lookup during the run is a hard error. Each check names its trust basis.
What "offline verified" proves:
- the file's bytes match its own sha256 digest (internal consistency: anyone who edits a run can also recompute its digest, so on its own this proves nothing about who wrote it);
- with
--pubkey,--pin,--key-fileor--key-env, that the holder of that key signed these bytes -- the only case the report fillsauthorship; - with
--attestation, that the statement is signed and names this digest, and that a receipt it carries is signed by the Rekor key or trusted root you gave; - for a keyless bundle, that the certificate chains to your Fulcio root /
trusted root, matches
--cert-identity/--cert-oidc-issuer, and (with CT keys) carries a valid SCT.
What it does not prove: that the log still contains the entry or was not
rolled back (no live inclusion or consistency check), that a key or certificate
was not revoked later, that your trusted root is current, or anything about a
check reported unavailable-offline. --trust-embedded-key verifies a key the
file itself carries, so it is reported as trust-on-first-use, never authorship.
Use --strict to make any missing required check fail the verdict.
--locate reports where a failed run broke, using only finer-grained hashes
that exist: step ids (each covers a step's kind, inputs, outputs, model_info,
tool_info, error and parent_ids, so it names the step, not the field), a stored
action manifest, or a key-verified attestation subject. When none of them
explains the break it says locate.unlocalisable rather than guess. Byte
offsets index the canonical JSON of the redacted, stored body with
metadata removed (what the digest covers), not the file on disk.
tine verify --offline DIR|REPO writes one tine-verify-dataset/1 report with
a Merkle root over the sorted (run_id, digest) pairs (leaf
sha256(0x00 || canonical_json([run_id, digest])), node
sha256(0x01 || left || right), an odd node carried up unchanged). A
repository run's digest is its tine-actions/1 run_digest.
tine timestamp data RUN
tine timestamp attach RUN TOKEN.tsr
tine verify RUN --offline --tsa-roots FILE.pem
0.31.0: offline RFC 3161 timestamp checks. timestamp data prints the exact
bytes a token must cover (the run's digest string, no newline); build the query
and fetch the response yourself, for example
tine timestamp data run.tine > bound.txt,
openssl ts -query -data bound.txt -sha256 -cert -out q.tsq, then POST q.tsq
to your TSA. opentine never contacts a TSA. timestamp attach checks the
response parses and covers the run's current digest, then stores it in
RUN.timestamps.json. verify --offline then reports one timestamp check per
token (imprint, TSA signature, timestamping EKU, genTime within the
certificate's validity, chain to a root in --tsa-roots or the
--trusted-root TSAs) and a timestamps section with genTime, TSA name,
policy OID and hash algorithm (SPEC §8.6).
tine timestamp data RUN --signature [N]
tine verify RUN --offline --report r.json --sign-key KEY [--timestamp]
tine verify-report data r.json
tine verify-report attach r.json TOKEN.tsr
tine verify-report check r.json [--pubkey P] [--tsa-roots FILE.pem] [--allow-unsigned] [--json]
0.39.0 (X20, X22). timestamp data --signature prints sig:sha256:<hex> of
the run's N-th signature block; a token over it verifies only while the run
carries that signature, and the report's signing_time is its genTime (the
verified signing time). Root-bound tokens keep verifying. --sign-key (an
Ed25519 key file from tine keygen, --report only) writes the
tine-verify-report/2 as signed canonical JSON; --timestamp (needs
--sign-key) also writes r.json.tsdata, the bytes a TSA token over that
signature must cover. verify-report check verifies the report offline and
exits 0 when it is authentic (whatever verdict it records), 4 when its
signature or a token fails, and 4 for a /1 or unsigned report unless
--allow-unsigned (SPEC §8.7).
tine replay RUN --verify --attest OUT.intoto.jsonl --attest-key KEY
Writes the verdict as an in-toto replay/v1 DSSE envelope, predicate type
https://opentine.dev/attestation/replay/v1 (SPEC §8.8). Both flags need
--verify; --attest needs --attest-key.
tine custody record ACTION SUBJECT --sign-key KEY [--actor A] [--note N] [--repo R]
tine custody record timestamp SIG_BOUND --token T.tsr --sign-key KEY
tine custody log [--json]
tine custody verify [--pubkey P] [--vkey V] [--tsa-roots FILE.pem] [--json]
Chain of custody on the repository's opentine-log/1 (.tine/log/custody):
each record says who (--actor, default the login name) received,
exported, verified, transferred or stored what, when, and is signed by
that actor's Ed25519 key. A timestamp record stores a TSA token over an
earlier record's sig_bound (printed by record and log). verify checks
the checkpoint, tiles, hash chain, signatures and tokens offline and exits 4
on any break (SPEC §8.9).
tine witness vkey --key KEY --name NAME
tine witness cosign CHECKPOINT --log-vkey V --key KEY --name NAME
[--proof P.json | --tiles DIR] [--state DIR] [--out FILE] [--json]
tine verify TARGET --offline --witnesses N-of-M --witness-vkey V... [--log-vkey V...]
tine bundle create FILE REF... --transparency
0.44 (X33). witness cosign checks a signed-note checkpoint against the pinned
log key and against the last checkpoint this witness cosigned for that origin
(--state, default $XDG_STATE_HOME/opentine/witness): the same size must have
the same root, a smaller size is a rollback and a larger one needs an RFC 9162
consistency proof (--proof, or computed from a local tile mirror with
--tiles). Only then does it print the checkpoint with a C2SP
cosignature/v1 line added; a fork or rollback exits 4. witness vkey prints
the key others pin with --witness-vkey. verify --offline --witnesses N-of-M
takes a bundle, an opentine-tlog-receipt/1 file or a bare checkpoint (with
one --log-vkey) and exits 4 unless N of the M pinned witnesses cosigned every
checkpoint; --log-vkey pins a log key by origin (otherwise the receipt's key
is used, trust on first use). bundle create --transparency embeds op-log and
push receipts for the bundled refs so they verify from the bundle alone; such
bundles need opentine 0.44+ to read. tine push and tine fetch check the
remote's audit log automatically (SPEC §8.10).
tine scitt verify STATEMENT --key PEM [--receipt R]... [--service-key PEM] --experimental
0.44, experimental: a COSE_Sign1 SCITT signed statement and its
RFC9162_SHA256 receipts, verified offline against pinned keys (SPEC §8.12).
Without --experimental it exits 2. Interop with scitt-api-emulator is not
claimed.
tine evidence export RUN... --out DIR [--sign KEY] [--pubkey P] [--pin FPR]
[--action-policy FILE] [--attestation FILE]
[--trusted-root FILE] [--operator NAME]
Writes MANIFEST.sha256, custody.jsonl, timeline.jsonl, timeline.csv,
verify-report.json, trust/ and runs/. custody.jsonl is outside the
manifest (it holds the only timestamp) and names the manifest's SHA-256; with
--sign it is signed with Ed25519 over opentine.custody.v1: + canonical JSON.
--attestation (one run only) and --trusted-root (only with a keyless
attestation) feed the attestation checks and are copied into trust/.
docs/conformance/minimal_verifier.py evidence DIR re-checks the folder
without opentine (SPEC Part 8).
tine evidence report RUN --format html|pdf -o PATH [--pubkey P] [--pin FPR]
[--action-policy FILE]
New in 0.39. Writes one run's offline verification, timeline and the
canonical evidence JSON (embedded as <script type="application/json" id="tine-evidence">) as one self-contained page. The HTML is canonical and
byte-identical across runs: no wall-clock time (only the run's own), the
source reduced to its file name, sorted-key canonical JSON, inline CSS, the
tine view CSP (no scripts, nothing fetched), and every string re-redacted.
--format pdf needs pip install 'opentine[pdf]' (pikepdf; exit 6 without it)
and is a derivative: fixed /CreationDate from the run, content-derived /ID,
evidence.json attached with /AFRelationship /Data. It is deterministic for
a given pikepdf/qpdf version, but only the HTML is gated on byte identity; the
PDF uses the base-14 Courier font (no system font is read), so it is not yet
PDF/A-3 conformant.
tine retention show|check [--repo DIR] [--json] (0.39) prints the retention
policy, or dry-runs what default gc would prune.
Trust policies
tine trust policy set prod --pubkey ~/keys/release.pub --rekor-key ~/keys/rekor.pem --require-receipt
tine trust policy set ci --cert-identity ci@example.com --cert-oidc-issuer https://token.actions.githubusercontent.com \
--fulcio-root ~/keys/fulcio.pem --rekor-key ~/keys/rekor.pem --ct-key ~/keys/ctlog.pem --require-sct
tine trust policy set sigstore --cert-identity ci@example.com \
--cert-oidc-issuer https://token.actions.githubusercontent.com --trusted-root ~/keys/trusted_root.json
tine trust policy list [--json]
tine trust policy show prod [--json]
tine trust policy default prod # or: --clear; no argument prints it
tine trust policy rm ci
tine verify RUN --attestation a.intoto.jsonl --policy prod
tine verify RUN --no-policy # ignore trust.default for this call
A policy holds pubkey, pin, rekor_key, require_receipt, cert_identity,
cert_oidc_issuer, fulcio_root, and (0.18) ct_key (a list of CT log key
files), require_sct and trusted_root (which replaces rekor_key,
fulcio_root and ct_key). Flags given on the command line win over the
policy; any key flag (--pubkey, --pin, --key-env, --key-file,
--trust-embedded-key) replaces the policy's key as a whole. Fields that do not
apply (keyless fields for a key-signed attestation, receipt fields for a plain run
verify) are unused rather than refused. The default policy applies only when no key,
receipt or keyless flag and no --policy is given. --trust-embedded-key cannot
be stored in a policy.
Sigstore trusted root (0.18)
tine verify RUN --attestation a.sigstore.json --cert-identity ci@example.com \
--cert-oidc-issuer https://token.actions.githubusercontent.com --trusted-root trusted_root.json
tine trust root update --root root.json [--repo-url https://tuf-repo-cdn.sigstore.dev] [--json]
tine trust root update # later runs: stored root and repository
--trusted-root FILE takes the Rekor keys (tlogs), Fulcio chains
(certificateAuthorities) and CT log keys (ctlogs) from one Sigstore
trusted_root.json, honouring each entry's validFor window. It is a usage
error beside --rekor-key, --fulcio-root or --ct-key. When the root lists
CT logs, an embedded SCT is required.
tine trust root update is a minimal TUF client: it refreshes
trusted_root.json into $XDG_CONFIG_HOME/opentine/sigstore/, after which that
copy is the default for keyless tine verify --attestation calls that name no
key file. Nothing is ever fetched implicitly. No TUF root is embedded: the first
run needs --root FILE, an initial root.json you obtained and checked out of
band (for the Sigstore public-good instance, from
sigstore/root-signing, e.g. its
metadata/root_history/ or https://tuf-repo-cdn.sigstore.dev/N.root.json
compared against the signing ceremony). To start over, remove
$XDG_CONFIG_HOME/opentine/sigstore/tuf/.
Agent Trace export (0.19)
tine export RUN --format agent-trace # record on stdout
tine export RUN --format agent-trace --output trace.json
Writes one Agent Trace record (RFC 0.1.0, validated
against https://agent-trace.dev/schemas/v1/trace-record.json). Each file the
run's successful tool calls wrote is a files entry with one conversation per
model, contributor ai, model_id spelled provider/model when the provider was
recorded. Line ranges are emitted only when they are known: a whole-file write
that is the run's last write to that path covers lines 1..N. Edits, patches and
shell redirects get file-level attribution (an empty ranges array). Absolute
paths are made relative to the enclosing repository (the nearest directory with
.git, else the current directory); paths outside it are left out and counted.
vcs and conversation url are omitted, since a run records neither; the run
id rides in metadata["io.github.0xcircuitbreaker.opentine"]. version is "0.1", the spelling the
published schema accepts. --endpoint is refused.
Citation export (0.25)
tine export RUN --format citation --output CITATION.cff
tine export RUN --format ro-crate --output ro-crate-metadata.json
citation writes a Citation File Format
1.2.0 document (type: dataset); ro-crate writes an
RO-Crate 1.1 ro-crate-metadata.json with
the metadata descriptor, a root Dataset, the run file, and opentine plus
each model as SoftwareApplication entities. Both carry the run id, the
integrity digest (sha256:…, SPEC §3.5), every model the run recorded, the
run's own creation time and the opentine version. Nothing else varies (no
clock, host or path), so the same run and version always give the same bytes.
A run whose digest does not verify is refused, and --endpoint is refused.
Without --output the document goes to stdout.
Entire checkpoint import (0.19)
tine import . --format entire --save run.tine # newest checkpoint, last session
tine import .::a3b2c4d5e6f7/0 --format entire --repo runs
Entire commits coding-agent sessions to the
entire/checkpoints/v1 branch (<id[:2]>/<id[2:]>/metadata.json, one numbered
directory per session with metadata.json, full.jsonl and prompt.txt).
SOURCE is the git repository; ::ID picks a checkpoint by id or unique prefix and
/N a session (0-based, in the summary's order). The branch is read with
git cat-file, never checked out; origin/entire/checkpoints/v1 is used when
there is no local branch. --format auto recognizes a directory SOURCE. The
session transcript is imported by the Claude Code, Codex or Gemini CLI importer;
any other agent imports as one human step carrying its prompt, with an import
warning. attributes["entire"] on the first step keeps the checkpoint and session
ids, agent, model, strategy, branch, commit, files touched and Entire's token
usage. full.jsonl holds the session up to that checkpoint, so the run is the
session so far. Session metadata over 1 MiB and transcripts over 64 MiB are
refused before they are read.
Per-checkpoint refs, --all and export (0.42)
tine import . --format entire --save run.tine # refs first, v1 branch as fallback
tine import . --format entire --all --repo runs # every checkpoint session, one run each
tine export run.tine --format entire --output ~/proj # write the run as a checkpoint ref
Current entireio/cli keeps one ref per checkpoint,
refs/entire/checkpoints/<id[-2:]>/<id>, whose commit tree is the checkpoint
(metadata.json, 0/, 1/ ...; sessions listed as /<N>/metadata.json).
Those refs are read first, newest commit first; any checkpoint id found only on
the entire/checkpoints/v1 branch is read from there. attributes["entire"] ["layout"] says which (refs or branch). --all records each session of
each checkpoint on heads/entire/<id, lowercased>/<N> and needs --repo
(--save, --ref and --fleet are refused with it); with --json it prints
{"command": "import", "format": "entire", "all": true, "runs": [...]}.
export --format entire writes the run, redacted, as one checkpoint in the
--output git repository: a 12-hex id derived from the run id, a Claude Code
full.jsonl, prompt.txt, content_hash.txt and both metadata files, committed
with Entire's Checkpoint: <id> message and Entire-Session/-Strategy/-Agent
trailers. Only git objects and that one ref are written. Exporting the same run
again is a no-op; a changed run becomes a child commit on the same ref.
Cline and Roo Code task import (0.42)
tine import ~/.config/Code/User/globalStorage/saoudrizwan.claude-dev/tasks/1730985600000 --save run.tine
tine import --from-default-location --format roo-task # list Roo Code tasks
SOURCE is a task directory (or its api_conversation_history.json);
ui_messages.json and Cline's task_metadata.json beside it are read when
present. Each assistant message is a model step, tool results (native
tool_result blocks or the [tool for 'x'] Result: text convention) are tool
steps, and other user turns human steps, with <environment_details> blocks
dropped. Token usage comes from the matching api_req_started record (Roo's
apiProtocol: "openai" counts cache reads inside tokensIn), else from the
message's metrics. auto tells Roo from Cline by the
rooveterinaryinc.roo-cline folder in the path. Windsurf is not supported: it
has no documented local session format.
Writer format (0.26, 0.42)
Since 0.42 .tine files are written as format v5 (SPEC Part 10): the v4
document with UTF-8 text blobs spelled as text, carrying the same oids, root
and tine-sig/3 signatures; opentine 0.40 or newer reads it. --for-legacy
writes v4 for older readers, and tine evidence export always copies its runs
as v4. Since 0.26 every writer produces format v4 objects (SPEC Part 9):
.tine files were tine-artifact/4 until 0.42, signatures tine-sig/3, Ed25519 attestations on a run
tine-attest/2, and tine init creates an object-format-4 repository (an
existing repository is marked object format 4 before the first object 0.26
writes into it). Reading never changes: every older file and repository stays
readable, and a read never rewrites it.
| Spelling | Writes |
|---|---|
| (default) | format v5 .tine files (SPEC Part 10; opentine >= 0.40 reads); new repositories object format 4 |
tine --for-legacy COMMAND ... (or --format 4) | format v4 .tine files, for readers before 0.40, for this command only |
tine --format 2 COMMAND ... | the deprecated v2 file / object-format-3 repository writers, for this command only |
OPENTINE_FORMAT=2 (or 3) | the same, for the whole environment |
OPENTINE_FORMAT=4 | v4 files for the whole environment, strict: no deprecated block even where v4 cannot express it (an HMAC attestation, sign_artifact on a v2 dict) |
tine migrate FILE | upgrades to v4 (--to v4 is the default; -o/--save names the output, else NAME.v4.tine) |
tine migrate FILE --to 2 | the deprecated in-file v1 -> v2 migration |
The legacy writers print one deprecation warning per process on stderr. A file
or repository written by 0.26 needs opentine 0.26 or newer; share with older
releases with tine --format 2. An explicit write refuses an integer beyond
2**53-1 or a non-finite number, naming the field; recorders (tine run, tine record, imports, hooks, serve --otlp) store such a value as its exact string
and list the field under metadata.warnings instead of losing the run.
tine bundle (and bundle push/fetch) carries the tine-sig/3 blocks of
imported v4 runs in the bundle manifest.
FIPS mode (0.41)
tine --fips COMMAND ... # or OPENTINE_FIPS=1
--fips is global, like --format. Without an active OpenSSL FIPS provider
in cryptography every command fails before it runs with exit 6
(trust_required) and, under --json, {"error": {"code": "trust_required", ...}}. A non-approved primitive met later (ChaCha20-Poly1305, writing the
archival xz form) fails the same way. tine verify --offline --json adds
crypto: {mode, provider_fips, openssl} to the report.
tine serve --root R --tenant T reseal --to aes6 rewrites a tenant's objects
as TINEAES6 (key id, epoch, XAES-256-GCM); it needs TINE_KMS_KEY_ID set.
Fan-out status and MCP tools (0.36)
tine fleet status [ID] --repo PATH lists the repository's tine fan-out
records (.tine/fanouts/) instead of
the fleets in --dir; with --json it prints
{"command": "fanout status", "fanouts": [...]}.
The MCP server (python -m opentine.mcp_server) builds its tool list from one
registry (opentine/_mcp_registry.py), each tool annotated read or write. The
default exposes only read tools; --allow-writes or
OPENTINE_MCP_ALLOW_WRITES=1 adds exactly the annotated write set (never
promote_run). The read tools generated from the registry return the same
payload as their command's --json:
| Tool | Command |
|---|---|
verify_run | tine verify RUN --offline --json |
log | tine log [REF] --limit N --repo REPO --json |
fleet_status | tine fleet status [ID] --json |
fanout_status | tine fleet status [ID] --repo REPO --json |
cost | tine cost RUN --json |
agent_show | tine agent show TARGET --repo REPO --json |
stats | tine stats [--group-by KEY] --limit N --json |
New in 0.44, recall(query, limit=10) is a hand-written read tool over the
derived search index (tine repo-search --rebuild-index, see
REPOSITORY.md): runs whose stored text mentions every word of
the query, best BM25 match first, at most 50 rows of run id, status, models and
a snippet of at most 240 characters. It never scans the store or builds the
index; without one it answers {"indexed": false, ...}.
Cost export (0.44)
tine cost RUN --otlp PATH|- # OTLP/JSON metrics from the cost aggregate
tine cost RUN --statement PATH --sign-key KEY [--signer NAME]
tine cost RUN --verify-statement PATH [--pubkey KEY.pub]
--otlp writes an ExportMetricsServiceRequest (a /v1/metrics body):
gen_ai.client.token.usage by gen_ai.token.type and opentine.cost.usd in
total, by gen_ai.request.model and by opentine.step.kind, as cumulative
sums on a resource carrying opentine.run.id. --statement writes a
tine-cost-statement/1: the aggregate (totals, tokens, by model, by kind) with
an Ed25519 tine-sig/3 block under opentine.cost-statement.v1:.
--verify-statement recomputes the aggregate from RUN and prints
{"ok", "matches_run", "signature", "basis"}, exiting 4 unless both the numbers
and the signature check (without --pubkey the embedded key is trusted on first
use, and basis says so). The statement covers the cost the run recorded;
tine price re-prices from the catalog.
Per-turn capture (0.38)
| Command | What it does |
|---|---|
tine hook capture [--agent NAME] --repo PATH | opentine-hook/1: one JSON event on stdin becomes one durable step of the session's run; prints a JSON response and always exits 0 |
tine enable [--agent NAME] [--dry-run] --repo PATH | Adds the capture shims to the Claude Code, Codex and Gemini CLI hook files and sets hooks.capture; --dry-run prints the unified diff only |
tine disable [--agent NAME] [--dry-run] | Restores each hook file byte for byte (or removes only the shims if it was edited since) |
Capture records nothing unless the repository's trusted config sets
hooks.capture. See CAPTURE.md.
MCP proxy capture (0.38)
tine mcp-proxy [--save PATH] [--force] [--repo PATH [--ref REF]] -- CMD [ARGS...]
tine mcp-proxy --http-upstream URL [--listen HOST:PORT] [--allow-non-loopback] [--save PATH] [-- CMD...]
Relays an MCP session over stdio (spawning CMD) or Streamable HTTP and records
each JSON-RPC exchange as a redacted tool step, saved incrementally. In HTTP
mode an optional CMD is run alongside and the proxy stops when it exits;
otherwise it serves until Ctrl-C or SIGTERM. --listen defaults to
127.0.0.1:0 (the chosen port is printed on stderr). See
CAPTURE.md.
Assurance tiers (0.39)
| Command | What it does |
|---|---|
tine proxy keygen [--force] [--json] | Creates the proxy witness key (Ed25519) under $XDG_CONFIG_HOME/opentine/proxy-keys/, apart from every agent key; tine record and tine mcp-proxy sign their finished runs with it (tine-sig/3) |
tine verify RUN --min-assurance T0..T3 | Exits 4 (verification_failed) when the verified tier is below the floor |
tine verify RUN --proxy-pubkey FILE | Also trusts this proxy public key as a T2 witness (repeatable) |
tine verify RUN --min-assurance T3 --tsa-roots FILE.pem | Lets an attached RFC 3161 token count toward T3 (outside --offline, --tsa-roots needs a floor) |
tine verify RUN --compare-capture OTHER [--json] | Divergence report: the better-witnessed run against the other, step by step (MCP tools/call and prompts); exits 4 when they diverge |
Tiers: T0 self-reported import, T1 hook-captured, T2 witnessed by
the record proxy or tine mcp-proxy and signed with a trusted proxy key,
T3 T2 plus a verified timestamp. The tier a capture claims is recorded
(metadata.capture.claimed_tier); the tier reported is computed at verify
time, and a claim alone never rises above T1. Every report carries an
assurance object, {"claimed", "verified", "witness", "reasons"}: tine verify --json, tine verify --offline (and so the MCP verify_run tool) and
tine show --json; the human output prints one assurance line.
Key storage and signers (0.41)
| Command | What it does |
|---|---|
tine keygen --out PATH / --agent NAME | Writes the private key as encrypted PKCS#8 (PEM, PBES2/AES-256); --unencrypted writes the deprecated plaintext-hex form |
tine key encrypt PATH [--json] | Rewrites a plaintext-hex private key as encrypted PKCS#8 in place; an encrypted key is left alone ("changed": false) |
tine key show SIGNER [--json] | Opens a signer and prints its signer, algorithm, key_id (sha256:<hex>) and public_key |
tine proxy keygen --signer URI [--force] | Makes the key an agent, HSM or KMS holds the proxy witness key; only the URI and the public half are stored |
tine proxy migrate --to URI [--json] | Moves the proxy key into a signer; the old pair goes to proxy-keys/retired/ and stays trusted for runs it signed |
The passphrase for an encrypted key comes from OPENTINE_KEY_PASSPHRASE, the
OS keyring (OPENTINE_KEY_KEYRING=1 with pip install 'opentine[keyring]'),
or a prompt when stdin is a terminal; with none, keygen refuses (exit 1) and
loading the key fails. A plaintext-hex key still loads, with a
PlaintextKeyWarning on stderr.
Every flag that takes an Ed25519 signing key file (sign --ed25519-key-file,
custody record --sign-key, verify --offline --report --sign-key, evidence export --sign, replay --attest-key, push --ed25519-key-file, export --format intoto --ed25519-key-file, actions sign) also takes a signer URI:
| Signer | Backend |
|---|---|
file:PATH or PATH | A key file (encrypted PKCS#8, or legacy hex) |
ssh-agent:FINGERPRINT | An Ed25519 key in ssh-agent (SSH_AUTH_SOCK); SHA256:... as ssh-add -l prints it, sha256:<hex>, or * for the only one |
pkcs11:token=T;object=O?module-path=LIB | An HSM via opentine[pkcs11] (CKM_EDDSA); PIN from pin-source=env:VAR, pin-value= or OPENTINE_PKCS11_PIN |
kms:aws:ARN | AWS KMS ECC_NIST_EDWARDS25519, ED25519_SHA_512 over the raw message (at most 4096 bytes), via opentine[kms-aws] |
kms:gcp:RESOURCE | GCP Cloud KMS EC_SIGN_ED25519 (.../cryptoKeyVersions/N), via opentine[kms-gcp] |
The flag is not spelled --signer there because tine sign --signer already
names the signer recorded in the block. Every backend's signature is checked
against its public key before it is used.
Key lifecycle and verifier hardening (0.41)
| Command | What it does |
|---|---|
tine key rotate KEY [--out NEW] [--json] | A new Ed25519 key, written as encrypted PKCS#8, replaces the private key file KEY (and KEY.pub); the old pair is kept as KEY-retired-<fp12>. The old key gets not_after = now, the new one not_before = now, and the old key signs an endorsement of the new one (tine-key-rotation/1). --out NEW writes the new key elsewhere and leaves KEY in place |
tine key rotate --agent NAME / --proxy | The same for an agent key (keygen --agent) or the proxy witness key (proxy keygen); the retired proxy key goes to proxy-keys/retired/, as with proxy migrate, and stays trusted for T2. A proxy key held by a signer is refused (use proxy migrate) |
tine key revoke KEY [--at TIME] [--json] | Records revoked_at (RFC 3339, default now) for sha256:<hex>, a .pub file or a private key file. An earlier revocation already recorded stands; a malformed --at is a usage error (exit 2) |
tine verify RUN --offline --tsa-policy OID | Accept only RFC 3161 tokens issued under this TSA policy (repeatable) |
tine verify RUN ... --allow-stale-root | Use the TUF-installed trusted root even though its metadata has expired (a warning on stderr) |
Both tine key verbs write only $XDG_CONFIG_HOME/opentine/key-lifecycle.json.
Fleet records and delegation (0.43)
| Command | What it does |
|---|---|
tine key delegate KEY --to PUB --agent NAME --action NAME [--max-depth N] [--not-before T] [--not-after T | --days N] [--parent CHAIN] --out CHAIN [--json] | KEY signs an opentine-delegation/1 certificate (SPEC 4.10) giving PUB the named agents and tools (* is any) for the window (default now to now + 30 days); --out gets the chain, root first, with --parent's certificates before the new one. --agent and --action repeat |
tine key delegation show CHAIN [--json] | Each certificate's digest, issuer, subject, window, parent and scope |
tine key delegation verify CHAIN --signer PUB|FPR [--at T] [--agent NAME] [--action NAME] [--root FPR] [--json] | Verifies the chain offline for that signer at T (default now); exit 4 and the delegation.* code (expired, scope-violation, broken-chain, wrong-signer, bad-signature, too-deep, malformed) when it fails |
tine fleet record RUN.tine [--json] | The run's opentine-fleet/1 record (SPEC 4.11), captured from OPENTINE_FLEET_ID/_MEMBER/_ROLE/_PARENT, and the length of its delegation chain |
tine fleet record RUN.tine --sign-key KEY --out FILE | Writes an opentine-fleet-record/1 document: the record bound to the run's id and digest under a tine-sig/3 block |
tine fleet record RUN.tine --attest OUT --attest-key KEY | Writes an in-toto https://opentine.dev/attestation/fleet/v1 DSSE envelope whose subject is the run's digest |
tine fleet record FILE [--pubkey PUB] | On a signed fleet record: verifies it offline (exit 4 on failure); without --pubkey the embedded key is trusted on first use |
A capture with OPENTINE_DELEGATION=CHAIN stores the chain in the run;
tine verify RUN --offline then adds a required delegation check: the chain
must verify for the run's signer at its signing time, its agent (agt_ ref,
harness, fleet member or role) and every tool it used. The check's detail lists
the chain root first; its trust basis says whether the root is one of --pin.
A trusted .tine/agents.toml may also carry windows
([agents.NAME.lifecycle."sha256:<hex>"] not_after = "..."), as may a trust
policy's key_lifecycle table; the strictest window wins.
tine verify RUN --offline adds a key-lifecycle check whenever a window
names the signer key, judged against the report's verified signing_time (a
signature-bound RFC 3161 token): lifecycle.valid, lifecycle.expired,
lifecycle.not-yet-valid or lifecycle.revoked. With no verified time it is
unavailable-offline / lifecycle.unverified-time, except that a revoked key
fails (lifecycle.revoked-unverified-time) and a claimed signed_at outside
the window fails. Plain tine verify RUN --pubkey/--pin has no verified time:
it exits 4 (verification_failed) on those failures and otherwise notes that
the window was checked against an unverified time.
Timestamp tokens now fail with timestamp.signing-cert-mismatch (no single
ESS signingCertificate/V2 attribute binding the TSA certificate),
timestamp.critical-extension, timestamp.policy-not-allowed, or
timestamp.missing-eku when the timeStamping EKU is not critical or not alone;
genTime plus or minus the token's accuracy must lie inside the TSA validity.
An attestation's tine-attest/2 record must be signed by the DSSE envelope's
key; the detail says record bound (0.41 records name signer_key) or
record unbound (older records, still accepted). Keyless verification refuses
(exit 6) a TUF-installed trusted root whose stored metadata has expired.
Push preview and manifest (0.36)
tine push REMOTE --dry-run (alias --outgoing) prints, as JSON, exactly what
the push would send, and opens no connection: each ref as old -> new (the old
side is the local remotes/<name>/... tracking ref from the last fetch, so the
list is an upper bound if the remote has moved), the objects by kind with their
stored bytes, and every run with the redaction ruleset it recorded (null for
a run that recorded none). It honours --ref, --all and --remote-ref.
--manifest PATH writes the same document as canonical JSON (JCS) -- on a dry
run, or beside a real push before it starts. --key-file (HMAC) or
--ed25519-key-file signs it with a tine-sig/3 header block over
opentine.push-manifest.v1: + JCS of {body, header}; --key-id names the key.
A key flag without --manifest or --dry-run is refused.
git config tine.transcriptRemote NAME (a git remote name, URL or path) makes
the tine git install-hook --push pre-push hook send refs/tine/bundle --
the runs named by Tine-Run: trailers -- to that remote instead of the code
remote, keeping transcripts off the code host.
Run summaries: tine explain (0.42)
tine explain RUN # text summary; stored as an annotation in a v3 repo
tine explain RUN --json # {"command": "explain", "run", "digest", "summary",
# "stored", "annotation", "narrative"}
tine explain RUN --no-store # print only
tine explain RUN --narrative # plus a narrative from a local model
A deterministic, offline summary built from the recorded run alone: what was
asked, models, steps by kind, tools used, files written and read, hosts, the
outcome, errors and failed tool calls, and tokens and cost when the run records
them (absent otherwise, never 0). The same run always gives byte-identical
output. summary.schema is opentine-explain/1; digest is the SHA-256 of the
summary as sorted, compact JSON.
In a v3 repository (--repo PATH, or one in the current directory) the
summary is stored on the run's annotation chain under
metadata["opentine.explain"]; re-running it writes nothing new. A legacy
.tine run is explained but not stored.
--narrative asks the model named in OPENTINE_EXPLAIN_MODEL
(provider[:model], for example ollama:llama3.1) for a few sentences. Only a
local provider is accepted; with none configured the command refuses with exit
code 2 and sends nothing. The narrative is stored apart from the summary, under
metadata["opentine.explain.narrative"], with generated_by: "model", a
label saying it is model-generated and not evidence, the model spec and the
digest of the summary it describes.
Line attribution (0.42)
tine git attribute COMMIT [RUN...] [--sign-key KEY] [--no-configure] [--json]
tine git attribution COMMIT [--verify] [--pubkey KEY.pub] [--json]
tine git attribution COMMIT --format agent-trace
tine stats --ai-share [--rev REV] [--json]
tine git attribute diffs COMMIT against its first parent and matches each
added line to the recorded write that inserted it (the matching tine blame
uses), over the runs given, or else the runs the commit already links through
Tine-Run trailers or notes. The result is stored in the commit's
refs/notes/tine note as one Tine-Attribution: {...} line (schema
opentine-line-attribution/1): per file, ranges with start_line,
end_line, the run, step, seq, tool and model that wrote them, and
the content_hash (SHA-256) of the lines covered. Tine-Run lines for the
runs are kept or added, so tine git log sees the same note. With
--sign-key the record carries an Ed25519 tine-sig/3 block under the domain
opentine.line-attribution.v1:.
The record names no commit, so it stays true when git copies the note to a
rewritten commit. tine git attribute adds this to the repository's config
(skip with --no-configure):
git config --add notes.rewriteRef refs/notes/tine
With it, git commit --amend and git rebase (including rebase -i) copy the
note to the new commit. Set it yourself in clones where attribute has not
run; git does not copy notes by default.
tine git attribution COMMIT --verify checks the signature (against
--pubkey, or the embedded key as trust on first use) and that every range's
hash still matches the lines the commit adds; it exits 1 when either fails.
--format agent-trace prints the note as an Agent Trace
record: vcs is {"type": "git", "revision": COMMIT}, one conversation per
model with contributor ai, ranges with content_hash, and run and step ids
in metadata["io.github.0xcircuitbreaker.opentine"].
tine stats --ai-share blames every text file at --rev (default HEAD) and
counts the lines whose originating commit's attribution note credits them to
a run: total_lines, ai_lines, ai_share, by_model, per-file counts and
commits_with_attribution. Lines in commits without a note count as not
attributed.
Fleet coordination: tasks, leases and steering (0.43)
| Command | What it does |
|---|---|
tine task add ID [--title T] --repo PATH | Creates coord/tasks/ID (opentine-coord/1) |
tine task claim ID --holder NAME [--ttl S] --repo PATH | Takes the lease by one compare-and-swap ref move; prints the new fencing token |
tine task heartbeat ID --holder NAME --fencing N [--ttl S] | Extends the lease; refused (stale) once it expired or was re-claimed |
tine task done ID --holder NAME --fencing N | Closes the task; refused for a stale holder |
tine task list --repo PATH | Every task, its status, holder, token and lease end |
tine fleet resume fleet.toml --id ID [--trust] | Runs the members of fleet ID that did not finish; the manifest digest must match the record |
tine fleet logs ID [--member KEY] | Prints each member's captured output |
tine fleet send ID --member M --message TEXT --repo PATH | Queues a steer message in coord/mailbox/ID/M |
Every task and mailbox version is an annotation chained by previous_id, so
the ref's history is the record's audit trail. Of any number of racing
claimants exactly one compare-and-swap wins; an expired lease is re-claimed
with a higher fencing token. With --json each task verb prints
{"command": "task <verb>", "task": {...}} ("tasks": [...] for list); a
refused operation exits 1 with {"error": {"code": "held|stale|done|exists|missing|contended", ...}}.
A sent message is delivered by the member's tine hook capture at its next
turn end (the hook inherits OPENTINE_FLEET_ID and OPENTINE_FLEET_MEMBER
from tine fleet up), once, and recorded as a human step with actor
steer. The generic response carries "steer": [TEXT, ...]; Claude Code's
Stop hook gets {"decision": "block", "reason": TEXT}, so the agent
continues with the message. Capture must be enabled (hooks.capture).
tine serve (0.43) also takes POST /v1/tenants/T/ref-txn with
{"updates": [{"name", "new", "expected_old"}, ...]} (at most 64): every move
is checked exactly as PUT /refs/<name> checks it, then all are applied in one
index transaction or none (409 {"updated": false}). The server lists
"ref_txn": true in /v1/capabilities; tine push then moves the head and
the run's annotation ref in one transaction, and keeps one PUT per ref
against a server that does not list it.
Command examples from README
Record tine run, tine import capture agent runs
Inspect tine log, tine show read history and runs
Branch tine fork, tine replay explore from any step
Trust tine verify, tine trust verify and sign what was recorded
Collaborate tine share push, fetch, clone and bundle runs
Agents tine agent agent identities, keys and history
Repository tine init, tine repo set up, maintain and integrate a repository
Help tine help [--all] [COMMAND] find every other command
tine run <script.py> Execute a Python script and save the Run it builds
tine run --model anthropic --prompt P Call a bundled model adapter directly, no script
tine run --harness codex --prompt P Record an external CLI agent as a run
tine repo integrate harnesses List agent CLIs --harness can drive, installed ones, fidelity
tine show <run> Pretty-print a run tree
tine show <run> --cost Show cost, tokens, and budget state as recorded
tine show <run> --price --at 2026-07-15 Re-price a run from the catalog (also prices imports)
tine verify <run> Verify integrity, and authenticity when a key is given
tine trust sign <run> --key-env TINE_KEY Sign an artifact (hmac-sha256 or ed25519)
tine trust keygen --out key --pub key.pub Generate an Ed25519 keypair (private key 0600)
tine trust keygen --hmac --out release.hmac Generate a 32-byte HMAC key
tine fork <run> --from-step 3 Branch from a step and continue there
tine replay <run> --mode cache Reuse recorded steps; --mode rerun re-executes
tine replay <run> --verify Check the replay reproduces the run: exit 0/1
tine diff <run_a> <run_b> Compare two runs step by step; --exit-code for 0/1
tine resume <run> Continue a run whose manifest declares resume support
tine repo migrate <run> --to v4 --in-place Upgrade an older artifact to format v4
tine log --legacy --tag prod --limit 20 List indexed runs from .tine_runs
tine log --search "tag:prod model:kimi" Query that index
tine tag <run> --add prod Add, remove, or list tags
tine repo storage reindex Rebuild .tine_runs/index.json
tine agent who --program rm --by agent,model Which agents ran a program, grouped
tine agent who --host '*.amazonaws.com' --by agent Which agents called a host
tine agent who --mcp 'github/create_*' --since 7d Which agents used an MCP tool
tine agent actions <run> One run's tool calls in order
tine agent touched --path 'src/**/secrets*' Which agents wrote or deleted a path
tine agent audit --policy agents.toml Check actions against deny/warn rules; exit 1 on deny
tine agent audit --policy p.toml --require-signed Also fail unless every run's action manifest verifies
tine agent id --harness claude-code --model M The agt_ ref an agent records (definition files hashed)
tine agent show <run|agt_ref> Identity, trust state and lineage of a run or agent
tine trust keygen --agent coder An agent signing key, kept in the user config dir
tine key rotate --agent coder New key; the old one gets not_after=now and endorses it
tine key revoke sha256:... --at 2026-01-01T00:00:00Z Signatures verified as made after that time fail
tine key delegate boss.key --to coder.pub --agent coder --action Bash --out chain.json Scoped, expiring authority
tine key delegation verify chain.json --signer coder.pub Check a delegation chain offline (exit 4 on failure)
tine agent actions <run> --sign --agent coder Sign the run's actions (tine-actions/1)
tine agent actions <run> --verify --pin sha256:... Trust state: verified, unsigned, mismatch or unknown-key
tine agent who --lineage agt_... --verified-only An agent and its subagents, verified runs only
tine repo storage gc Pack a repository's objects (about 18x less disk)
tine repo storage repack Merge packs into one
tine repo storage du --by run Disk usage by kind, run or ref
tine repo storage prune --delete Remove unreachable objects (dry run without --delete)
tine repo archive create repo.tine-archive One compressed file for a whole repository
tine repo storage compress run.tine --decompress Rewrite .tine files plain (or compressed)
tine export <run> --output spans.json.zst --compress zstd
tine repo integrate git install-hook [--global] [--push [--strict]] Add Tine-Run trailers to commits made by recorded runs
tine repo integrate git note <commit> [run...] Record runs on a commit under refs/notes/tine
tine log --commit <sha> | --pr <n> The runs behind a commit or a GitHub PR
tine agent blame src/app.py:42 [--git] Which run, step, model and tool call wrote a line
tine bisect start <bad> <good> [--runs ...|--steps <run>]
tine bisect run --eval "pytest -q" Find the first bad run or step (or --score NAME>=X)
tine share remote add origin https://host/tenant Named remotes; fetch/push/pull accept the name, push --all
tine share pull origin Fetch and fast-forward only
tine repo branch [-d] <name> [run] Branches are heads/* refs
tine tag <name> [run] [-s] Tag a run; -s signs it; tine trust verify-tag <name>
tine repo reflog [ref] / tine repo reset <ref> <run> Every ref move is recorded and recoverable
tine repo config --list / alias.<name> Porcelain settings, aliases and hooks (trust-gated)
tine log --graph --all --oneline The fork tree with model, status and cost
tine rebase <run> --onto-model <model> Fork a run onto another model
tine cherry-pick <run>:<step> --onto <run> Copy one step onto another run
tine fan-out <run> --vary model=a,b -- CMD ... Fork N ways from one step, run them concurrently
tine run --parallel 4 --harness codex --prompt P Run one invocation N times at once (--jobs, --budget)
tine repo worktree add <path> <ref> [--git] An isolated directory per branch; list/remove/prune
tine fleet up fleet.toml --trust Run a declared fleet (fan-out or supervisor/workers)
tine fleet status|stop|cost <id> Members, a stop that kills every process tree, cost
tine fleet record run.tine --sign-key k --out rec.json A run's fleet record, signed (--attest: in-toto fleet/v1)
tine fleet resume|logs|send <id> Resume unfinished members, read output, steer one
tine task add|claim|heartbeat|done|list Leases with fencing tokens (opentine-coord/1)
tine init ~/agent-runs
tine repo integrate hook install --global --repo ~/agent-runs # --dry-run to preview, --agent to narrow
tine repo integrate plugin export ./opentine-plugin --repo ~/agent-runs # a Claude Code plugin directory
claude --plugin-dir ./opentine-plugin
tine record -- python my_agent.py --task "fix the bug"
tine record --save run.tine -- node agent.js
tine record --upstream azure=https://my-resource.openai.azure.com -- python agent.py
tine mcp-proxy --save mcp.tine -- python my_server.py
tine serve --otlp --otlp-port 4318
OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4318 OTEL_EXPORTER_OTLP_PROTOCOL=http/json python my_agent.py
tine rewind 3f9c2a@12
tine rewind 3f9c2a@12 --apply
tine rewind run.tine --json
tine git install-hook --push --repo ~/runs
git push origin main
tine bundle fetch git@host:team/app.git --as origin --repo ~/runs
tine view 3f9c2a -o run.html
tine view run.tine --open
tine verify run.tine --offline --pubkey release.pub --locate --strict
tine verify ./runs --offline --json --report dataset.json
tine evidence export run1.tine run2.tine --out case-42 --pubkey release.pub --sign me.key
tine evidence report run.tine --format html -o report.html # deterministic page
python3 -I docs/conformance/minimal_verifier.py artifact run.tine # no opentine needed
tine export run.tine --format citation --output CITATION.cff # or --format ro-crate
tine media image "a lighthouse at dusk" --out img.png --save run.tine
tine media speech "hello" --out hello.mp3 --save run.tine
tine media transcribe meeting.m4a --save run.tine
tine import <trace> --format otel-json --save run.tine
tine import - --format jsonl --repo . --ref heads/main
tine import agent.log --format langchain --save run.tine
tine import --from-default-location # newest agent-CLI sessions on this machine
tine import latest --from-default-location --save run.tine # import the newest one
tine import <trace> --format otel-json --price --save run.tine # price it from the catalog
tine import trajectory.json --format atif --repo . # Harbor ATIF (v1.0-v1.8)
tine import ~/.local/share/opencode/opencode.db --repo . # OpenCode sessions (read-only)
tine import session.jsonl --fleet --repo . # Claude Code: a run per subagent
tine import trajectory_samples.jsonl --repo . # Hermes Agent (FILE::N picks one)
tine import session.log --adapter NAME --repo . # an allowlisted AdapterSpec
tine repo integrate harnesses --check # check every importer adapter
tine export <run> --format atif --output trajectory.json # ATIF v1.8
tine export <run> --format agent-trace --output trace.json # Agent Trace RFC 0.1
tine export <run> > spans.json
tine export <run> --output spans.json
tine export <run> --endpoint http://127.0.0.1:4318 # local OTLP collector
tine export <run> --endpoint https://collector.example/v1/traces
tine show|verify|ls|search|stats|cost|price ... --json
tine replay <run> --verify --json
tine diff <run_a> <run_b> [--json] [--exit-code]
tine import <trace> [--format FMT] [--save PATH] [--repo PATH] [--price] --json
tine tag <run> [--list] --json
tine pricing list|show|check|update ... --json
tine repo-log|repo-show|repo-diff|repo-search|context ... --json
tine repo-fork|repo-resume|attest|evaluate|promote ... --json
tine pricing list [--provider P] [--model M] [--at YYYY-MM-DD] [--json]
tine pricing show <provider> <model> [--at YYYY-MM-DD] [--json]
tine pricing check [path] [--allow-unsigned] [--json]
tine pricing update <file-or-https-url> [--dest PATH] [--json]
tine init [path] [--bare]
tine repo migrate --to-v3 <run.tine> --repo . --ref heads/main [--allow-unverified] \
[--key-env VAR | --key-file PATH | --pubkey PATH | --trust-embedded-key] [--pin FINGERPRINT]...
tine repo storage fsck --repo . [--shallow]
tine repo-log [ref] --repo . [--limit N] [--json]
tine repo-show <ref-or-run-oid> --repo . [--json]
tine repo-diff <left> <right> --repo . [--exit-code] [--json]
tine repo-search [query] --repo . [--limit N] [--min-score S] [--model M] [--json]
tine context <event-oid> --repo . [--depth N] [--json]
tine repo-fork <ref-or-run-oid> --from-event <oid> --ref REF \
[--model M] [--prompt P] [--policy JSON] [--repo .] [--json]
tine repo-resume <ref-or-run-oid> --ref REF [--repo .] [--json]
tine trust attest <ref-or-run-oid> --signer NAME (--claim JSON | --claim-file PATH) \
[--key-env VAR | --key-file PATH | --ed25519-key-file PATH] [--key-id ID] [--json]
tine trust evaluate <ref-or-run-oid> --evaluator NAME --score NAME=VALUE... \
[--key-env VAR | --key-file PATH | --ed25519-key-file PATH] [--key-id ID] [--json]
tine trust promote <ref-or-run-oid> --name NAME [--expected-old OID] [--json]
tine repo-verify <attestation-oid|ref-or-run-oid> --repo . \
[--key-env VAR | --key-file PATH | --pubkey PATH | --trust-embedded-key] \
[--pin FINGERPRINT]... [--require-signature] [--signer NAME]... [--claim JSON] [--json]
tine object <object-id> --repo . [--resolve-blobs]
tine repo pack --repo . --output run.pack [object-id ...]
tine repo serve --root DIR --cert cert.pem --key key.pem [--insecure-dev] [--writer-promotes]
tine repo serve --root DIR [--tenant T] refs | delete-ref NAME [--expect OID] | associations OID
tine repo serve --root DIR [--tenant T] delete-objects OID... [--from FILE|-] [--dry-run]
tine repo serve --root DIR [--tenant T] purge [--grace-seconds N] [--dry-run]
tine share fetch <remote> --repo . [--tenant T] [--token-file PATH] [--ref R] [--depth N]
tine share push <remote> --repo . [--tenant T] [--token-file PATH] [--ref R] [--remote-ref R]
tine share clone <remote> <path> [--tenant T] [--token-file PATH] [--ref R] [--depth N]