tomo docs
home github

Command reference

Every command Tomo exposes. All informational commands take --json for scripting. Human output is colored on a terminal and plain when piped.

Jump to: init · sync · connect · status · log · diff · restore · conflicts · ignore · attach · stop · logs · events · db · update · bug · completions · dev

tomo init #

Optional. tomo sync <host:/path>, tomo sync --local-peer <path>, and tomo connect <host:/path> all initialize the project automatically on first use, so you rarely need init directly. Run it explicitly to pre-configure a project, or to initialize a directory (like your $HOME) that auto-init deliberately refuses.

Initialize a Tomo project in the current directory (create .tomo/). Writes a commented starter config.toml and a stable replica id, and adds .tomo/ to .gitignore if the folder is a git repo. Idempotent: re-running on an existing project changes nothing.

tomo init
$ tomo init
initialized Tomo project in /home/you/proj/.tomo

tomo sync #

Sync this project with a peer — the primary command. Name the peer as a single rsync-style target (user@host:/remote/path, also host:~/path for the remote home). It records the peer if new and starts syncing over SSH in one step — the session's own bootstrap and handshake are the validation. An identical already-recorded peer just runs; a different target simply switches the recorded peer — a loud one-line notice (⇄ peer changed: was … · now …) prints before reconnecting. With no target it runs against the recorded [remote], or --local-peer <path> for a local directory, or watch-only if neither is configured.

Auto-initializes. Given a target or --local-peer in a directory that is not yet a Tomo project, sync initializes it in place (creating .tomo/, printing a one-line initialized .tomo/ (private)) and continues seamlessly — no separate tomo init needed. As a safety net it refuses to auto-initialize your entire home directory or a filesystem root (cd into a project first, or run tomo init there explicitly if you truly mean it). A bare tomo sync in an uninitialized directory — nothing to resume — still errors and points you at the one-command form.

On a real terminal, tomo sync runs the session in the background and attaches the interactive TUI — the live stream plus a status heartbeat, with the conflict center one keypress away (c). q stops the session (with a confirm), d detaches and leaves it syncing. Pipes, scripts, --json, and --plain get the classic line stream, byte-for-byte.

tomo sync [OPTIONS] [TARGET]
[TARGET]
The peer as a single user@host:/remote/path target (also host:~/path for the remote home). Omit to resume the recorded peer.
--local-peer <PATH>
Sync with a local project directory instead of over SSH (spawns a served peer rooted there). Mutually exclusive with a <target>.
--json
Emit machine-readable JSON event lines.
-d, --detach
Start the session in the background and return (prints the pid and how to attach).
--plain
Classic line stream instead of the TUI (pipes and --json always stream).

Examples

$ tomo sync you@gpu-box:~/proj        # first run: record + bootstrap + sync (TUI on a terminal)
$ tomo sync                            # reuse the recorded peer
$ tomo sync --local-peer ../mirror     # mirror to a local dir (no SSH)
$ tomo sync dev@gpu-box:~/proj
initialized .tomo/ (private)
recorded remote dev@gpu-box:~/proj
connecting to dev@gpu-box over SSH
pushed remote binary tomo 0.2.0 (x86_64-unknown-linux-musl, 48234112 bytes)
✓ peer connected
✓ synced src/main.rs
✓ synced target/release/proj

tomo connect #

Record a sync peer for this project and validate the connection — without starting a session. It records the [remote], bootstraps the remote binary, exchanges the handshake, and exits. A one-shot health check. tomo sync does this automatically as it starts a session, so you rarely need connect directly. Idempotent: re-running with the same target revalidates instead of erroring; a different target simply switches the recorded peer (a loud one-line notice prints before revalidating against the new target).

tomo connect [OPTIONS] <TARGET>
<TARGET>
The peer as a single user@host:/remote/path target (also host:~/path for the remote home).
--identity <PATH>
Explicit SSH private-key path, recorded in the [remote] so later sessions reuse it. Tried before ssh-agent, ~/.ssh/config, and the default id_ed25519/id_rsa. Use when your key is neither in the agent nor a default name nor selectable via ~/.ssh/config.

