Skip to content

What syncs, and what the cloud can see

Short version: the harness runs the agent on your machine; the relay syncs the agent’s sealed memory as ciphertext; plaintext lives only on your devices. This page spells out each part precisely.

The thing that syncs is the portable encrypted agent log: a harness-agnostic event log of the agent’s memory, conversation history, and identity. It is not a copy of any harness’s native session store; Tally captures sessions into this format at its own layer, which is why sync works the same no matter which harness ran the agent.

The sync unit is a sealed log delta, not a file copy. tally push batches every log entry appended since the last push, seals the batch, and publishes the ciphertext.

From tally push:

  • Each batch is sealed with your seed-derived sync key (AES-256-GCM) before it leaves the machine.
  • What goes over the wire, and what the relay stores, is ciphertext only.

From tally pull on another device:

  • The device back-fills the seat channel from its saved cursor.
  • Each batch is decrypted locally with the same seed-derived sync key.
  • Entries are applied to the local log idempotently, and the hash chain is re-verified after apply.
Terminal window
# device A: publish new local-log deltas to your seat's channel
tally push
# device B: pull the deltas and apply them locally
tally pull

Both commands require a configured relay. The relay can also be configured via the TALLY_RELAY_URL and TALLY_RELAY_JWT environment variables; tally push tells you what to do if the relay is unset.

tally connect is the once-per-seat setup that makes push and pull work. It registers the channel, runs the device-grant, and stores the resulting channel-scoped credential to <tally_home>/relay.json.

Terminal window
# owner key from $SKYTALE_API_KEY (or pass --api-key)
tally connect

Options worth knowing:

  • --api-key <key>: the owner API key; otherwise read from $SKYTALE_API_KEY.
  • --channel <name>: override the channel; the default is the seat’s pronoic/agents/<hex>.
  • --api-url <url>: API base URL; defaults to $SKYTALE_API_URL or https://api.skytale.sh.
  • --relay-url <url>: the per-owner relay URL. The CLI syncs over WsTransport (/ws/<channel> routing), so pass a relay that speaks that, not the gRPC endpoint.
  • --seat <label>: an owner-facing seat label (default cli-seat).
  • --new-account-email <email>: mints a fresh throwaway account first, for testing only; use an undeliverable address such as x@example.invalid.

Note what the credential is: channel-scoped, not account-wide. The seat gets exactly the access it needs to publish and fetch ciphertext on its own channel. And note what it is not: it is a transport credential, not a decryption key. Holding it lets a party move sealed batches; it does not let anyone read them.

The relay is a store-and-forward pipe for opaque ciphertext. Its job is to hold sealed deltas so your other devices can catch up. Think of it like a coordination server, not a data store you read.

What it necessarily sees, because it routes traffic:

  • That a seat published or fetched batches on its channel.
  • The size and timing of those ciphertext batches.

What it cannot see, ever:

  • The content of your log: no messages, no memory, no history, no identity material.
  • Your keys. The sync key is derived from your seed, and the seed never leaves your devices.

This is structural end-to-end encryption: the relay operator (including us) cannot read your data because the design never hands it the keys, not because of a policy promise. It is a property of the architecture, not of anyone’s good behavior. We deliberately do not claim more than that for the relay: it is a zero-knowledge pipe, not attested confidential compute.

  • On your devices: the readable log, encrypted at rest under your keys. This is the only place plaintext exists.
  • On the relay: sealed ciphertext, store-forwarded for catch-up.
  • Nowhere else. There is no plaintext cloud sync store. The encrypted log is the thing that syncs.
  • Each agent’s keys derive from a seed you hold, one per seat: the base seat has its own, and every named agent has its own independent one. tally init generates the base seed silently on your machine; tally backup <agent> is the deliberate ceremony that reveals a seat’s recovery mnemonic.
  • The sync key that seals a seat’s deltas is derived from that seat’s seed. It is never sent to the relay, the directory, or us.
  • Consequence, stated plainly: losing a seed means losing that agent’s data, like a wallet, and the base phrase cannot recover a named agent. Restore-from-seed is the recovery story in the beta. Back up each agent’s seed. See Backup and recovery.

How Tally gets into the loop: two modes, one substrate

Section titled “How Tally gets into the loop: two modes, one substrate”

Sync happens at the Tally layer, not the harness layer. There are two entry points, both sealing into the same log:

tally continue vision --claude-code --fable-5 launches the harness and model for you and captures the session back into the encrypted log on exit. This is the composition path: pick harness and model at launch, resume a named agent anywhere. See Continue, start, and run.

tally sync watches your registered repos’ native harness sessions and syncs them automatically, with no tally command in your workflow once a repo is registered:

Terminal window
# opt a repo in, once
tally sync add <repo>
# run the watch-export-pull-materialize engine in the foreground
tally sync watch
# or run exactly one engine tick
tally sync once
# see registered repos, watermarks, and cursors
tally sync status

Two things to know about transparent mode:

  • It is opt-in per repo. That is the privacy gate: nothing syncs unless you registered the repo. Running your harness raw, with nothing from Tally present, syncs nothing, because there is nothing observing.
  • It is sync, not live co-drive. The engine observes the harness’s persisted session on an interval, so continuity across machines is near-real-time, not keystroke-simultaneous. Resuming the same agent on another machine works; two machines driving the same live session at once is not a thing it does.

Be precise about what the hosted side keeps. The relay does store your pushed ciphertext, persisted server-side; that is what lets an offline device catch up. But the archive is a bounded buffer, not a durable save: entries older than 7 days are purged, and each channel keeps at most a capped number of recent entries. Batches that age out are recoverable only from a device that still holds the local log. So there is no durable cloud save tier in the beta: the relay is catch-up storage, not a managed backup product, and you should not treat it as one. Your durable copies are your devices plus your seed backup. When a durable save tier ships, it will be documented with the same wording discipline used here.

Similarly, every seat in the beta runs on your machines. There is no hosted agent runtime, so there is no case in the beta where your plaintext exists off your devices. The cloud sees ciphertext, full stop.

You do not have to take this page’s word for any of it. The CLI ships the tools to inspect your own seat:

Terminal window
# this seat's identity (DID), agent home, and relay/channel; prints no secrets
tally whoami
# the event count, and whether the local log's hash chain verifies
tally status
# diagnose the local setup: identity, home, harness installs, relay/api reachability
tally doctor
# interact with the local encrypted event log directly
tally log --help

tally doctor prints pass, warn, or fail per check with an actionable fix, and exits non-zero if anything fails. If you want to know what your machine is actually configured to talk to, whoami and doctor answer from the machine itself, not from documentation.

The harness runs the agent; the relay syncs its sealed memory as ciphertext; plaintext lives only on your devices, under keys derived from a seed only you hold.