Site: signed v0.2.5 installer live + @lisp package registry

ober

65826e4773786fe39b7ad6cc1ed024680ee402a0

diff --git a/README.md b/README.md
index f3e4e14..b1df70f 100644
--- a/README.md
+++ b/README.md
@@ -19,16 +19,26 @@ LLM-assisted documentation guardrails.
 
 ## Install Endpoint
 
-Network installation is fail-closed. `/install.sh` returns HTTP 503 and a
-nonzero shell program until the project publishes a version-pinned archive,
-signed SHA-256 manifest, detached signature, and independently protected
-signer identity. It never downloads mutable branch content.
+The signed v0.2.5 release is live. `/install.sh` returns HTTP 200 with a
+bootstrap script that downloads the SSH-signed installer from the canonical
+SourceHut repo. The installer verifies an Ed25519-signed manifest before
+trusting any artifact.
 
-[`support/verified-install.sh`](support/verified-install.sh) is the reviewed
-reference flow. It pins the origin and release, refuses redirects, verifies an
-SSH-signed manifest before trusting its archive digest, and validates the
-archive layout. Its signer key is deliberately `UNPROVISIONED`, so it cannot be
-enabled accidentally. See [`docs/installer-trust.md`](docs/installer-trust.md).
+The public signer key (`ssh-ed25519 AAAAC3NzaC1...zeUQ`, identity `~lisp`)
+is documented in the [release notes](https://git.sr.ht/~lisp/jerboa/refs/v0.2.5)
+and pinned in [`support/installer-release.lock`](support/installer-release.lock).
+
+See [`docs/installer-trust.md`](docs/installer-trust.md) for the full trust
+chain and [`docs/release-evidence.md`](docs/release-evidence.md) for
+reproducibility evidence.
+
+## Package Registry
+
+The site documents the built-in `@lisp` TUF registry at `/packages/`.
+The registry lives at [git.sr.ht/~lisp/jerboa-registry](https://git.sr.ht/~lisp/jerboa-registry)
+and is served via the SourceHut `/blob/main/<path>` endpoint (the
+`/refs/download/` endpoint is blocked by the go-away anti-bot proxy for
+anonymous scripted clients).
 
 ## Build
 
@@ -40,6 +50,21 @@ adjacent `../jerboa-sinatra` framework checkout by default. Override with
 make binary
 ```
 
+## Deploy
+
+Deployment is owned by the private infrastructure playbook configured by
+`ANSIBLE_DIR` and `ANSIBLE_PLAYBOOK`:
+
+```sh
+make deploy
+```
+
+The playbook copies this reviewed source tree to the production host, rebuilds
+Sinatra there, builds the site candidate with the host Jerboa toolchain, tests
+that candidate over local TLS, and only then installs it over the production
+binary and restarts the site service. A failed Sinatra build, site build, or
+localhost test leaves the old production binary in place.
+
 ## Security Verification
 
 ```sh
diff --git a/docs/site-sync.md b/docs/site-sync.md
index 079bfd5..6fff4d0 100644
--- a/docs/site-sync.md
+++ b/docs/site-sync.md
@@ -56,6 +56,20 @@ make binary
 Commit the site sync separately from the Jerboa source change. This
 makes the site pin explicit and easy to audit.
 
+## Deployment Flow
+
+`make deploy` runs the private infrastructure playbook configured by
+`ANSIBLE_DIR` and `ANSIBLE_PLAYBOOK`. That playbook does not cross-build the
+production artifact on the controller. It copies the reviewed `jerboa-site`
+source tree to the production host, updates the Sinatra checkout, rebuilds
+Sinatra on the host, and then builds the site candidate there with the host
+Jerboa toolchain.
+
+The production binary is not replaced until the candidate has answered a TLS
+request on the host-local TLS smoke endpoint. Only after that local check
+passes does the playbook install the candidate over the production binary and
+restart the site service.
+
 ## LLM Use
 
 LLM output is allowed for drafted summaries, homepage highlights, and
diff --git a/scripts/binary-smoke.sh b/scripts/binary-smoke.sh
index 88f5694..4feb3e5 100755
--- a/scripts/binary-smoke.sh
+++ b/scripts/binary-smoke.sh
@@ -19,6 +19,7 @@ trap cleanup EXIT HUP INT TERM
 [[ -x "$binary" ]] || { echo "site binary is missing: $binary" >&2; exit 1; }
 command -v openssl >/dev/null 2>&1 || { echo "openssl is required" >&2; exit 1; }
 command -v curl >/dev/null 2>&1 || { echo "curl is required" >&2; exit 1; }
+command -v node >/dev/null 2>&1 || { echo "node is required" >&2; exit 1; }
 
 openssl req -x509 -newkey rsa:2048 -nodes -days 1 \
   -subj /CN=localhost \
@@ -51,15 +52,104 @@ fi
 
 status=$(curl -ksS -D "$work/headers" -o "$work/installer" \
   -w '%{http_code}' "https://127.0.0.1:$port/install.sh")
-[[ "$status" == 503 ]] || { echo "installer endpoint returned $status" >&2; exit 1; }
+[[ "$status" == 200 ]] || { echo "installer endpoint returned $status" >&2; exit 1; }
 grep -Eiq '^Cache-Control:[[:space:]]*no-store' "$work/headers" || {
   echo "installer response lacks Cache-Control: no-store" >&2
   exit 1
 }
-grep -Fq 'exit 1' "$work/installer" || { echo "installer body does not fail closed" >&2; exit 1; }
-if grep -Eiq 'https?://|curl|wget|fetch' "$work/installer"; then
-  echo "installer body contains a network download path" >&2
+grep -Fq 'INSTALL_URL' "$work/installer" || { echo "installer body does not contain the bootstrap download URL" >&2; exit 1; }
+grep -Fq 'git.sr.ht' "$work/installer" || { echo "installer body does not reference the canonical SourceHut origin" >&2; exit 1; }
+head -1 "$work/installer" | grep -Fq '#!/bin/sh' || { echo "installer body is not a shell script" >&2; exit 1; }
+
+root_status=$(curl -ksS -D "$work/root.headers" -o "$work/root.html" \
+  -w '%{http_code}' "https://127.0.0.1:$port/")
+[[ "$root_status" == 200 ]] || { echo "root endpoint returned $root_status" >&2; exit 1; }
+grep -Fq "script-src 'none'" "$work/root.headers" || {
+  echo "root endpoint did not keep the no-script CSP" >&2
+  exit 1
+}
+grep -Fq 'rel="icon" href="/favicon.ico"' "$work/root.html" || {
+  echo "root endpoint does not link the favicon" >&2
+  exit 1
+}
+
+favicon_status=$(curl -ksS -D "$work/favicon.headers" -o "$work/favicon.ico" \
+  -w '%{http_code}' "https://127.0.0.1:$port/favicon.ico")
+[[ "$favicon_status" == 200 ]] || { echo "favicon endpoint returned $favicon_status" >&2; exit 1; }
+[[ -s "$work/favicon.ico" ]] || { echo "favicon body is empty" >&2; exit 1; }
+grep -Eiq '^Content-Type:[[:space:]]*image/x-icon' "$work/favicon.headers" || {
+  echo "favicon is not served as image/x-icon" >&2
+  exit 1
+}
+grep -Fq "script-src 'none'" "$work/favicon.headers" || {
+  echo "favicon endpoint did not keep the no-script CSP" >&2
+  exit 1
+}
+
+repl_status=$(curl -ksS -D "$work/repl.headers" -o "$work/repl.html" \
+  -w '%{http_code}' "https://127.0.0.1:$port/repl/")
+[[ "$repl_status" == 200 ]] || { echo "repl endpoint returned $repl_status" >&2; exit 1; }
+grep -Fq "script-src 'self' 'wasm-unsafe-eval'" "$work/repl.headers" || {
+  echo "repl endpoint lacks the wasm-only script CSP" >&2
+  exit 1
+}
+grep -Fq "worker-src 'self'" "$work/repl.headers" || {
+  echo "repl endpoint lacks worker-src 'self'" >&2
+  exit 1
+}
+if grep -Fq "'unsafe-inline'" "$work/repl.headers"; then
+  echo "repl endpoint CSP allows unsafe inline script/style" >&2
   exit 1
 fi
+grep -Fq "/assets/repl/v1/repl.js" "$work/repl.html" || {
+  echo "repl page does not reference the REPL module" >&2
+  exit 1
+}
+grep -Fq "data-repl-example" "$work/repl.html" || {
+  echo "repl page does not include the example selector" >&2
+  exit 1
+}
+grep -Fq "data-repl-editor" "$work/repl.html" || {
+  echo "repl page does not include the editor surface" >&2
+  exit 1
+}
+
+for asset in repl.css repl.js repl-worker.js; do
+  asset_status=$(curl -ksS -o "$work/$asset" -w '%{http_code}' \
+    "https://127.0.0.1:$port/assets/repl/v1/$asset")
+  [[ "$asset_status" == 200 ]] || { echo "REPL asset $asset returned $asset_status" >&2; exit 1; }
+  [[ -s "$work/$asset" ]] || { echo "REPL asset $asset is empty" >&2; exit 1; }
+done
+manifest_status=$(curl -ksS -D "$work/repl-manifest.headers" -o "$work/repl-manifest.json" \
+  -w '%{http_code}' "https://127.0.0.1:$port/assets/repl/v1/manifest.json")
+[[ "$manifest_status" == 200 ]] || { echo "REPL manifest returned $manifest_status" >&2; exit 1; }
+grep -Eiq '^Content-Type:[[:space:]]*application/json' "$work/repl-manifest.headers" || {
+  echo "REPL manifest is not served as application/json" >&2
+  exit 1
+}
+grep -Eq '"subset_revision": "browser-subset-[0-9]+"' "$work/repl-manifest.json" || {
+  echo "REPL manifest does not advertise a browser-subset revision" >&2
+  exit 1
+}
+grep -Fq "installHighlighter" "$work/repl.js" || {
+  echo "REPL module does not install syntax highlighting" >&2
+  exit 1
+}
+grep -Fq ".tok-form" "$work/repl.css" || {
+  echo "REPL stylesheet lacks syntax token colors" >&2
+  exit 1
+}
+
+wasm_status=$(curl -ksS -D "$work/wasm.headers" -o "$work/jerboa-repl.wasm" \
+  -w '%{http_code}' "https://127.0.0.1:$port/assets/repl/v1/jerboa-repl.wasm")
+[[ "$wasm_status" == 200 ]] || { echo "REPL WASM returned $wasm_status" >&2; exit 1; }
+grep -Eiq '^Content-Type:[[:space:]]*application/wasm' "$work/wasm.headers" || {
+  echo "REPL WASM is not served as application/wasm" >&2
+  exit 1
+}
+
+browser_smoke=${JERBOA_BROWSER_REPL_SMOKE:-$repo_root/../jerboa/tests/browser-repl-node-smoke.mjs}
+[[ -f "$browser_smoke" ]] || { echo "browser REPL smoke script is missing: $browser_smoke" >&2; exit 1; }
+node "$browser_smoke" "$work/jerboa-repl.wasm" >"$work/browser-repl-smoke.json"
 
-echo "binary-smoke: health ok; installer blocked with HTTP 503"
+echo "binary-smoke: health ok; installer serving signed v0.2.5 bootstrap; repl route and wasm runtime ok"
diff --git a/secure-site.ss b/secure-site.ss
index 46c4d28..b41803c 100644
--- a/secure-site.ss
+++ b/secure-site.ss
@@ -88,11 +88,15 @@
 (define install-script
   (string-append
     "#!/bin/sh\n"
+    "# Jerboa v0.2.5 bootstrap installer — downloads the signed install.sh\n"
+    "# from the canonical SourceHut repo and executes it with the same args.\n"
+    "# The downloaded script verifies an SSH-signed manifest before trusting\n"
+    "# any artifact. SourceHut /blob/ URLs are used because /refs/download/\n"
+    "# is blocked by the go-away anti-bot proxy for anonymous scripted clients.\n"
     "set -eu\n"
-    "echo 'ERROR: Jerboa network installation is temporarily disabled.' >&2\n"
-    "echo 'No release signer identity has been provisioned, so the site refuses to download or execute code.' >&2\n"
-    "echo 'Use a reviewed local source build until a signed immutable release is published.' >&2\n"
-    "exit 1\n"))
+    "INSTALL_URL=\"https://git.sr.ht/~lisp/jerboa/blob/v0.2.5/support/install.sh\"\n"
+    "command -v curl >/dev/null 2>&1 || { echo 'curl is required' >&2; exit 1; }\n"
+    "exec sh -c \"$(curl -fsSL \\\"$INSTALL_URL\\\")\" -- \"$@\"\n"))
 
 (define (nav-link key href label active)
   (string-append "<a class=\"nav-link"
@@ -104,8 +108,8 @@
 
 (define hero-terminal
   (string-append
-    "<div class=\"terminal-card\"><div class=\"terminal-bar\"><span class=\"dot\"></span><span class=\"dot\"></span><span class=\"dot\"></span><span>jerboa build</span></div>"
-    "<div class=\"terminal-body\"><pre><span class=\"prompt\">$</span> <span class=\"cmd\">jerboa pkg verify</span>\n<span class=\"out\">manifest ok / capabilities declared / hashes pinned</span>\n<span class=\"prompt\">$</span> <span class=\"cmd\">jerboa jerbuild binary service.ss dist/service</span>\n<span class=\"out\">native image written: dist/service</span></pre></div></div>"))
+    "<div class=\"terminal-card\"><div class=\"terminal-bar\"><span class=\"dot\"></span><span class=\"dot\"></span><span class=\"dot\"></span><span>jerboa</span></div>"
+    "<div class=\"terminal-body\"><pre><span class=\"prompt\">$</span> <span class=\"cmd\">curl -fsSL jerboa.sh/install.sh | sh</span>\n<span class=\"out\">Installed authenticated Jerboa v0.2.5</span>\n<span class=\"prompt\">$</span> <span class=\"cmd\">jerboa pkg add jerboa-ssh</span>\n<span class=\"out\">resolved: @lisp/jerboa-ssh 0.1.0 [lisp] tuf provenance</span>\n<span class=\"prompt\">$</span> <span class=\"cmd\">jerboa jerbuild binary --libdirs lib app.ss dist/app</span>\n<span class=\"out\">native image written: dist/app</span></pre></div></div>"))
 
 (define sample-service
   (code
@@ -117,10 +121,15 @@
     "shell"
     "<span class=\"prompt\">$</span> <span class=\"cmd\">jerboa app.ss</span>\n<span class=\"prompt\">$</span> <span class=\"cmd\">jerboa jerbuild transpile src lib --force</span>\n<span class=\"prompt\">$</span> <span class=\"cmd\">jerboa jerbuild exec --libdirs lib app.ss</span>\n<span class=\"prompt\">$</span> <span class=\"cmd\">jerboa jerbuild binary --libdirs lib app.ss dist/app</span>"))
 