Examples

$ tomo connect you@gpu-box:~/proj
$ tomo connect you@gpu-box:~/proj --identity ~/.ssh/gpu_ed25519

tomo status #

Show sync status for this project: index root hash, file and tombstone counts, the conflict badge, peer connection state, and history mode. Safe to run alongside a live session.

tomo status [OPTIONS] (alias: tomo s)
--json
Emit the machine-readable status JSON.

Examples

$ tomo status
root       af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262
files      128
tombstones 3
conflicts  0
peer       offline
history    adaptive (412 versions)
$ tomo status --json
{
  "root": "af1349b9…f3262",
  "files": 128,
  "tombstones": 3,
  "conflicts": 0,
  "conflicts_unresolved": 0,
  "connected": false,
  "reconciling": false,
  "history": { "mode": "adaptive", "versions_recorded": 412, "rung": 0, "staged": 0 },
  "updated_unix_ms": 1784585581996
}

tomo log #

Show version history, newest first. With a <path>, shows that path's full history. With no path, shows recent activity across all paths (the 20 newest versions by default; raise it with --limit).

tomo log [OPTIONS] [PATH]
[PATH]
The path whose history to show (repo-relative or absolute). Omit for repo-wide recent activity.
--json
Emit machine-readable JSON.
--limit <N>
Show at most this many versions (newest first). Repo-wide log defaults to 20.

Examples

$ tomo log src/main.rs
history of src/main.rs (newest first):
  #3   present   1.2 kB   replica 332f855c   local    2s ago  (2026-07-20 22:13:26Z)
  #2   present   1.1 kB   replica a91be004   remote   5m ago  (2026-07-20 22:08:11Z)
  #1   present   0.9 kB   replica 332f855c   local    9m ago  (2026-07-20 22:04:02Z)
$ tomo log                     # repo-wide recent activity
$ tomo log src/main.rs --json  # machine-readable, ids from "id"

The JSON is an array of version objects, each with id, present, tombstone, size, exec, content_hash, replica, origin, wall_unix_ms, and the vector clock. The id is what you pass to diff and restore.

tomo diff #

Show a textual diff of a path between recorded versions and/or the working tree. By default diffs the newest recorded version against the current working-tree file. Exit 0 when identical (or binary/oversized, declined), exit 1 when they differ — git-style.

tomo diff [OPTIONS] <PATH>
<PATH>
The path to diff (repo-relative or absolute).
--version <VERSION>
The recorded version id to use as the base (left) side. Defaults to the newest recorded version.
--against <AGAINST>
A recorded version id to use as the target (right) side instead of the working-tree file. So --version A --against B diffs two recorded versions.
--json
Emit machine-readable JSON.

Examples

$ tomo diff note.txt --version 1 --against 2
diff note.txt: version #1 → version #2 (- base / + target):
  hello
+ there
  world
$ tomo diff src/main.rs                  # newest recorded vs working tree
$ tomo diff src/main.rs --version 5      # version 5 vs working tree

tomo restore #

Restore a path to a previous version. With no --version, restores the version before the current newest — the common "undo my last save". The write goes through staging + atomic rename; if a session is running, the restored bytes then sync to the peer as an ordinary local change.

tomo restore [OPTIONS] <PATH>
<PATH>
The path to restore (repo-relative or absolute).
--version <VERSION>
The exact version id to restore (an id from tomo log). Defaults to the version before the current newest.
--stdout
Write the restored bytes to stdout instead of the file on disk — useful for inspecting or piping an old version without overwriting your working copy.

Examples

$ tomo restore src/main.rs               # undo the last save
$ tomo restore src/main.rs --version 2   # restore an exact version
$ tomo restore src/main.rs --version 2 --stdout | less
$ tomo restore src/main.rs --version 2
restored src/main.rs to version #2 (1.1 kB)

tomo conflicts #

List, inspect, or resolve conflicts. Conflicts are resolved automatically and never block sync (last-writer-wins); the loser is always preserved in history. These commands surface that record non-blockingly and let you recover a losing version. With no subcommand, lists the unresolved conflicts.

