site/hephaestus/index.html
Local Dev 089805c498 site: fix Hephaestus nav wrap; logo + OG tags on tools and releases pages
hephaestus/index.html inlines its own nav CSS instead of loading shared.css,
so the injected logo SVG had no size rule and rendered at 300x150, pushing
the brand onto its own row. Added the three .logo rules to its inline style.
tools/ and releases/ were parked during the 0.3.18 ship; now carry the same
inline logo and Open Graph tags as the rest of the site.
2026-09-10 00:32:01 +02:00

343 lines
23 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Hephaestus — decentralized code forge for Silent Mode</title>
<meta name="description" content="Hephaestus is Silent Mode's code host. Sign in with a Bitcoin Cash wallet — no email, no password reset. Repos hosted on your VPS, cold blobs (LFS, attachments, packages) stored on the Sia network. Live at code.silentmode.st.">
<meta property="og:type" content="website">
<meta property="og:site_name" content="Silent Mode">
<meta property="og:title" content="Hephaestus — decentralized code forge for Silent Mode">
<meta property="og:description" content="Hephaestus is Silent Mode's code host. Sign in with a Bitcoin Cash wallet — no email, no password reset. Repos hosted on your VPS, cold blobs (LFS, attachments, packages) stored on the Sia network. Live at code.silentmode.st.">
<meta property="og:url" content="https://silentmode.st/hephaestus/">
<meta property="og:image" content="https://silentmode.st/brand/og.png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta name="twitter:card" content="summary_large_image">
<style>
:root{
--bg:#0b0e14; --panel:#141a24; --panel2:#18202c; --line:rgba(255,255,255,.09);
--ink:#e7eaf1; --mut:#8b98a9; --dim:#5e6678; --acid:#d6ff3d;
--chain:#d6ff3d; --sia:#b39ddb; --srv:#4fd1a5; --ok:#4fd1a5; --taken:#f6768a;
--warn:#ffc75f;
}
*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{margin:0;background:radial-gradient(1100px 560px at 50% -12%,#16202e,var(--bg));
color:var(--ink);font:16px/1.65 system-ui,-apple-system,Segoe UI,Roboto,sans-serif;min-height:100vh}
a{color:var(--acid)}
.wrap{max-width:980px;margin:0 auto;padding:0 1.2rem}
.topnav{position:sticky;top:0;z-index:20;display:flex;gap:2px;align-items:center;flex-wrap:wrap;
padding:10px 1.2rem;background:rgba(11,14,20,.82);backdrop-filter:blur(10px);
border-bottom:1px solid var(--line)}
.topnav .brand{font-weight:600;color:var(--ink);text-decoration:none;margin-right:14px;font-size:15px;letter-spacing:.2px}
.topnav .brand .g{color:var(--acid)}
.topnav .brand .logo{width:24px;height:16px;vertical-align:-2px;margin-right:8px}
.topnav .brand .logo .l1{stroke:var(--mut)}
.topnav .brand .logo .l2{stroke:var(--acid)}
.topnav a{color:var(--mut);text-decoration:none;padding:6px 12px;border-radius:8px;font-size:14px}
.topnav a:hover{color:var(--ink);background:var(--panel)}
.topnav a.here{color:var(--acid);background:rgba(214,255,61,.08)}
.topnav a.portal{margin-left:auto;background:rgba(214,255,61,.10);color:var(--acid);font-weight:500}
.topnav a.portal:hover{background:rgba(214,255,61,.18)}
header.hero{text-align:center;padding:5rem 1.2rem 1rem}
.mark{font-size:56px;line-height:1}
h1{font-size:clamp(2rem,5.5vw,2.9rem);margin:.4rem 0 .3rem}
h1 .g{color:var(--acid)}
.tag{color:var(--mut);font-size:1.05rem;max-width:660px;margin:0 auto}
.cta{margin-top:1.8rem;display:flex;gap:10px;justify-content:center;flex-wrap:wrap}
.btn{display:inline-block;text-decoration:none;padding:11px 20px;border-radius:10px;background:#4b7bec;color:#fff;font-size:14px;border:none;cursor:pointer;font-family:inherit;transition:filter .1s}
.btn.ghost{background:transparent;border:1px solid var(--line);color:var(--ink)}
.btn.acid{background:var(--acid);color:#0b0e14;font-weight:600}
.btn:hover{filter:brightness(1.12)}
section{padding:2.6rem 0;border-top:1px solid var(--line);margin-top:2.5rem}
section:first-of-type{border-top:none;margin-top:1.5rem}
h2{font-size:1.5rem;margin:0 0 .4rem}
h3{font-size:1.1rem;margin:1.2rem 0 .35rem}
.lede{color:var(--mut);margin:0 0 1.6rem;max-width:720px}
.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:14px}
.card{background:var(--panel);border:1px solid var(--line);border-radius:14px;padding:18px 20px}
.card h3{margin:0 0 .5rem;display:flex;align-items:center;gap:8px}
.card p{margin:0;color:var(--mut);font-size:14px}
.card .cta{margin-top:14px;justify-content:flex-start}
.dot{width:9px;height:9px;border-radius:50%;display:inline-block}
.d-chain{background:var(--chain)} .d-sia{background:var(--sia)} .d-srv{background:var(--srv)}
.note{background:var(--panel);border:1px solid var(--line);border-left:3px solid var(--acid);
border-radius:10px;padding:14px 18px;color:var(--mut);font-size:14px;margin-top:1.4rem}
.note.warn{border-left-color:var(--warn)}
.note b{color:var(--ink)}
code,.mono{background:#0e131b;border:1px solid var(--line);border-radius:6px;padding:1px 6px;font-family:ui-monospace,monospace;font-size:13px}
pre{background:#0e131b;border:1px solid var(--line);border-radius:10px;padding:12px 14px;overflow-x:auto;
font-family:ui-monospace,monospace;font-size:13px;color:var(--ink);margin:1rem 0;line-height:1.55}
ol.steps{counter-reset:s;list-style:none;padding:0;margin:1.2rem 0 0;display:grid;gap:10px}
ol.steps li{counter-increment:s;display:grid;grid-template-columns:30px 1fr;gap:14px;align-items:start;
background:var(--panel2);border:1px solid var(--line);border-radius:12px;padding:13px 16px}
ol.steps li::before{content:counter(s);grid-column:1;grid-row:1;
display:grid;place-items:center;width:24px;height:24px;border-radius:50%;
background:rgba(214,255,61,.14);color:var(--acid);font-size:12.5px;font-weight:700}
ol.steps li > *{grid-column:2;min-width:0}
ol.steps b{color:var(--ink)} ol.steps span{color:var(--mut);font-size:14px}
.pill{display:inline-block;font-size:11px;padding:2px 8px;border-radius:999px;background:rgba(255,255,255,.07);color:var(--dim);margin-left:8px;vertical-align:middle;font-weight:500}
.pill.soon{background:rgba(214,255,61,.13);color:var(--acid)}
.pill.warn{background:rgba(255,199,95,.14);color:var(--warn)}
table.spec{width:100%;border-collapse:collapse;margin:1.2rem 0;font-size:14px}
table.spec th,table.spec td{padding:8px 12px;border-bottom:1px solid var(--line);text-align:left;vertical-align:top}
table.spec th{color:var(--mut);font-weight:500;font-size:12.5px;text-transform:uppercase;letter-spacing:.3px}
table.spec td:first-child{color:var(--acid);white-space:nowrap;font-family:ui-monospace,monospace;font-size:13px}
footer{border-top:1px solid var(--line);padding:2.4rem 0 3.5rem;color:var(--dim);font-size:13px;text-align:center;margin-top:2.5rem}
</style>
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
</head>
<body>
<nav class="topnav">
<a class="brand" href="../"><svg class="logo" viewBox="0 0 32 20" aria-hidden="true"><rect class="l1" x="1.5" y="3.5" width="17" height="13" rx="6.5" ry="6.5" fill="none" stroke-width="2.6"/><rect class="l2" x="13.5" y="3.5" width="17" height="13" rx="6.5" ry="6.5" fill="none" stroke-width="2.6"/></svg>Silent <span class="g">Mode</span></a>
<a href="../tools/">Theseus</a>
<a href="../prometheus/">Prometheus</a>
<a href="../sirius/">Sirius</a>
<a href="./" class="here">Hephaestus</a>
<a href="../helios/">Helios</a>
<a href="../hermes/">Hermes</a>
<a href="https://code.silentmode.st/" class="portal">Open forge →</a>
</nav>
<div class="wrap">
<header class="hero">
<div class="mark">⚒️</div>
<h1><span class="g">Hephaestus</span> — the forge</h1>
<p class="tag">A code host you sign into with a Bitcoin Cash wallet. Repositories on your own VPS, cold blobs on the Sia network. No email. No password reset. No middleman.</p>
<div class="cta">
<a class="btn acid" href="https://code.silentmode.st/user/oauth2/hephaestus-wallet">Sign in with wallet</a>
<a class="btn ghost" href="https://code.silentmode.st/explore/repos">Browse repos</a>
</div>
</header>
<section id="what">
<h2>What Hephaestus is</h2>
<p class="lede">A friction-free GitHub alternative for people who want to hold their own identity. Under the hood it's Forgejo (a soft-fork of Gitea) with a wallet-authentication layer bolted on and cold storage moved from disk to Sia.</p>
<div class="grid">
<div class="card">
<h3><span class="dot d-chain"></span> Wallet is your identity</h3>
<p>Generate or import a BCH wallet in your browser. Sign a one-time challenge to prove control. That's your account — nothing to remember except your recovery phrase.</p>
</div>
<div class="card">
<h3><span class="dot d-sia"></span> Cold storage on Sia</h3>
<p>Every LFS object, release archive, package registry blob and issue attachment lives on the Sia network via <code>s3.silentmode.st:8600</code>. Live git repos + Postgres stay on the VPS SSD for speed.</p>
</div>
<div class="card">
<h3><span class="dot d-srv"></span> Standard git — push over HTTPS or SSH</h3>
<p>Nothing weird. <code>git clone</code>, <code>git push</code>, PRs, issues, releases, container registry, the works. Bring your existing muscle memory.</p>
</div>
</div>
</section>
<section id="quickstart">
<h2>Sign in — 30 seconds</h2>
<ol class="steps">
<li><b>Open the forge.</b> <span>Go to <a href="https://code.silentmode.st/">code.silentmode.st</a> and click <b>Sign in</b>, then <b>Sign in with hephaestus-wallet</b>.</span></li>
<li><b>Generate or import a wallet.</b> <span>Pick "Generate new" for a fresh BIP-39 12-word recovery phrase, or "Import existing" if you already have one. Write it down — <b>lose it and the account is gone</b>.</span></li>
<li><b>Set a browser passphrase</b> (min 8 chars). <span>Used to encrypt the wallet in your browser's localStorage. Never leaves your device.</span></li>
<li><b>Click "Create wallet &amp; sign in".</b> <span>The browser signs a challenge, the server verifies, Forgejo auto-provisions you as <code>bch_&lt;first-20-of-your-cashaddr&gt;</code>. You land in the dashboard.</span></li>
</ol>
<p class="note"><b>Why no email?</b> Nothing to leak, nothing to phish, no password-reset flow to hijack. The trade: if you lose your recovery phrase there is no support form to send you back in. Back the phrase up. Twice. On paper.</p>
</section>
<section id="cli">
<h2>For CLI &amp; programmatic access <span class="pill">read before debugging</span></h2>
<p class="lede">If you're driving the sign-in from a CLI, CI job, or any scripted client without a real browser, read this first. It heads off two misdiagnoses we've already hit.</p>
<h3>Misdiagnosis #1: "The login shell page is only 510 bytes — it's a broken stub"</h3>
<p>It's not a stub — it's a <b>deliberately small bootstrap page</b> that renders the wallet UI client-side via a JS module (standard SPA pattern). Size ≠ brokenness. The full UI (mnemonic generation, passphrase encryption, sign flow) is inside <code>wallet.js</code>, not the shell. Test by requesting <code>wallet.js</code> instead:</p>
<pre>curl -sI https://code.silentmode.st/auth/static/wallet.js
# expect: HTTP 200, ~10 KB, Content-Type: application/javascript</pre>
<h3>Misdiagnosis #2: "static/wallet.js returns 404 at every path"</h3>
<p>It only 404s if you drop the <code>/auth/</code> prefix. Caddy path-multiplexes: <b><code>/auth/*</code> goes to the auth-proxy, everything else goes to Forgejo</b>. Forgejo has no <code>/static/wallet.js</code>, so that path is expected-404. The real paths are:</p>
<table class="spec">
<tr><th>URL</th><th>Served by</th><th>Purpose</th></tr>
<tr><td>/auth/authorize</td><td>auth-proxy</td><td>Login shell HTML (SPA bootstrap)</td></tr>
<tr><td>/auth/static/wallet.js</td><td>auth-proxy</td><td>Wallet UI + signing logic (~10 KB)</td></tr>
<tr><td>/auth/static/login.css</td><td>auth-proxy</td><td>Styles for the login card</td></tr>
<tr><td>/auth/challenge</td><td>auth-proxy</td><td>POST cashaddr → get nonce + signed message</td></tr>
<tr><td>/auth/verify</td><td>auth-proxy</td><td>POST nonce + signature → get OAuth code</td></tr>
<tr><td>/auth/.well-known/openid-configuration</td><td>auth-proxy</td><td>OIDC discovery</td></tr>
<tr><td>/user/oauth2/hephaestus-wallet</td><td>Forgejo</td><td>Kicks off the OAuth handshake (307 → /auth/authorize)</td></tr>
<tr><td>/user/oauth2/hephaestus-wallet/callback</td><td>Forgejo</td><td>Receives the OAuth code, mints session</td></tr>
<tr><td>/api/v1/version</td><td>Forgejo</td><td>Public: returns Forgejo version</td></tr>
<tr><td>/api/v1/user</td><td>Forgejo</td><td>Requires an API <b>token</b> (not a session cookie) — returning 401 in a browser is not a bug</td></tr>
</table>
<h3>Testing the sign-in flow end-to-end without a real browser</h3>
<p>The wallet signing is easiest to reproduce in Node/Deno or a headless browser — the crypto is BIP-137 "Bitcoin Signed Message" over BCH secp256k1. But <b>the server-side pieces alone can be smoke-tested with curl</b>:</p>
<pre>ISSUER=https://code.silentmode.st/auth
# 1. discovery document lists all endpoints
curl -s "$ISSUER/.well-known/openid-configuration" | jq .
# 2. request a challenge for any cashaddr (server just holds it 5 min)
curl -s -X POST -H 'content-type: application/json' \
-d '{"cashaddr":"bitcoincash:qq00000000000000000000000000000000000000q"}' \
"$ISSUER/challenge"
# → returns {"nonce": "...", "message": "code.silentmode.st wants you to sign in..."}
# 3. any BCH wallet that speaks "Sign Message" can produce a valid signature
# for that exact message. Then POST it:
curl -s -X POST -H 'content-type: application/json' \
-d '{"nonce":"THE_NONCE","signature":"BASE64_SIG"}' \
"$ISSUER/verify"
# → returns {"redirect": "https://code.silentmode.st/user/oauth2/hephaestus-wallet/callback?code=..."}</pre>
<p>For the JS side (which is what the browser does), inspect <code>auth-proxy/public/wallet.js</code> in the repo — it's ~250 lines and does exactly this: <code>generateBip39Mnemonic → deriveHdPath("m/44'/145'/0'/0/0") → sign(magicHash(message))</code>. Nothing exotic.</p>
<h3>Common browser-side checks</h3>
<p>If your CLI drives a real browser (Playwright, Puppeteer, curl-with-cookies) and you want to know if you're actually signed in:</p>
<pre>// The URL bar isn't reliable when Forgejo shows Security or Settings pages —
// they render for logged-in users but don't have "Dashboard" in the title.
// Best check: does the profile menu render, and is there no "Sign in" link?
const signedIn = !document.querySelector('a[href*="/user/login"]')
&amp;&amp; !!document.querySelector('[aria-label*="Profile"], .user-menu, .avatar');
// The username, if you're on the Dashboard:
document.title.match(/^(bch_\w+)/)?.[1];</pre>
<p class="note warn"><b>Do not test with <code>fetch('/api/v1/user')</code> unless you have an API token.</b> That endpoint requires token auth even when you're signed into the web UI. Session cookies get you into Forgejo pages; they don't get you into the token-scoped API. A 401 there means "no token" — it does not mean "not signed in."</p>
</section>
<section id="git">
<h2>Push some code</h2>
<p class="lede">Two paths, either works. Pick whichever fits your setup.</p>
<h3>Over HTTPS (with an access token)</h3>
<p>Log in, open <b>Settings → Applications → Generate New Token</b>, give it <code>write:repository</code> scope. Then:</p>
<pre>git clone https://<b>your_bch_username</b>:<b>YOUR_TOKEN</b>@code.silentmode.st/<b>your_bch_username</b>/<b>your-repo</b>.git
cd your-repo
echo "Hello, forge" &gt; README.md
git add README.md &amp;&amp; git commit -m "hello"
git push</pre>
<h3>Over SSH (with your existing key)</h3>
<p>Add your public key to <b>Settings → SSH / GPG Keys → Add Key</b>. Then use port 2222:</p>
<pre>git clone ssh://git@code.silentmode.st:2222/<b>your_bch_username</b>/<b>your-repo</b>.git</pre>
<p>Your key is only trusted for git-over-SSH; there's no shell access.</p>
</section>
<section id="architecture">
<h2>How it fits together</h2>
<pre> you (browser)
https://code.silentmode.st/
┌──────────┴──────────┐
│ Caddy │ ← Let's Encrypt cert, HTTP/3
│ (path-based mux) │
└──┬───────────────┬──┘
│ │
│/auth/* │/
▼ ▼
auth-proxy Forgejo ── Postgres (live git repos + DB
(OIDC provider) ───┬─── on local VPS SSD)
Node/Fastify │
libauth for │ storage backend
BCH signature ▼
verification s3.silentmode.st:8600 ← s3d gateway
Sia network hosts
(LFS, attachments,
packages, archives)</pre>
<table class="spec">
<tr><th>Component</th><th>Role</th></tr>
<tr><td>Forgejo 10</td><td>Web UI, PRs, issues, releases, container/npm registry, git-over-HTTPS + SSH</td></tr>
<tr><td>Postgres 16</td><td>User records, issues, PRs, permissions, session state</td></tr>
<tr><td>Caddy 2</td><td>Reverse proxy + automatic Let's Encrypt TLS + HTTP/3</td></tr>
<tr><td>auth-proxy</td><td>OIDC provider (Node/Fastify + <a href="https://libauth.org">libauth</a>). Issues signed challenges, verifies BCH signatures, mints OAuth codes.</td></tr>
<tr><td>s3d → Sia</td><td>Cold storage. Files are encrypted client-side, sharded via Reed-Solomon, scattered across independent hosts.</td></tr>
<tr><td>restic</td><td>Nightly encrypted snapshots (Postgres + /data/git) to a separate Sia bucket. Systemd timer at 03:15 UTC.</td></tr>
</table>
</section>
<section id="protocol">
<h2>Wallet-auth protocol</h2>
<p class="lede">Any BCH wallet that speaks Bitcoin Signed Message can produce a signature Hephaestus will accept. There is no Hephaestus-specific signing format.</p>
<pre>Message the wallet signs:
─────────────────────────────
code.silentmode.st wants you to sign in with your Bitcoin Cash account:
bitcoincash:qzkc695pm4r3p7kcq36sh0t3fdu5e6ua7u2ar36vea
By signing, you prove you control this address. This request will not
trigger a blockchain transaction or cost any fees.
Domain: code.silentmode.st
Nonce: e65d80b51d3f1baa2efb8d952d827104
Issued At: 2026-08-29T17:50:12.655Z</pre>
<p>Signature is standard <b>BIP-137-style</b> recoverable ECDSA over the <code>SHA256(SHA256(varint(magic) || magic || varint(msg) || msg))</code> digest, base64-encoded. The server recovers the pubkey, derives the cashaddr, and matches it against the address you claimed. Nonces expire after 5 minutes and are single-use.</p>
<p>OIDC id_token claims: <code>sub = full cashaddr</code>, <code>preferred_username = "bch_" + first-20-of-address</code>, plus a custom <code>cashaddr</code> claim carrying the full address for downstream tools. Signed with EdDSA (Ed25519).</p>
</section>
<section id="operators">
<h2>For operators <span class="pill">self-host your own</span></h2>
<p class="lede">Hephaestus is a docker-compose stack. Everything you need is in the <a href="https://code.silentmode.st/silentmode/silentmode">silentmode monorepo</a> under <code>Hephaestus/</code>. To stand up your own instance:</p>
<ol class="steps">
<li><b>Get a Linux VPS with Docker</b> <span>(2 GB RAM, ~10 GB free disk minimum). A domain name pointing at it. Ports 80/443/2222 open.</span></li>
<li><b>Clone the repo, copy the env template</b>
<pre>git clone ssh://git@code.silentmode.st:2222/silentmode/silentmode.git
cd silentmode/Hephaestus
cp .env.example .env
# fill in real values — see .env.example for what each field means</pre></li>
<li><b>Bring it up</b>
<pre>docker compose up -d</pre>
<span>First run pulls ~500 MB of images and builds the auth-proxy. Give it a few minutes.</span></li>
<li><b>Complete Forgejo install</b> <span>via POST to <code>/</code> with your admin creds (see <code>PROTOCOL.md</code> in the repo for the exact field list — Forgejo's <code>--config</code> path prevents the CLI installer working, so it has to be the HTTP path).</span></li>
<li><b>Register the wallet OIDC provider</b>
<pre>docker compose exec forgejo forgejo \
--config /data/gitea/conf/app.ini admin auth add-oauth \
--provider openidConnect \
--name hephaestus-wallet \
--key "$AUTH_PROXY_CLIENT_ID" --secret "$AUTH_PROXY_CLIENT_SECRET" \
--auto-discover-url "$AUTH_PROXY_ISSUER/.well-known/openid-configuration" \
--scopes "openid profile"</pre></li>
</ol>
<h3>Gotchas we hit — save yourself the same debugging</h3>
<ul style="color:var(--mut);font-size:14.5px;line-height:1.75">
<li>Forgejo's docker entrypoint re-writes <code>app.ini</code> from env vars on every start — sed edits inside the container get clobbered. Everything must come from <code>FORGEJO__section__KEY</code> env vars in <code>docker-compose.yml</code>.</li>
<li><code>DISABLE_REGISTRATION=true</code> blocks OIDC auto-provisioning too, not just the local form. Use <code>DISABLE_REGISTRATION=false</code> + <code>ALLOW_ONLY_EXTERNAL_REGISTRATION=true</code> + <code>SHOW_REGISTRATION_BUTTON=false</code>.</li>
<li>Forgejo needs <code>[oauth2_client] ENABLE_AUTO_REGISTRATION=true</code> AND <code>USERNAME=preferred_username</code> AND an <code>email</code> claim on the id_token (auth-proxy synthesizes one).</li>
<li>Forgejo usernames are <code>[a-zA-Z0-9-_.]+</code>, max 40 chars. Raw cashaddrs (54 chars, colon) don't fit — auth-proxy sends <code>bch_&lt;first-20&gt;</code> as the username while keeping the full cashaddr in <code>sub</code>.</li>
<li>When serving auth-proxy under a <code>/auth/*</code> path prefix behind a reverse proxy, all client-side asset paths and fetch URLs must be <b>path-relative</b> (no leading slash), otherwise the browser resolves them to origin root and hits the wrong service.</li>
</ul>
</section>
<section id="status">
<h2>Status</h2>
<table class="spec">
<tr><th>Live at</th><td><a href="https://code.silentmode.st/">code.silentmode.st</a></td></tr>
<tr><th>Signup</th><td>Open (wallet-only; local registration disabled)</td></tr>
<tr><th>Storage</th><td>Sia network for cold blobs, VPS SSD for hot path</td></tr>
<tr><th>Backups</th><td>Nightly restic → separate Sia bucket, encrypted client-side</td></tr>
<tr><th>Source</th><td><a href="https://code.silentmode.st/silentmode/silentmode">silentmode/silentmode</a> (private — request access from an admin), or the local checkout under <code>Hephaestus/</code></td></tr>
<tr><th>License</th><td>Forgejo is GPL-3.0. Auth-proxy + Caddyfile + docker-compose scaffolding is part of the Silent Mode monorepo.</td></tr>
<tr><th>Chain</th><td>Chipnet (Bitcoin Cash test network) <span class="pill warn">alpha</span></td></tr>
<tr><th>BCNR name</th><td><code>hephaestus.x</code> — minted on chipnet, points at <code>https://code.silentmode.st/</code>. Resolve via <a href="https://navigate.st/bns/hephaestus.x/">navigate.st gateway</a> or any BCNR-aware browser (Theseus, Ariadne).</td></tr>
</table>
<p class="note"><b>Report an issue.</b> Open one at <a href="https://code.silentmode.st/silentmode/silentmode/issues">silentmode/silentmode/issues</a> once you have access, or ping in the usual Silent Mode channels.</p>
</section>
</div>
<footer>
<div class="wrap">
Silent Mode — a Deviant project · Hephaestus is one of the Silent Mode tools · <a href="../">silentmode.st</a>
</div>
</footer>
</body>
</html>