Skip to content

Clone from a Forge or peer, then sync

This guide gets a repository onto your machine and keeps it in step with everyone else. The headline: tovio sync does push and pull in one command, and when your history and a teammate's have diverged, tovio sync reconciles the two on the lane — a clean merge, or a tracked conflict — deterministically and without a force-push, so neither side's work is ever left off-lane. An exchange can still be refused by authorization, protected-ref, quota, object-closure, state, or transport gates.

Networked clone and sync are built

Networked clone and tovio sync (push and pull over native TLS and HTTP-framed sync, sparse path-scope, N-replica CRDT convergence) are built and tested, and opportunistic auto-sync is on by default. Production binaries passed the distinct-Docker-host exercise under a real operator CA. Public-release, broader HA/load, hosted parity, and external evidence remain Phase 5 gates.

flowchart LR
    C["tovio clone"] --> R[("local repo")]
    R -. "tovio sync" .-> F(("Forge / peers"))
    F -. "diverged tips reconcile on-lane" .-> R

More diagrams for the full team collaboration flow: Team workflows.

Clone a repository

tovio clone takes three things: the relay, the repository id, and the directory to create. The relay is either a hosted Forge (https://host, trusted through public PKI) or a native relay (host:port, the address tovio serve prints — port 7743 by default), which needs the relay's pinned certificate.

$ tovio clone https://forge.example.dev <repo-id> repo
✓ Cloned 1204 objects from https://forge.example.dev into repo
$ tovio clone forge.example.dev:7743 <repo-id> repo --cert relay-cert.der

A clone with no filter flags is complete: full history, every object, fully usable offline. Three composable axes narrow it — which subtree (--sparse "src/**", repeatable), how much history (--depth 50), and which content (--blobless, or --blob-limit <bytes> to skip only large files):

$ tovio clone https://forge.example.dev <repo-id> repo --sparse "src/**" --depth 50

Any filtered clone is promisor-backed: the objects it omitted are not lost — a read of one backfills lazily from the origin, re-hashed on arrival. tovio fetch --deepen <n> extends a shallow history and tovio fetch --complete fattens the repository back to a complete, offline-sovereign closure.

Missing decryption clearance does not by itself block an authorized clone

Policy-protected files arrive as ciphertext and are decrypted on access only if your identity's attributes satisfy their policy. You can clone a repository in full and still be unable to read the protected payloads in it. If repository discovery and transfer are otherwise authorized, lacking a usable recipient key leaves those paths encrypted rather than granting plaintext. Repository authorization, object disclosure, quota, closure verification, and transport can still refuse the clone. To learn what's gating a file you can't read, use tovio access check.

Sync your work

tovio sync is the everyday command for sharing and receiving changes. With no arguments it uses the origin saved when you cloned; it is built for both humans and always-on agents.

$ tovio sync
✓ Synced with forge.example.dev:7743 (received 4 object(s), sent 1; 2 ref(s) merged)

That single line is push and pull together: it sent your local objects and received four, and it merged the lane refs. You don't run push then pull — sync is the native verb.

One direction only

If you genuinely want just one direction, restrict it:

$ tovio sync --pull      # receive only
$ tovio sync --push      # send only

A one-way --push won't clobber a diverged remote

tovio sync --push skips the pull, so it can't reconcile. If the remote lane has moved on and diverged from your tip, the push is refused (TVO-SYNC-006, "Push refused: the remote lane has diverged from your local tip") before anything is uploaded, rather than orphaning the remote tip — run a full tovio sync to reconcile on-lane first, then the push fast-forwards.

Coming from Git

tovio push and tovio pull are the one-direction primitives behind sync, kept for Git muscle memory. Typed bare, they print a hint for migrants; with a relay and repository id they push or pull. The native equivalent of both is just tovio sync — one command, both directions.

Auto-sync keeps you current between syncs

You will run tovio sync less often than you expect, because opportunistic auto-sync is on by default. After a history- or lane-advancing command succeeds — commit, land, switch, tag, cherry-pick, revert, rebase — TOVIO runs one throttled sync (at most once per sync.auto.interval seconds, default 120). It is deliberately conservative:

  • It always pulls, but never materializes over a dirty working copy — with uncommitted edits it skips the round rather than risk them.
  • It keeps your lane current with its upstream (the lane it will land onto, defaulting to the lane you branched from; tovio autosync upstream --set <lane> retargets it) by folding the upstream in only when that merge is conflict-free; a merge that would conflict is left for a deliberate tovio land. A protected lane is never auto-advanced, and this fold runs only on a complete checkout — a sparse or partial clone integrates its upstream through an explicit tovio land.
  • Push is consent-gated. The default sync.auto.push = shared pushes only the current lane, and only after you have published that lane once yourself — your first manual tovio sync is the act of consent. Protected lanes are never auto-pushed.
  • It is never fatal and never noisy: an offline or locked repository is a silent skip, and the primary command's exit code and --json output are untouched.

Turn it off for one command with the global --no-sync flag, for a shell with TOVIO_NO_SYNC, or for the repository with tovio config set sync.auto off. To stay current while idle, run the continuous companion in a spare terminal:

$ tovio sync --watch
✓ watching origin — syncing every 120s (Ctrl-C to stop)
✓ auto-synced with origin (↓ 5 object(s), merged upstream)

--interval <secs> overrides the poll interval and --once runs a single poll for scripts.

Divergence reconciles on the lane

This is the part that feels different from Git. When you and a teammate both advanced the same unprotected lane offline, an interactive tovio sync doesn't reject your push or pick a winner and strand the other tip — it reconciles the two on the lane. It runs the same merge engine tovio land uses: if the two sides merge cleanly, the lane advances to a two-parent merge commit; if they can't, the lane advances to a two-parent commit that carries the conflict as data. Either way both tips become parents, so neither line of work is ever left off-lane. There's no diverged-history error and no force-push.

$ tovio sync
✓ Synced with forge.example.dev:7743 (received 1 object(s), sent 1; 1 ref(s) merged)
  ✓ reconciled divergent lane `main` on-lane (clean merge, blake3:7yq2…)

If the two sides touched the same lines, the reconciliation carries the conflict — on the lane, as data:

$ tovio sync
✓ Synced with forge.example.dev:7743 (received 1 object(s), sent 1; 1 ref(s) merged)
  🔒 reconciled divergent lane `main` on-lane with 1 conflict(s) to resolve (blake3:7yq2…)
    conflict src/integrations/auth/oauth.ts

Run tovio conflicts to see it and tovio resolve to settle it. Only an interactive tovio sync or tovio pull builds this reconciliation commit; background auto-sync adopts refs and isolates, and leaves a genuine divergence for your next manual sync.

Read this as relief, not a warning

In Git, "your branch and the remote have diverged" is the start of a stressful afternoon. In TOVIO it's a status line: your work and theirs are combined into one commit on the lane, or held together as a tracked conflict — never a silently dropped tip. The reconciliation commit has a deterministic identity, so if a teammate reconciles the same divergence independently they land the byte-identical commit and everyone converges — no merge-of-merges. Authorization and protected-lane requirements still apply, and require_review lanes reconcile through their proposal/review path rather than auto-reconciling here.

When a teammate's change still has conflicts

Conflicts are data in TOVIO, so a reachable conflict object transfers like any other addressed object. But sync will not drop someone else's unresolved conflict markers into your working tree if your change builds on top of theirs. That would break your build, so the materialize step is gated (TVO-CONFLICT-004) — the objects still download; only the materialization is refused.

$ tovio sync
✗ Cannot pull chg:002 as a dependency: 1 unresolved conflict(s)

  Change chg:002 has 1 unresolved conflict object(s); materializing it into the working tree as a
  dependency you build on top of would break the build. The objects still downloaded — only the
  materialization is refused.
    ~ src/integrations/auth/oauth.ts

  Notify the author:
    tovio change notify chg:002
  Build against the last-known-clean version:
    tovio materialize --isolate
  List the conflicted paths:
    tovio status --conflicts

  [TVO-CONFLICT-004]

You have two clean choices:

  • Wait for Bob to resolve. tovio change notify chg:002 records a local, never-synced notify intent for the change; tovio change watch chg:002 --remote <forge> polls the Forge's event feed and returns when the change resolves or lands.
  • Isolate. tovio sync --isolate (or, with the objects already downloaded, tovio materialize --isolate) materializes the conflicted paths at their last-known-clean version so your tree builds, and pins them so tovio status flags the isolated build. The conflict stays flagged, and the pinned path re-materializes on its own the next time a sync transfers Bob's resolution — no command to run.

A conflict in your own stack never blocks you. This gate is only the boundary where a teammate's unresolved conflict would land in your build.

If the relay is unreachable

A relay you can't reach is reported, never destructive. The transport fails before any ref or working-copy mutation, so your local work is untouched and your next sync picks up where this one left off.

$ tovio sync
✗ Sync failed: connection refused

  The connection, TLS handshake, or object transfer did not complete.

  Check the address, that `tovio serve` is running, and that the relay cert matches (--cert)

  [TVO-SYNC-003]

Recap

  • tovio clone <relay> <repo-id> <dir> — complete by default; --sparse, --depth, --blobless / --blob-limit narrow it into a promisor-backed clone that backfills on read. Protected files arrive encrypted and stay that way without clearance.
  • tovio sync — push and pull in one; a divergence reconciles on the lane into a merge-or-conflict commit, so there's no "diverged", no "rejected", and no off-lane orphan.
  • Auto-sync is on by default: pull after every advancing command, conflict-free-only upstream integration, consent-gated push; --no-sync / TOVIO_NO_SYNC / sync.auto off turn it off; tovio sync --watch keeps syncing while idle.
  • tovio sync --push / --pull — one direction when you want it.
  • tovio sync --isolate — build past a teammate's unresolved conflict at the last clean version.

Where to next

Last reviewed September 9, 2026

Suggest an improvement to this page Not for security reports — see disclosure