tomo conflicts [list | show <ID-OR-PATH> | resolve [ID-OR-PATH]]

conflicts list

--all
Include already-acknowledged conflicts, not just unresolved ones.
--json
Emit machine-readable JSON.
$ tomo conflicts list
unresolved conflicts:
  #7  src/config.rs   local ✓ winner  ·  remote preserved   2m ago
  #6  README.md       remote ✓ winner ·  local preserved     8m ago

A clean tree reports no unresolved conflicts 🎉.

conflicts show <ID-OR-PATH>

<ID-OR-PATH>
The conflict id (from tomo conflicts list), or a project-relative path — which shows that path's newest unresolved conflict.
--json
Emit machine-readable JSON.

Shows one conflict in detail, including a diff of the two heads and their vector clocks — so you can see exactly what the losing side would have written.

$ tomo conflicts show 7
$ tomo conflicts show src/main.rs

conflicts resolve [ID-OR-PATH]

[ID-OR-PATH]
The conflict id to resolve, or a project-relative path — which targets that path's newest unresolved conflict. Omit only with --all or --interactive.
--keep-current
Keep the current file and mark the conflict acknowledged (the tree is left untouched).
--take-loser
Replace the current file with the preserved losing version, then mark it resolved. A running session syncs it as a normal local edit.
--both
Keep both: materialize the preserved loser alongside the winner as <path>.theirs for a manual merge, then acknowledge. The sidecar syncs like any file.
--all
Mass-acknowledge every unresolved conflict (only with --keep-current semantics; not valid with --take-loser/--both).
--interactive
Walk every unresolved conflict one at a time — show its diff, prompt keep/take/both/skip. A terminal-based fallback for the conflict center.
$ tomo conflicts resolve 7 --keep-current
$ tomo conflicts resolve src/main.rs --take-loser
$ tomo conflicts resolve 7 --both
$ tomo conflicts resolve --all --keep-current
$ tomo conflicts resolve --interactive

tomo ignore #

Add an ignore rule to .tomo/config.toml, or — with no argument — list the effective ignore rules. Adding a rule appends to the config; your existing comments and formatting are kept byte-for-byte (it never parses and rewrites the file), and the write goes through the same crash-safe staging + atomic-rename path as every other Tomo write.

