Files
loom-cli/.loom/published/guarantees.md
T
jeffryandClaude Opus 5 d3fec24bc6 guarantees: promise visibility about the surface we do not promise
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
2026-09-08 10:41:29 -04:00

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 lockthe 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 silenta 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 aloneit 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 ]
  • pathrelative 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/.
  • urlthe resolved origin, branch and all.
  • etagthe publisher's, verbatim, including its quotes.
  • visibilityoptional. What the source could be read as when it was fetched: public or not-public. Never privatean 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 lockand a lock on this page reports 200 the 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.