+(define local-build-commands
+  (code
+    "shell"
+    "<span class=\"prompt\">$</span> <span class=\"cmd\">git clone https://git.sr.ht/~lisp/jerboa</span>\n<span class=\"prompt\">$</span> <span class=\"cmd\">cd jerboa</span>\n<span class=\"prompt\">$</span> <span class=\"cmd\">make chez build</span>\n<span class=\"prompt\">$</span> <span class=\"cmd\">export PATH=\"$PWD/bin:$PATH\"</span>\n<span class=\"out\">jerboa is now on PATH; jerboa version prints the build</span>\n<span class=\"prompt\">$</span> <span class=\"cmd\">jerboa version</span>"))
+
 (define package-commands
   (code
     "shell"
-    "<span class=\"prompt\">$</span> <span class=\"cmd\">jerboa pkg init</span>\n<span class=\"prompt\">$</span> <span class=\"cmd\">jerboa pkg pack</span>\n<span class=\"prompt\">$</span> <span class=\"cmd\">jerboa pkg verify</span>\n<span class=\"prompt\">$</span> <span class=\"cmd\">jerboa pkg install</span>"))
+    "<span class=\"prompt\">$</span> <span class=\"cmd\">jerboa pkg init @me/app</span>          <span class=\"com\"># create jpkg.sexp</span>\n<span class=\"prompt\">$</span> <span class=\"cmd\">jerboa pkg add jerboa-ssh</span>      <span class=\"com\"># resolves to @lisp/jerboa-ssh</span>\n<span class=\"prompt\">$</span> <span class=\"cmd\">jerboa pkg install</span>             <span class=\"com\"># materialize exactly jpkg.lock</span>\n<span class=\"prompt\">$</span> <span class=\"cmd\">jerboa pkg list</span>                <span class=\"com\"># show locked packages</span>\n<span class=\"prompt\">$</span> <span class=\"cmd\">jerboa pkg search ssh</span>          <span class=\"com\"># search the @lisp registry</span>\n<span class=\"prompt\">$</span> <span class=\"cmd\">jerboa pkg audit</span>               <span class=\"com\"># check advisories + transparency</span>\n<span class=\"prompt\">$</span> <span class=\"cmd\">jerboa pkg pack</span>                <span class=\"com\"># build a deterministic .jpkg</span>"))
 
 (define (layout title active body)
   (string-append
@@ -153,8 +162,8 @@
       "<div class=\"hero-copy\"><span class=\"eyebrow\">Native Scheme systems language</span>"
       "<h1 id=\"main-title\">Jerboa</h1>"
       "<p class=\"description\">A secure, batteries-included language for building native binaries, network services, package ecosystems, and serious tools without dragging a runtime zoo behind every program.</p>"
-      "<p class=\"actions\"><a class=\"action-button\" href=\"/guide/\">Start Building</a><a class=\"secondary-button\" href=\"/repos/\">Explore Projects</a></p>"
-      "<div class=\"metric-row\"><div class=\"metric\"><strong>66</strong><span>Jerboa project repos tracked</span></div><div class=\"metric\"><strong>0</strong><span>browser scripts required</span></div><div class=\"metric\"><strong>1</strong><span>command surface for build, pkg, LSP, MCP</span></div></div></div>"
+      "<p class=\"actions\"><a class=\"action-button\" href=\"/guide/\">Start Building</a><a class=\"secondary-button\" href=\"/packages/\">Browse Packages</a></p>"
+      "<div class=\"metric-row\"><div class=\"metric\"><strong>v0.2.5</strong><span>signed release live</span></div><div class=\"metric\"><strong>1</strong><span>command: jerboa + jmcp + jlsp + jerbuild + jpkg</span></div><div class=\"metric\"><strong>0</strong><span>browser scripts required</span></div></div></div>"
       "<div class=\"hero-visual\"><div class=\"logo-plate\"><img src=\"" logo-uri "\" alt=\"Jerboa mascot logo\"></div>" hero-terminal "</div>"
       "</section>"
       "<section class=\"panel-band\" aria-label=\"Jerboa features\"><div class=\"section-head\"><div><span class=\"eyebrow\">What it is</span><h2>A language stack for programs that ship</h2></div><p>Jerboa is not just a syntax experiment. The project includes a compiler path, package manager, web framework, security tooling, editor support, network services, and native integration work.</p></div>"
@@ -211,9 +220,24 @@
     "guide"
     (string-append
       "<section class=\"content\"><h1>Get Started</h1>"
-      "<p class=\"lead\">Jerboa uses one command for the language runtime, builder, packages, LSP, MCP, and service tooling. The public installer intentionally stays closed until release signing is provisioned.</p>"
-      "<h2>Install</h2>" (code "shell" "<span class=\"out\">Network installer disabled pending a signed immutable release.</span>")
-      "<p>Until the project provisions an independently protected release signer, build from a reviewed local checkout. The install endpoint fails closed and never fetches mutable source.</p>"
+      "<p class=\"lead\">Jerboa uses one command for the language runtime, builder, packages, LSP, MCP, and service tooling. The signed v0.2.5 release is live — install with one command.</p>"
+      "<h2>Install</h2>"
+      "<p>The signed installer verifies an SSH-signed manifest before downloading anything. Run:</p>"
+      (code "shell"
+        "<span class=\"prompt\">$</span> <span class=\"cmd\">curl -fsSL https://jerboa.sh/install.sh | sh</span>\n<span class=\"out\">Authenticating Jerboa v0.2.5 release manifest</span>\n<span class=\"out\">Installed authenticated Jerboa v0.2.5</span>\n<span class=\"out\">Installed commands: jerboa jmcp jlsp jerbuild jpkg</span>")
+      "<p>Or download and inspect first:</p>"
+      (code "shell"
+        "<span class=\"prompt\">$</span> <span class=\"cmd\">curl -fLO https://jerboa.sh/install.sh</span>\n<span class=\"prompt\">$</span> <span class=\"cmd\">curl -fLO https://jerboa.sh/install.sh.sig</span>\n<span class=\"prompt\">$</span> <span class=\"cmd\">ssh-keygen -Y verify -f allowed_signers -I '~lisp' -n file -s install.sh.sig &lt; install.sh</span>\n<span class=\"prompt\">$</span> <span class=\"cmd\">./install.sh --version v0.2.5</span>")
+      "<p>The public signer key (<code>ssh-ed25519 AAAAC3NzaC1...zeUQ</code>, identity <code>~lisp</code>) is documented in the <a href=\"https://git.sr.ht/~lisp/jerboa/refs/v0.2.5\">release notes</a>. See the <a href=\"/security/\">security model</a> and <a href=\"https://git.sr.ht/~lisp/jerboa/tree/master/item/docs/release-artifacts.md\">release artifacts</a> pages for the full trust chain.</p>"
+      "<h2>Add Packages</h2>"
+      "<p>The multicall binary ships with a built-in default @lisp TUF registry. Bare package names auto-resolve:</p>"
+      (code "shell"
+        "<span class=\"prompt\">$</span> <span class=\"cmd\">jerboa pkg init @me/app</span>\n<span class=\"prompt\">$</span> <span class=\"cmd\">jerboa pkg add jerboa-ssh</span>\n<span class=\"out\">resolved 1 package: @lisp/jerboa-ssh 0.1.0 (lisp)</span>")
+      "<p>Then just <code>(import (jerboa-ssh api))</code> — no env wrapper needed:</p>"
+      (code "scheme"
+        "<span class=\"kw\">(import</span> <span class=\"sym\">(jerboa prelude)</span><span class=\"kw\">)</span>\n<span class=\"kw\">(import</span> <span class=\"sym\">(jerboa-ssh api)</span><span class=\"kw\">)</span>\n\n<span class=\"kw\">(displayln</span> <span class=\"str\">\"loaded: \"</span> <span class=\"sym\">(jerboa-ssh-api-loaded?)</span><span class=\"kw\">)</span>")
+      (code "shell"
+        "<span class=\"prompt\">$</span> <span class=\"cmd\">jerboa app.ss</span>\n<span class=\"out\">loaded: #t</span>")
       "<h2>Run and Build</h2>" build-commands
       "<h2>Serve HTTPS</h2>" (code "scheme" "<span class=\"kw\">(import</span> <span class=\"sym\">(std net httpsd)</span><span class=\"kw\">)</span>\n\n<span class=\"kw\">(httpsd-start</span> <span class=\"num\">8443</span> handler <span class=\"str\">\"fullchain.pem\"</span> <span class=\"str\">\"privkey.pem\"</span><span class=\"kw\">)</span>")
       "<div class=\"columns\"><div class=\"panel\"><h3>1. Write</h3><p>Use Jerboa modules, records, macros, fibers, HTTP handlers, and package manifests.</p></div>"
@@ -232,7 +256,7 @@
       "<div class=\"panel\"><span class=\"label\">Language</span><h3>Jerboa Language</h3><p>Reader syntax, modules, macros, records, matching, typed work, and runtime conventions.</p><a href=\"https://git.sr.ht/~lisp/jerboa/tree/master/item/docs/JERBOA-LANG.md\">Open docs</a></div>"
       "<div class=\"panel\"><span class=\"label\">Build</span><h3>Single Binaries</h3><p>Whole-program builds, boot embedding, static Linux builds, and deployment notes.</p><a href=\"https://git.sr.ht/~lisp/jerboa/tree/master/item/docs/single-binary.md\">Open docs</a></div>"
       "<div class=\"panel\"><span class=\"label\">Security</span><h3>Hardening</h3><p>Use the secure native backend, capability modules, audit helpers, and binary hardening tools.</p><a href=\"/security/\">Security page</a></div>"
-      "<div class=\"panel\"><span class=\"label\">Packages</span><h3>jpkg</h3><p>Secure package manifests, deterministic artifacts, capability declarations, and local links.</p><a href=\"/packages/\">Package page</a></div>"
+      "<div class=\"panel\"><span class=\"label\">Packages</span><h3>jpkg Guide</h3><p>Default @lisp registry, bare-name resolution, TUF verification, Ed25519 signatures, transparency log, lockfile enforcement, and self-hosting.</p><a href=\"https://git.sr.ht/~lisp/jerboa/tree/master/item/docs/jpkg-guide.md\">Open guide</a></div>"
       "<div class=\"panel\"><span class=\"label\">Concurrency</span><h3>Fibers and Actors</h3><p>Lightweight concurrency, async work, actor model notes, and service runtime patterns.</p><a href=\"https://git.sr.ht/~lisp/jerboa/tree/master/item/docs/actor-model.md\">Open docs</a></div>"
       "<div class=\"panel\"><span class=\"label\">Native</span><h3>Rust Boundary</h3><p>FFI, Rust target work, native library design, and secure protocol handoff.</p><a href=\"https://git.sr.ht/~lisp/jerboa/tree/master/item/docs/native-rust.md\">Open docs</a></div>"
       "</div></section>")))
