Docs
Documentation
Everything to go from install to sharing a private key over a relay.
Getting started
A private .env living in a shared repo — the shortest path to seeing the thesis work.
# install (or build with: cargo build --release) curl -sSf https://loot.millerbyte.com/install.sh | sh loot init --identity alice printf 'TOKEN=supersecret\n' > .env printf '# My Project\n' > README.md printf '.env restricted=alice\n*.md public\n' > .lootattributes loot describe -m "initial work" # records the tree AND names the change loot surface # alice restores both README.md and .env
The .env ciphertext lives in .loot/ the whole time. Switch to a non-keyholder and it stays sealed:
printf mallory > .loot/identity rm -f .env README.md loot surface # mallory: README.md appears; .env stays sealed
If mallory snapshots and re-syncs, the sealed file is carried forward untouched — snapshot is visibility-aware, so a non-keyholder can never silently drop or expose content they can't read.
Core concepts
The seven ideas the rest of loot is built from.
Changes
A change is loot's reviewable unit of history — its answer to a commit. There is no separate add/commit step: the working tree is the change at the tip. loot describe -m records it and names it; loot new finalizes and signs it, starting a fresh one. A change carries a set of paths, each with its own visibility — which is where permissions live.
Visibility & .lootattributes
Every path is public, restricted (a named set of key holders), or embargoed (encrypted to all until a reveal time). You declare it in .lootattributes, a gitattributes-style file: .env restricted=alice, *.md public. Unmatched paths default to public. The file is versioned like any other, so the policy travels to every clone.
Identity & keys
An identity is a keyholder — an ed25519 keypair minted at loot init. Visibility is ultimately enforced by who holds the decryption key for a piece of content: "permissioning is key management." Names like alice are local nicknames bound to a globally-stable public key through the peer registry.
Grants
A grant hands one content key to one identity. It's sealed to the recipient's public key (they can't be granted anything they can't unseal), signed by you so the trail is forge-evident, and recorded in an append-only manifest. Grants are how restricted content is shared after the fact — and loot maroon is how access is cut off again.
Relays & hosts
A relay stores and forwards sealed content it cannot read. Restricted keys never travel in a sync bundle, so the relay's zero-knowledge property is enforced at the wire level, not by policy. A host is just a relay that never sleeps — which makes a loot host a zero-knowledge code host: it physically cannot read your private code.
Embargo
An embargoed path is encrypted to everyone until a reveal timestamp. You can merge a security fix, cut the release, and push — the relay holds the ciphertext while withholding the key until reveal_at passes on the relay's own clock. Then anyone who pulls can read it. No lying clock, escrow inspection, or patched binary reads it early: the key bytes simply aren't there yet.
Docks (for concurrency)
A dock is an isolated working tree plus its own tip, materialized cheaply over one shared object store — loot's answer to a git worktree, without a second clone. Docks are the light-touch tool for running several agents or workstreams against one repo; concurrent edits reconcile through the merge classifier, and conflicts surface as machine-readable verdicts rather than being silently dropped.
Task guides
Keep a file private in a shared repo
Declare the path restricted before you record it. Only listed identities get a key; everyone else carries ciphertext.
printf '.env restricted=alice\n' > .lootattributes loot describe -m "add sealed .env" loot push # the relay stores it but cannot read it
Share a private file with a teammate
Register their public key (from loot whoami on their machine), then deliver a sealed grant over the relay.
loot peer add bob "ssh-ed25519 AAAA..." loot grant --relay origin .env bob # on bob's machine: loot pull-grants # verifies alice's signature, checks the peer registry loot surface # now bob can read .env
Embargo a security fix
Mark the file embargoed until a unix timestamp. Push now; the key is withheld by the relay until reveal time.
echo "VULN_DETAILS=CVE-2025-XXXX" > security-fix.txt printf 'security-fix.txt embargoed=1800000000\n' >> .lootattributes loot describe -m "patch for CVE-2025-XXXX" loot push # relay holds ciphertext; key withheld until reveal_at
At reveal_at, the relay releases the key and anyone who pulls can read the fix.
Sync over a relay
A relay is the collaboration hub. Run one anywhere; push and pull resolve origin by default.
# terminal 1: run a relay loot serve --dir /tmp/relay --addr 127.0.0.1:4000 # terminal 2: alice publishes loot remote add origin http://127.0.0.1:4000 loot push # terminal 3: bob clones (sees only public content until granted) loot clone http://127.0.0.1:4000 ./bob-repo --identity bob
CLI reference
The commands that matter, grouped by what you're doing. Every mutating verb snapshots the working tree first — no manual loot status needed. Run loot --help for the full list.
Setup
| loot init [--identity <name>] | Initialize a repo here (identity from global config if omitted). |
| loot clone <url> <dir> [--identity <name>] | Clone a relay into <dir>; ends with a materialized working tree. |
| loot config set|unset|list | Manage global config (~/.config/loot/config) — e.g. a default identity. |
Local
| loot status [--porcelain|--json] | Show the working change, read-only — no snapshot, no ceremony. |
| loot describe -m <message> | Record the working tree and name the change. Your first verb on new edits. |
| loot new [-m <message>] | Finalize (sign) the working change and start a fresh one on top. |
| loot edit <change-id> | Reopen a finalized change to amend it; supersedes it on finalize (ADR 0032). |
| loot log | Show change history with visibility hints; a divergent change is marked !. |
| loot surface | Materialize what the current identity may see; sealed paths are skipped. |
| loot gc [--dry-run] | Prune loose objects no change references. |
| loot verify [--accept-loss] | Integrity-check the object store: rehash every object, name missing ones by referencing change. Exits 1 on problems; --accept-loss records unrecoverable losses so only new damage fails. |
| loot undo · loot op log · loot op restore <n> | Step the view back / list / jump the operation log (redo included). |
| loot abandon <version-id> [--head] | Drop one version of a divergent change, or a whole fork tip; undoable. |
| loot adopt [<version-id>] [--discard-wip] | Catch this working tree up to landed history. |
Docks (concurrency)
| loot dock <name> --at <dir> | Bind a separate worktree over the same shared store — no second clone. |
| loot dock merge <name> | Merge another dock's finalized tip into the current one, in-process. |
| loot docks | List docks with their working tip and visibility. |
| loot lane new / loot lanes | Spawn / observe sealed ephemeral lanes — the isolation unit for concurrent agents. |
Sync
| loot bundle <file> · loot apply <file> | Offline sync: write a sync bundle (ciphertext, no private keys) / merge a peer’s. |
| loot remote add|remove|list | Register named relay URLs (origin is the conventional default). |
| loot push [<url>] · loot pull [<url>] | Publish changes to a relay / fetch, merge, and converge from one. |
| loot serve [--dir <path>] [--addr <host:port>] | Run a relay: stores and forwards ciphertext it cannot read. |
| loot conflicts · loot resolve <path> <file> | List paths needing human resolution / resolve one from a file. |
Grants & visibility
| loot grant <path> <identity> <file> | Write a targeted grant bundle for file delivery. |
| loot grant --relay <name> <path> <identity> | Seal and deliver a content key via the relay’s mailbox. |
| loot grants [<url>] · loot pull-grants [<url>] | Peek the pending grant count / fetch, verify, and apply sealed grants. |
| loot maroon [--hard] <path> <identity> | Cut an identity off future access; --hard also purges the held key. |
| loot migrate <path> <vis-spec> | Change a path’s visibility: public | restricted=a,b | embargoed=<ts>. |
| loot manifest | Show the grant audit trail (grantor/grantee pubkeys, timestamps). |
Identity
| loot keygen · loot whoami | Generate an identity keypair / show this repo’s public key. |
| loot id export <file> · loot id import <file> | Move the same identity between machines (passphrase-encrypted). |
| loot peer add|remove|list | Manage the local nickname → public key registry (loot’s known_hosts). |