Known issues

What can cost you your work

loot is a public alpha, and this is the page that says so with specifics. Everything below is a way loot can lose, strand or silently drop work you have already done. It is written from our own testing against the shipping binary, and it is deliberately unflattering — a Known Issues page that flatters is worth nothing.

Last reviewed , against loot v0.4.24.

What is not on this page. This one is about what costs you your work. Who can read your work is a separate question with a page of its own — every reader, every tier, and the two cells where the plain answer misleads are on the trust matrix. Neither page restates the other, so read both.

Lose the key and the content is gone

Your identity is a file inside your repo. There is no copy of it anywhere else, and there is no reset link.

An identity is the ed25519 keypair at .loot/id, minted by loot init and living inside the repo it belongs to. There is no machine-level keystore — the identity entry in your global config is a name, a label, not key material. Everything in .loot/objects/ is ciphertext sealed to that key. Delete .loot/, or lose the disk, and the content is unopenable: by you, by us, by anyone. That is the design working rather than failing, which is exactly why the backup below matters more than it looks.

The recovery phrase is a backup you take in advance, not a door you can open afterwards. loot id recover reads a 24-word phrase and rebuilds precisely the keypair it encodes, and since v0.4.19 loot id phrase prints those words for the identity you already have. ⚠ Both open the repo first. There is no route from a lost .loot/ back to a phrase — the words come out of the key, not the other way round — so a phrase you have not written down before the disk dies is a phrase you will never see. Run loot id phrase the day you run loot init. It prints to a terminal only and refuses a pipe, a redirect or a captured subprocess, with no override: those 24 words are the private key, so read them off the screen. (The phrase the browser account onboarding on this site shows you is a different, browser-minted identity, not the one in your repo.)

The backup that does exist is loot id export. It writes the keypair to a file, passphrase-encrypted, and loot id import reads it back on another machine. Run it immediately after loot init and keep the file somewhere that is not the repo. It is the only thing standing between a lost .loot/ and lost content.

Custody at rest, and where the remedy bites

A passphrase is offered, not required. If you did not deliberately type one, your keys are in the clear on this disk.

loot init offers a custody passphrase. Take it and .loot/id is encrypted and the content keys in .loot/keyring and .loot/escrow become envelopes only your own key opens. Decline it — or run loot init from a script, a CI job or an agent, where there is no terminal and so no prompt is ever shown — and every one of those stays plaintext at rest. loot id lock sets a passphrase on a repo that already exists. What a plaintext keyring exposes, and to whom, is on the trust matrix; what follows is what the passphrase itself can cost you.

There is no recovery from a lost passphrase. Nothing in loot opens a repo whose .loot/id is encrypted under a passphrase nobody has. The loot id export backup above is the answer here too — and it is the same single file, so if you only do one thing on this page, do that one.

A locked repo opens nothing, and stops there. Every verb that reads content refuses with the same message and points at the environment variable or loot unlock — status, log, diff, grep, surface, whoami, describe and push among them. So on a locked machine you can see nothing and record nothing until you unlock. loot unlock and loot lock do still run: they open no repo at all, which is what keeps the remedy reachable.

Taking delivery is the one exception. loot pull against a relay runs while locked, because filing the keys that arrive needs only your public key — they are stored sealed and open the next time you unlock. A pull against a forge refuses by name instead: a forge authenticates every request with your identity key, and a locked repo cannot produce it. A wrong LOOT_PASSPHRASE does not stop the relay pull either — it is reported on stderr and ignored, because that pull never needed one.

A locked pull is a quarter of a pull. loot pull normally fetches, merges, converges and surfaces. While locked it only fetches and files keys — it does not fold diverged heads and does not write your working tree — and it prints exactly that, on stderr as well when you asked for --porcelain or --json. Afterwards run loot unlock, then loot rehome to materialize what arrived, and then loot converge to fold the heads. Reach for rehome rather than surface: both refuse over edits no change recorded — exactly what a locked repo could not capture — but only rehome's refusal says what recording them would do, and it refuses only over bytes that really are yours. The copy a locked pull left behind is not one of them: since v0.4.21 the ingest writes down the claim it could not check and the first unlocked open checks it, so rehome materializes what arrived instead of refusing over your own stale copy.