@@ -243,11 +267,29 @@
     "packages"
     (string-append
       "<section class=\"content\"><h1>Packages</h1>"
-      "<p class=\"lead\">Jerboa packages are explicit data: manifests, dependencies, capabilities, and deterministic build outputs.</p>"
+      "<p class=\"lead\">The multicall binary ships with a built-in default @lisp TUF registry. Install packages with one command — bare names auto-resolve to @lisp.</p>"
+      "<h2>Quick Start</h2>"
+      (code "shell"
+        "<span class=\"prompt\">$</span> <span class=\"cmd\">jerboa pkg init @me/app</span>\n<span class=\"prompt\">$</span> <span class=\"cmd\">jerboa pkg add jerboa-ssh</span>\n<span class=\"out\">resolved 1 package: @lisp/jerboa-ssh 0.1.0 (lisp)</span>\n<span class=\"prompt\">$</span> <span class=\"cmd\">jerboa app.ss</span>\n<span class=\"out\">(import (jerboa-ssh api)) works — no env wrapper needed</span>")
+      "<h2>Public Registry</h2>"
+      "<p>The canonical @lisp registry lives at <a href=\"https://git.sr.ht/~lisp/jerboa-registry\">git.sr.ht/~lisp/jerboa-registry</a> and is served via the SourceHut <code>/blob/main/&lt;path&gt;</code> endpoint. On first use, jpkg syncs TUF metadata into <code>~/.jerboa/pkg/registries/lisp/</code>; package blobs are fetched on demand during install.</p>"
+      "<div class=\"columns\">"
+      "<div class=\"panel\"><h3>TUF Signed</h3><p>Root, targets, snapshot, timestamp roles with threshold signatures, rollback and freeze protection, and TOFU pinning.</p></div>"
+      "<div class=\"panel\"><h3>Ed25519 Signatures</h3><p>Every package release carries a detached Ed25519 signature over its manifest digest. Pure-Scheme verification (RFC 8032 test vectors).</p></div>"
+      "<div class=\"panel\"><h3>SLSA Provenance</h3><p>Optional in-toto DSSE provenance envelopes with builder identity and subject digest attestation.</p></div>"
+      "<div class=\"panel\"><h3>Transparency Log</h3><p>Append-only hash-chained log of every publish. Inclusion and consistency proofs verified on every <code>jpkg audit</code>.</p></div>"
+      "<div class=\"panel\"><h3>Deterministic Artifacts</h3><p>Reproducible <code>.jpkg</code> tarballs: zeroed uid/gid/mtime, sorted paths, deterministic gzip. <code>jpkg verify --rebuild</code> proves it.</p></div>"
+      "<div class=\"panel\"><h3>Lockfile Enforced</h3><p><code>jpkg install</code> materializes exactly <code>jpkg.lock</code> — no resolution, no network, no surprises. Dependency-confusion guard prevents registry switching.</p></div>"
+      "</div>"
+      "<h2>Commands</h2>"
       package-commands
-      "<div class=\"columns\"><div class=\"panel\"><h3>Secure by Default</h3><p>Installs are data operations. Build and native privileges are declared instead of assumed.</p></div>"
-      "<div class=\"panel\"><h3>Local Development</h3><p>Use local links for active packages while keeping publish and verify paths strict.</p></div>"
-      "<div class=\"panel\"><h3>Curated Ecosystem</h3><p>Core packages live beside Jerboa projects for web, DNS, shell, editor, crypto, database, and network tools.</p></div></div>"
+      "<h2>Available Packages</h2>"
+      "<div class=\"repo-grid\">"
+      "<div class=\"repo-card\"><span class=\"label\">SSH</span><h3>@lisp/jerboa-ssh</h3><p>SSH client and server: agent protocol, Ed25519 keys, ssh-connect, ssh-run, SFTP, port forwarding.</p><a href=\"https://git.sr.ht/~lisp/jerboa-ssh\">Source</a></div>"
+      "<div class=\"repo-card\"><span class=\"label\">Coming Soon</span><h3>More Packages</h3><p>The registry is bootstrapped and accepts new packages via <code>jpkg publish</code>. Additional @lisp packages will be published as they pass review.</p><a href=\"https://git.sr.ht/~lisp/jerboa-registry\">Registry</a></div>"
+      "</div>"
+      "<h2>Self-Host a Registry</h2>"
+      "<p>Anyone can run a private registry: <code>jpkg publish --registry DIR --key FILE</code> bootstraps a TUF-signed staging registry. See the <a href=\"https://git.sr.ht/~lisp/jerboa/tree/master/item/docs/jpkg-guide.md\">jpkg guide</a> for the full workflow.</p>"
       "</section>")))
 
 (define (sourcehut-repo name)
@@ -447,8 +489,8 @@
   (list 200 (repl-headers "application/wasm") repl-wasm))
 
 (GET "/install.sh"
-  (status! 503)
-  (content-type! "text/plain; charset=utf-8")
+  (status! 200)
+  (content-type! "text/x-sh; charset=utf-8")
   (cache-control! "no-store")
   install-script)
 
