Offline-first and replicated¶
TOVIO keeps ordinary version-control work local. A repository with the objects and authorized keys needed
for the current checkout can commit, inspect history, switch lanes, resolve conflicts, land changes, and use
undo/redo without contacting a Forge. Synchronization is a separate exchange with another replica or a
Forge; it is not required for every local operation. Once a lane has an upstream, TOVIO also runs that
exchange opportunistically after a history-advancing command — but only as a best-effort side effect:
it is throttled, it skips a busy or dirty repository, and neither its failure nor its absence changes the
outcome or exit code of the command you ran. Turn it off with tovio config set sync.auto off, per
command with --no-sync, or for a session with TOVIO_NO_SYNC.
“Offline-first” does not mean that every checkout contains every object or that every replica has the same authority. Full clones are available, but sparse, partial, shallow, and lazy profiles deliberately keep only a selected graph and may need an authorized promisor to hydrate missing objects. Cryptographic policy, capability scope, protected refs, quota, and repository state can also accept or refuse a remote operation. (File locks are not on that list: the shipped lock refusal is a local one, described below.)
What works locally¶
Within the materialized repository profile, the local engine owns:
- addressed blobs, chunks, trees, commits, changes, and conflict objects;
- lane and tag state already present in the replica;
- the operation log used by
tovio undoandtovio redo; - local identity and recipient keys, sealed through the configured keystore; and
- authorized policy history and wrapped-key material needed to read protected content.
Public content needs no decryption key. A protected object remains ciphertext until an authorized endpoint has both an applicable policy decision and usable recipient key material. A partial checkout cannot pretend a missing object is present, and an expired or revoked authorization is not repaired merely by going offline.
Synchronization and lane reconciliation¶
The object graph is an immutable, content-addressed DAG. Every blob, tree, commit, change, and conflict object is named by the hash of its bytes, and nothing already recorded is overwritten or discarded — synchronization only ever adds objects. That is the foundation everything below rests on: a synced commit is reachable from some ref or it is not, but it is never quietly lost.
When a tovio sync or tovio pull you ran brings a divergent incoming tip on your unprotected
current lane — the local tip and the incoming tip are concurrent, with neither an ancestor of the other —
TOVIO reconciles the two on the lane instead of picking a pointer winner and stranding the loser
(ADR-0288):
- It computes the DAG merge-base of the local and incoming tips and runs the same typed three-way merge
engine that
tovio landuses. - If the two sides merge cleanly, the lane advances to a two-parent merge commit.
- If they don't, the lane advances to a two-parent commit that carries first-class conflict objects — legal, operational repository state you resolve when ready.
Either way parents = [local_tip, incoming_tip], so both diverged tips are parents of the new lane tip:
reachable from the lane, never off in the ether. A divergence becomes an ordinary merge-or-conflict commit on
the lane; content is never stranded. (Fast-forward and already-up-to-date syncs skip all of this — there is
nothing to reconcile.)
Selecting the merged tip does not silently land the other change, prove that it passed policy, or authorize it
for a protected ref. Protected / require_review lanes are carved out entirely: they advance only through
the proposal / land path, never by reconcile-on-sync.
The background auto-sync described above does not reconcile. An unattended pull must never materialize a
conflict behind your back, so it keeps the plain pointer merge and isolates the affected paths instead. A
divergence it settles therefore ends as a pointer winner with the losing tip off the lane — still recorded in
the object graph and in your operation log, but not a parent of the new lane tip. Reconciliation is a
foreground behavior: tovio sync and tovio pull are what build the two-parent commit.
tovio sync combines send and receive in one user workflow, but a particular exchange can still fail or be
refused. Examples include an invalid signature, missing object closure, insufficient capability or path
scope, a protected-ref requirement, quota denial, stale repository state, or unavailable transport. A
divergent edit on an exclusive-lockable path is refused too, but by your own client rather than by the
peer: two sides that edited such a path apart cannot be merged into a content conflict without losing a
write, so the edits have to be serialized through a lock instead. The local work remains addressed so the
operator can correct the condition and retry.
Mechanism: the Hybrid Logical Clock and the ref register¶
On-lane reconciliation is the outcome; the machinery that propagates it is a Last-Writer-Wins CRDT register keyed on a Hybrid Logical Clock (HLC). This layer governs the lane pointer only — which commit each ref names — never the content it points at.
An HLC timestamp combines physical time, a logical counter, and actor identity. The logical component preserves causal ordering when wall clocks are skewed or multiple events occur at the same physical time; the actor tie-break keeps concurrent values deterministic. The register gives replicas offline convergence and liveness: peers that receive the same valid updates settle on the same pointer.
What changed with on-lane reconciliation is what the register carries after a foreground sync resolves a divergence. Instead of a bare winner with a stranded loser, it carries the reconciliation commit, which bears a fresh dominating HLC and so dominates the concurrent tips it reconciled. LWW propagates that reconciliation rather than being what resolves the divergence — though where no reconciliation was built (a background auto-sync, a protected lane) plain LWW is still what settles the pointer. The HLC is an ordering mechanism, not proof that a client clock or actor is trusted; signatures, authorization, replay checks, and server-derived targets remain separate gates.
Local and Forge boundaries¶
| Client or local replica | Forge or other synchronization peer |
|---|---|
| Materialized objects and refs for the selected full/sparse/partial/shallow profile | Objects and refs admitted by its repository, routing, retention, and authorization policy |
| Local operation log, checkout state, and conflict work | Proposals, reviews, locks, webhooks, audit, coordination, and hosted administration state |
| Sealed identity and recipient keys used by that endpoint | TLS/service credentials and, when enabled, separately governed Key Authority or provider credentials |
| Plaintext materialized for authorized local use | Protected payload ciphertext by default; public content and operational metadata remain visible |
The Forge is optional for the local engine, but it is authoritative for the collaboration and hosted-service state it owns. It can accept or reject writes, affect availability, observe public content and metadata, and serve content to explicitly authorized runners, agents, or users. Merely hosting a protected object does not give the Forge a recipient private key or unwrapped data key; that narrower confidentiality boundary is described in The Forge and trust.
Partial and lazy profiles¶
Sparse paths limit the requested tree scope. Shallow history limits ancestry. Partial and lazy modes defer object transfer until a later authorized read or prefetch. The local mode marker prevents a non-secret runner profile from silently falling back to a human credential. A checkout that cannot authenticate its promisor or verify returned bytes fails closed instead of substituting mock or unverified content.
Current implementation boundary¶
The offline core, HLC/CRDT lane model, typed conflicts, native and HTTP-framed synchronization, and full/sparse/partial/shallow/lazy transfer profiles are implemented under their documented supported configurations. Distributed sharding, replicated mutation edges, hosted parity, and release packaging have substantial bounded implementations, but their remaining multi-host, physical-failure, cross-platform, load, and independent evidence is still open. See the product roadmap for the curated availability statement.
Where to go next¶
- The Forge and trust — the server's exact confidentiality and authority boundary.
- Conflicts as data — how incompatible content remains explicit.
- Coming from Git — mapping familiar workflows to lanes and changes.
- Clone and sync — supported transfer profiles and commands.
Last reviewed September 9, 2026
Suggest an improvement to this page Not for security reports — see disclosure