# A check we run, not just a promise.

> Renest's escape hatch is restore.sh, one plain shell script that brings a nest's files and dependencies back using only curl, jq, sha256sum, tar and uv. Every change to the nest format is checked by running that script, so the promise that your setup can leave without us is tested rather than merely stated.

Canonical page: https://renest.ai/docs/escape-hatch-deep-dive

<h2 id="promises">An export promise that nothing runs drifts out of truth</h2>

<p>Almost every storage product makes the same promise, usually as one sentence in an FAQ:
<em>your data can always leave</em>. The sentence is sincere when it is written. Then the
product keeps moving. A new field lands in the storage format; the export path nobody runs
falls a version behind; a dependency of the export tool breaks and nobody notices, because
nothing in the release process ever runs it. The promise is still on the page. It just
isn't true anymore, and there is no moment at which anyone decided to break it.</p>

<p>That failure mode is structural, not moral. A promise checked by nobody, on no schedule,
will drift out of truth — the only question is when. So we tie the check to the moment the
drift would start: a change to the format.</p>

<h2 id="gate">Every format change is checked by running the escape hatch itself</h2>

<p>The escape hatch is <code>restore.sh</code>: one plain shell script that brings a nest's
files and dependencies back using only <strong>curl, jq, sha256sum (or shasum), tar and uv</strong>, plus the stock
text tools every base system ships. It does not need Renest installed, and pointed at a
bucket you can already read it needs no account and no server of ours. From format 2.3
on, a copy travels inside every nest Renest packs. The
<a href="/docs/escape-hatch">operational page</a> covers how to run it. This page is
about how it is kept honest.</p>

<p>Two things check it:</p>

<ul>
<li><strong>An automated test.</strong> Our test suite packs a nest with the current code,
runs the real <code>restore.sh</code> against it — not a Python stand-in — and checks
every file that comes back against its recorded fingerprint, byte for byte.</li>
<li><strong>A run on a real machine for every format change.</strong> Our checklist for
changing the format calls for running the escape hatch on a real Linux machine rather
than a development laptop, and separately running the full product path until a rebuilt
environment renders an image. Both are required; neither stands in for the other. This is
a written release step, not something a machine blocks on.</li>
</ul>

<p><strong>The script's clean exit is not the whole verdict.</strong> It proves the files
came back and matched their fingerprints. The script itself never starts the application —
its last stage is the byte check — so "did the rebuilt environment actually do its job"
is answered by the product path, where the <code>renest</code> tool starts the
application and judges what comes out. See <a href="/docs/three-gates">how a rebuild
is judged</a>.</p>

<h2 id="consequences">Running the script against each format keeps the format open and the dependency list short</h2>

<p><strong>The format cannot quietly grow private state.</strong> The script rebuilds only
what the manifest records. Anything a format change put somewhere else — a server-side
lookup, a field only our own tooling understands — is invisible to the script, and a
rebuild that relied on it would come back incomplete. So a capability the format gains
has to be expressible in the open manifest to survive the escape hatch.</p>

<p><strong>The dependency list cannot creep.</strong> Each new convenience — a fancier
downloader, a verification library, a progress UI — would be one more thing a stranded
user in some future year has to find before their files come back. The format-change
checklist says outright that the escape hatch gains no new dependency, and the script
works around missing conveniences rather than adding them (it builds its own timeout from
a background job and <code>sleep</code> instead of requiring <code>timeout</code>). The
list has moved in only one direction so far: git was on it once, and was removed when it
turned out the script never actually called it.</p>

<p><strong>Old nests stay readable on purpose.</strong> The script's header records exactly
which format versions this copy reads, and the version check distinguishes two cases: a
<em>newer minor</em> version of the same major is warned about and let through, because
the specification only ever adds optional fields within a major version — refusing would
turn a nest whose bytes restore perfectly into a brick. A <em>different major</em> version
is refused outright, and the refusal points out that the manifest still lists every file
with its fingerprint, so nobody is left wondering whether their models are gone. The
warn-and-continue rule exists because an earlier copy of the script once refused a minor
version that had only added optional fields.</p>

<h2 id="scope">The escape hatch brings files back and reports compatibility, but never decides it</h2>

<p>Stating the promise narrowly is what makes it keepable, so here is the narrow version.
The escape hatch needs: the five tools above, a shell, and <strong>network reach to
wherever your nest is stored</strong> — your own bucket, or ours. It cannot sign links to a
private bucket itself (it has no openssl, deliberately), so a private bucket needs links
signed where your key lives, passed in as a restore code or presigned URLs.</p>

<p>And it does not promise the rebuilt environment runs on any machine. A GPU the packed
build has no compiled code for, a different CUDA major version, a different chip family —
the script detects these, says so in plain terms before the download starts, and
<strong>carries on anyway</strong>. Its job is to get your files back and rebuild the
environment as recorded; whether this particular machine can run the result is a fact it
reports, never a decision it makes for you.</p>

<h2 id="refuses">The script stops on trust problems, not on compatibility problems</h2>

<p>Trust is the exception, because a nest is someone's code arriving on your machine. The script refuses a manifest path that tries to write outside the folder you gave it, or to drop files where they would be executed rather than read — that check runs before any file is fetched. A nest may carry four model caches (Hugging Face, rembg, transparent-background, insightface); they land inside the restore folder. Two riskier cases, a link in a code archive that points outside its folder and a home-folder path beyond those caches, are warned about loudly and go ahead only when you type <code>yes</code> or set the confirming variable. It tells you the risk and leaves the decision to you. And it stops before
installing any dependency when a nest's dependency lock points at servers outside a known
list, unless you name those hosts yourself. Those are not compatibility questions, and a
warning that scrolls past during a long install would be worthless there. Machine
mismatches, by contrast, are told loudly and then attempted anyway.</p>

<h2 id="audit">Every shipped copy of the script is listed by sha256 so you can check yours</h2>

<p>None of the above needs to be taken on faith. The script is plain shell, readable start
to finish, and each shipped version is listed by sha256 — along with which format it was
written for and what was later found wrong with it — in a version list kept
with the format specification. The script never
reads that list itself; it works the same when you cannot reach it. It is there for
you.</p>

<p>The licensing matches the role. The format specification and the escape hatch script are
Apache-2.0 — genuinely open, because these are the parts that must outlive us for any of
this to mean anything. The <code>renest</code> command-line tool is source-available, with
its code published in full, and we don't call this source-available tool open-source software.
See <a href="/docs/licensing">licensing</a> for the details.</p>

<p>A promise is a sentence about the future, maintained by memory. A check is something
you run. We would rather depend on the second — and so can you.</p>
