loom's .usages.md for this page found the hole. The docs site depends on the command surface — its README and publish script tell a person to type loomctl external add loom/<repo> <doc>.md — and this page explicitly does not promise it. Nothing parses the command, which is exactly why no check would catch a rename: the thing that moved is not a document anybody adopted. The answer is not to promise the surface, which would freeze the CLI. It is to promise that a change to it lands on this page — which consumers already lock — so a rename reports 200 the day it happens. The exclusion goes from "you are on your own" to "you will be told", and it costs one append-only section. Same shape as a supersession in the event log: the record is not that the thing never changes, it is that the change is findable by whoever depended on it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018UTxuSizozEA8yDitPuris
4.8 KiB
What loomctl guarantees
Not what it does — --help says that, and the commands will change. This is
what will keep being true while they do.
It grants no access, and records where the copy came from
loomctl reads what your credentials already let you read. Everything it
does is possible with copy and paste. It is a mast, not a lock — the point
is to make the wrong thing deliberate, not impossible.
What it adds over a paste is provenance. A pasted document cannot answer "where did this come from, and were we allowed to have it" — not because the question is hard, but because the evidence is gone.
It never writes over the network
No push, no publish, no POST, no token that needs write scope. Every byte
it writes is a file in your working tree. Committing and pushing are yours,
because the consequences of a push land on people a tool cannot experience.
A credential given to loomctl should never carry write scope, and if one
does, nothing here will use it.
Freshness is a conditional request against the publisher's ETag
Stored verbatim, opaque, never a hash we compute. A fetch that normalises anything breaks a local digest and reports a change that did not happen.
This is externals' rule and loomctl is a second holder of it. It is stated
here so that the tool holding it is a fact somebody can find, and so that
breaking it is visible rather than silent — a specimen was written in this
repository that computed a hash instead, and it was wrong within a day.
The URL in a lock is resolved. A short form follows whatever the default branch is at the time you ask, so a branch rename would report as a change in the document.
It reports; it does not repair
Nothing is overwritten. A document that moved upstream is written to a staging area as a candidate, and taking it is a separate act. A local copy that differs from what the publisher serves is left alone — it is the only evidence that something changed while nothing was watching.
add adopts what is absent and refuses what is already adopted. A document
that is present but unlocked is locked only when the bytes are identical to what
the publisher serves, so a lock's claim — this copy is the one being served —
is verified rather than assumed.
The lock file
.loom/externals/.locks, one record per adopted document, tab-separated,
ordered by path.
path <TAB> url <TAB> etag [ <TAB> visibility ]
path— relative to.loom/externals/, and for a person to read. It does not round-trip to a URL; it drops the route, the branch, and the publisher's.loom/published/.url— the resolved origin, branch and all.etag— the publisher's, verbatim, including its quotes.visibility— optional. What the source could be read as when it was fetched:publicornot-public. Neverprivate— an anonymous request tells those two apart and nothing finer.
Records with three fields remain valid. A repository does not stop working because the tool learned something new.
What is not promised
The command surface. Names, flags and output are --help's business and may
change. Nothing should parse them.
The generated orientation file's format. It is byte-deterministic within a version so that its diff is readable; it is not stable across versions.
That visibility is precise. The signal distinguishes public from not-public and nothing finer, so it cannot see two repositories private to different people — which is the case where adopting between private repositories genuinely widens access. The tool says so where it reports it, rather than implying a verdict it has not earned.
That anything is checked when you are not looking. Nothing here runs on a schedule, and a document nobody checks is a document nobody is checking.
What is promised about the things that are not promised
The command surface may change. This page will say when it does.
A consumer whose README tells a person to type loomctl external add loom/<repo> <doc>.md depends on that command by name — not by parsing it, which is why no
check would ever catch a rename. The thing that moved would not be a document
they adopted.
So the exclusion is narrower than "you are on your own". We do not promise the surface holds; we promise that a change to it lands here, on a page you can lock — and a lock on this page reports
200the day a command is renamed.
That is the whole mechanism, and it costs one section:
Surface changes
Append-only, newest last. Nothing yet — the commands have not been renamed since this page existed.
Verified fetchable by somebody who is not us on 2026-09-08.