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|listManage 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 logShow change history with visibility hints; a divergent change is marked !.
loot surfaceMaterialize 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 docksList docks with their working tip and visibility.
loot lane new / loot lanesSpawn / 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|listRegister 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 manifestShow the grant audit trail (grantor/grantee pubkeys, timestamps).

Identity

loot keygen · loot whoamiGenerate 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|listManage the local nickname → public key registry (loot’s known_hosts).