The unlock session file is a credential. loot unlock writes a session file under your config directory, outside .loot/. The file it writes in v0.4.24 holds a secret derived from your key and sealed under .loot/id's own ciphertext, so the file alone opens nothing and yields no passphrase. It is still not nothing: it discloses that this identity is unlocked on this machine, and beside a copy of your .loot/ it is full custody with nothing to guess.

A session file written by a loot older than v0.4.17 holds the passphrase itself, hex-encoded. Anyone who could read that file had the passphrase, including anywhere else you used it. loot refuses such a file rather than honouring it, and says so: loot unlock replaces one, loot lock removes it. ⚠ You are only told when loot actually reads the session — if LOOT_PASSPHRASE is exported and working, the old file sits in your config directory and nothing ever mentions it. If you unlocked on an earlier release, run loot lock once, and treat that passphrase as exposed if this config directory is synced or backed up. Do not sync your config directory, and do not reuse a passphrase you use anywhere else.

Nothing here is a boundary against someone on this machine. The machine name in the file is a label loot honours, not a cryptographic wrap, so a copied session is inert to loot rather than protected by it. On Linux and macOS the file is mode 0600 from the moment it is created; on Windows loot sets no permissions on it at all — it inherits whatever your config directory grants. Treat it like a private key, because beside your .loot/ it is one.

On Windows nothing clears that session for you. There is no reboot-cleared runtime directory to put it in, so an unlock lasts until you run loot lock. "Until the session ends" means exactly that and nothing more.

A push cannot be taken back

undo stops at it, burn cannot follow it into a git mirror, and neither recalls what was already read.

A push is recorded in the operation log as a barrier, and loot undo refuses to step across one: a push discloses; it cannot be retracted by undo. to reverse a published change, record a new change or `loot maroon` the path. That refusal is the honest answer rather than a missing feature. maroon cuts an identity off from future access; it does not reach a copy somebody already holds.

loot burn destroys every historical object of a path here and deposits a signed purge request, and it tells you which of three tiers you got. Never pushed: destruction is complete on this machine. Already pushed: best-effort — relays and peers that cooperate with your key destroy their copy on the next sync, and one that does not know your key holds the request for review instead. Pushed to a forge: bounded by that operator's retention window, which burn asks each host it disclosed to and prints, one line each.

loot burn cannot address a git blob. loot never rewrites git history. If the content was projected into the git mirror, burn names the commits and stops there — and if you burn without fixing the git tip first, the next ferry re-ingests the tip's bytes under a fresh address the burn log cannot match. Remove or re-seal the path at HEAD, ferry, and only then rewrite the mirror and every git remote with git-filter-repo or BFG. Or accept it, and rotate.

Rotate the leaked secret. Burning bytes cannot recall what was already read. It is the only step that actually ends an exposure, and it is the one people skip because the tool printed something reassuring first.

From our own testing

A hands-on sweep of the surface a solo tester touches, reviewed against v0.4.24. Worst first.

What happensWhat to do about it
loot edit reopens the tip only. Amending an older change refuses: v1 edits only a tip (childless) change.There is no workaround. This one is simply not built yet.

How this page is kept honest

No cadence. Updated on report, and dated so you can tell.

This page has no review schedule. Committing to one we would not keep would be its own dishonesty, and a Known Issues page that has quietly stopped being true is worse than not having one: it turns "we are honest about our bugs" into evidence that we stopped looking. So instead: it is updated on report. Anything found — by us while building, or by you while using it — is written here in the same pass that records it, and an entry is deleted rather than left struck through. An entry leaves on the release, not on the fix — you cannot install our working tree, so it stays until the release carrying its fix is the one named at the top of this page, and says so in the second column until then. Both halves of that keep the page a description of the binary you can install today, not a changelog of things that used to be wrong.

The date at the top is the last time somebody read this whole page against the release named beside it and confirmed every claim on it still holds. That date is the number to judge this page by. If it has drifted a long way behind the version you installed, treat what you read here as evidence of what was true then rather than of what is true now.

Reporting. There is no public issue tracker — the source repository is private — so mail security@millerbyte.com. It is the same address as the vulnerability disclosure route and it is the one we watch. A bug that costs you work is as welcome as a vulnerability, and a report that turns out to be our documentation being wrong is still a report worth sending. loot is maintained by one person, so expect an acknowledgement in days, not hours.