A bare directory name (no glob metacharacters and no /; a trailing / is stripped) expands to the same two rules the built-in defaults use — <name> and <name>/** — so both the directory and everything under it are ignored (per-path enforcement needs both). A pattern with glob characters or a slash is added verbatim as a single rule (power-user mode). Invalid globs are rejected writing nothing, and a pattern targeting .tomo (always ignored) writes nothing. Because config is read at session startup, adding a rule while a session runs prints a restart hint — restart with tomo stop && tomo sync.

tomo ignore [PATTERN] [--json]
[PATTERN]
The path or glob to ignore. Omit to list the effective ignore rules (built-in defaults marked (default), then your rules).
--json
Emit machine-readable JSON.

Examples

$ tomo ignore node_modules             # bare name → node_modules + node_modules/**
$ tomo ignore 'build/**'               # glob → added verbatim, one rule
$ tomo ignore                          # list the effective ignore rules
$ tomo ignore node_modules
✓ added ignore rule `node_modules` (+ `node_modules/**` for its contents)

tomo attach #

Join the running session from any terminal — the TUI by default, --plain for the line stream, --json for raw event records. Detaching (q/d/Ctrl-C) never disturbs the session. Multiple terminals can attach at once.

tomo attach [--plain|--json] (alias: tomo a)

tomo stop #

Cleanly stop the running session (idempotent — a second stop is a friendly no-op). Falls back to SIGTERM if the control socket is unresponsive.

tomo stop

tomo logs #

Tail the session log (.tomo/logs/session.log) — the detached session's stream. -f follows.

tomo logs [-f] [-n N]

tomo events #

Stream the running session's control-channel event feed — human lines by default, versioned JSON records with --json (connect/disconnect, synced, conflict with id, transfer progress, heartbeat). The scriptable twin of the TUI: everything the TUI shows rides this same feed.

tomo events [--json]

tomo db check #

Inspect the history database. db check verifies the integrity of the history store — every recorded version's chunks are present and re-hash to their expected BLAKE3 ids. Exit 0 when healthy, 1 on problems found.

tomo db check [OPTIONS]
--json
Emit machine-readable JSON.
$ tomo db check
history OK: 412 versions, 1043 chunks verified

tomo update #

Update Tomo to the latest release, in place. It mirrors the installer: it detects this platform's release asset, fetches the release SHA256SUMS, and compares the published hash of that asset against the SHA-256 of the running binary — a content check, never a version-number compare. If they differ it downloads the asset, verifies its checksum (a mismatch aborts with nothing replaced), and atomically swaps it over the running executable. upgrade is an accepted alias.

tomo update [--check]
--check
Report whether an update is available (with short content hashes and, best-effort, the latest tag) without installing it.
$ tomo update --check
update available
  current  fe1f4be3d62c
  latest   ac5b3bf59ce0
$ tomo update
updated tomo 0.1.6 -> 0.2.0

Running sessions keep the old version until restarted; the remote peer auto-updates at the next connect (the bootstrap re-pushes on any version skew). The download base defaults to the GitHub latest-release URL and is overridable via TOMO_UPDATE_BASE (the test hook). If the binary lives somewhere you can't write, update says so and points you back at the installer.

tomo bug #

File a bug report against Tomo's issue tracker (github.com/jakequist/tomo). With no arguments it opens the blank new-issue page in your browser. With a -m message (title optional — derived from the message's first line when you omit -t) it files the report: through the gh CLI when one is installed and authenticated (printing the issue URL it returns), otherwise by opening a prefilled issues/new URL. A -t title alone prefills a title-only URL.

Only the tool version and target platform are attached — a small tomo <version> · <triple> footer — never logs, paths, or environment. When you're reporting a sync problem, pasting the output of tomo logs -n 50 into the issue body helps a lot. On a headless server with no browser (or with --print), the URL is printed on stdout with a one-line prompt — copy it anywhere to file the issue. Works anywhere; no initialized project required.

tomo bug [-t <title>] [-m <message>] [--print]
-t, --title <TITLE>
The issue title. Derived from the message's first line (truncated to 72 chars) when omitted.
-m, --message <MESSAGE>
The issue body. Its presence is what triggers filing, rather than just opening the blank page.
--print
Print the URL instead of opening a browser (the script-friendly fallback; handy on headless servers).
$ tomo bug -t "sync stalls on large files" -m "repro: 2 GB file, both sides idle after 40%"
https://github.com/jakequist/tomo/issues/128
$ tomo bug --print                     # headless: print the new-issue URL
open this to file the issue:
https://github.com/jakequist/tomo/issues/new

tomo completions <SHELL> #

Print a shell completion script to stdout. Generate for your shell and source it. Safe to pipe: output stops cleanly on a closed reader. Supported shells: bash, elvish, fish, powershell, zsh.

tomo completions <SHELL>
$ tomo completions bash > ~/.local/share/bash-completion/completions/tomo
$ tomo completions zsh > "${fpath[1]}/_tomo"

tomo dev <…> — diagnostics #

Hidden developer/diagnostic commands, not part of the stable surface. Two are worth knowing:

tomo dev ssh-route <TARGET>
Resolve an SSH target through ~/.ssh/config and print the route Tomo would take — the direct analogue of ssh -G <target>, for diffing. Per hop: alias, resolved hostname/port/user, identity files, StrictHostKeyChecking, the known-hosts files consulted, and the ProxyJump chain. Pure resolution, no network. Takes --json.
tomo dev embedded-binaries
List the release binaries embedded into this build's bootstrap payload. Empty in ordinary dev builds; populated only in a fat release build. Used to verify a fat binary's embedded inventory. Takes --json.

See Configuration → Troubleshooting for when to reach for ssh-route.