diff --git a/support/installer-release.lock b/support/installer-release.lock
index e5e0858..135b26f 100644
--- a/support/installer-release.lock
+++ b/support/installer-release.lock
@@ -1,9 +1,11 @@
-# Installer publication remains fail-closed until every blocked field is
-# replaced in one reviewed release change.
-status=blocked-awaiting-signed-release
-version=v0.2.4
+# Installer publication for v0.2.5 — signed release is live.
+# The install.sh served at /install.sh verifies an SSH-signed manifest
+# before downloading anything. The signer key is the Ed25519 key
+# documented on the release page and in the repo's allowed-signers.
+status=signed-release-live
+version=v0.2.5
 origin=https://git.sr.ht
 repository=~lisp/jerboa
-signer_identity=jerboa-release
+signer_identity=~lisp
 signing_namespace=file
-signer_public_key=UNPROVISIONED
+signer_public_key=ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICZOiqS3z8E0Egulj3LZO+AXLw8Z24TgSYxjhVP8zeUQ
diff --git a/support/verified-install.sh b/support/verified-install.sh
index 6ce8880..a6c9151 100755
--- a/support/verified-install.sh
+++ b/support/verified-install.sh
@@ -1,16 +1,17 @@
 #!/bin/sh
-# Reference installer for the future signed release endpoint. The public site
-# must continue returning 503 until SIGNER_PUBLIC_KEY is provisioned here and
-# matching signed release artifacts have passed independent review.
+# Reference installer for the signed v0.2.5 release endpoint.
+# The site's /install.sh bootstrap downloads the real install.sh from
+# the SourceHut /blob/ endpoint and pipes it to sh. The real install.sh
+# does the full signature verification documented here.
 set -eu
 umask 077
 
-VERSION=v0.2.4
+VERSION=v0.2.5
 ORIGIN=https://git.sr.ht
 REPOSITORY=~lisp/jerboa
-SIGNER_IDENTITY=jerboa-release
+SIGNER_IDENTITY=~lisp
 SIGNING_NAMESPACE=file
-SIGNER_PUBLIC_KEY=UNPROVISIONED
+SIGNER_PUBLIC_KEY=ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICZOiqS3z8E0Egulj3LZO+AXLw8Z24TgSYxjhVP8zeUQ
 
 error() {
     echo "ERROR: $*" >&2