Every Silent Mode public split repo is expected to be free of tool-attribution
metadata (see CLAUDE.md). The split output is filtered before it hits the
forge — local monorepo history is unchanged.
Also adds project-scoped CLAUDE.md so any Claude Code session working here
picks up the no-author-metadata rule on load.
- site/hephaestus.x/index.html: replace single 'Sign in with wallet' CTA with
a <details> dropdown labelled 'Bitcoin Cash wallet'. Menu items:
Sign in -> /user/oauth2/hephaestus-wallet#import
Sign up -> /user/oauth2/hephaestus-wallet#create (pill: easiest)
WizardConnect -> /user/oauth2/hephaestus-wallet#connect (pill: most private)
Same emoji + copy scheme as the wallet accordion, so the landing previews
the choices the user will see after clicking through.
- Hephaestus/auth-proxy/public/wallet.js: renderTabs() now reads location.hash
and auto-opens the matching <details> option on load (create/import/connect).
Fragments survive Forgejo's OAuth redirect chain, so a click on 'Sign up'
from the landing lands the user directly on the Create accordion.
Clicking Create / Import / WizardConnect now expands the flow *inside* that
option (native <details>/<summary>) instead of hiding the picker and rendering
a separate view. Opening one option auto-closes the others. Chevron flips and
border turns accent-orange on the open card. "Back" buttons removed — closing
is a click on the same summary.
- wallet.js: renderTabs() emits three <details class="wallet-opt">; the
per-option flow content is populated lazily on first `toggle` and lives
inside `.wallet-flow` (no more global #panel). Accordion behavior is
enforced by closing sibling <details> on toggle.
- login.css: .wallet-opt reworked as details-summary card; chevron rotates
on [open]; .wallet-flow is the divider-topped body inside each card.
- login.css/wallet.js: replace 2-tab (generate/import) UX with 3 big options
— Create a new wallet [easiest], Import / add a wallet, Connect a wallet —
WizardConnect [most private] (Cashonize/Paytaca placeholder, "coming soon").
- Caddyfile (both hostnames): /user/login now 302→ /user/oauth2/hephaestus-wallet.
Escape hatch: /user/login?password=1 falls through to Forgejo's password form,
linked from the picker footer as "Prefer old-school? Sign in with username & password".
Two pieces from testing "login through hephaestus.x":
1. bns-gateway (public-gateway.mjs, ip: case) — forward the upstream's
response headers, not just content-type. The old code stripped Location,
Set-Cookie, and everything else, so redirects from a proxied hostname
died silently in the browser ("Temporary Redirect" body with no Location
header). Header set now respects RFC 7230 hop-by-hop exclusions and
drops Content-Length (we may rewrite HTML for baseHref).
2. Hephaestus stack:
- forgejo/Dockerfile: tiny extension of the official image that copies
the Silent Mode Argonautica root CA into the OS trust store, so
Forgejo's Go client can validate hephaestus.x's cert on OIDC discovery
calls. Deliberately no `USER git` at the end — parent's s6-overlay
needs to init as root.
- docker-compose.yml: switch to `build: ./forgejo` and add
`extra_hosts: - "hephaestus.x:host-gateway"` so Forgejo can resolve
hephaestus.x back to the host's Caddy.
Both changes are inert at the moment because Forgejo's ROOT_URL is back at
code.silentmode.st (browsers-without-BCNR-resolvers couldn't complete
OAuth through hephaestus.x because session cookies don't cross origins —
the working UX has the "Sign in with wallet" button on hephaestus.x
delegate to code.silentmode.st). Keep the infrastructure in place for when
Theseus/Ariadne adoption makes it viable to flip ROOT_URL properly.
Architecture shift: hephaestus.x used to be Sia-bucket-only (via bns-gateway's
s3: record type). Now it's VPS-served with Silent Mode CA cert; the Sia bucket
stays populated as a disaster-recovery mirror that a single Argus CLI call
(update.js flipping ip: → s3:) can promote back to primary if the VPS dies.
Every code.silentmode.st URL now also works at hephaestus.x — the same Caddy
handles both hostnames; hephaestus.x additionally checks /srv/hephaestus.x/
for a matching static file first, so /forge/, /silentmode/theseus/, and the
other landing pages don't get eaten by Forgejo's dynamic routes.
- caddy/Caddyfile: add hephaestus.x server block with the Argonautica-issued
cert; static-first, Forgejo-fallback
- docker-compose.yml: mount ./caddy (whole dir, for certs/) and
/var/www/hephaestus.x → /srv/hephaestus.x
- scripts/sync-hephaestus-x-to-sia.sh: nightly rclone sync as DR backup
Off-tree changes (kept in memory record for future sessions):
- Silent Mode CA issued hephaestus.x.crt (fingerprint
6e251c2bb4987e66890aa28ebc8e16df5dfe03c1fc559634246ae69c2e00400b)
- BCNR record on hephaestus.x flipped to {"ip":"81.31.210.65","tls":"6e251c2b..."}
(TXID fdd301a2ae313636f71ec4dfba9a3ff723a9158b4a3937ac4ce0a83b3f8cda11)
- systemd timer hephaestus-x-sia-sync.timer on the p2pexchange VPS, 03:35 UTC daily
Since silentmode/silentmode was deleted and each project now lives in its
own repo, cross-cutting commits made in the local working copy need to be
routed per-project via git-subtree-split. Rather than remember the
incantation, wrap it:
scripts/push-split.sh Hephaestus # → 'hephaestus' remote
scripts/push-split.sh TheseusNavigator # → 'theseus' (Navigator suffix stripped)
scripts/push-split.sh AriadneResolver # → 'ariadne' (Resolver suffix stripped)
scripts/push-split.sh site-sirius-x sirius # explicit override for non-matching names
Preserves history (uses --branch, not --squash), pushes to <remote>:master,
cleans up the ephemeral branch on exit.
Previous version was a 100ms bounce to code.silentmode.st — user never saw
hephaestus.x/forge/ content, just a flash. New version is a real catalog page:
- Fetches public repo list live from Forgejo's API on page load
- Renders each repo as a card with name, owner, description, updated date,
clickable to code.silentmode.st/<owner>/<repo> when the user chooses
- Falls back to a "browse directly at code.silentmode.st" hint on API error
- Includes the git clone URL patterns (HTTPS-with-PAT and SSH-2222) inline
Enabled CORS on Forgejo so hephaestus.x (served from a different origin)
can hit /api/v1/repos/search — Access-Control-Allow-Origin: *, methods
GET+HEAD only, no credentials. That's the minimum for public listings and
matches how the API is meant to be used.
/forgejo/ is a byte-identical alias.
Only bitcoincash: was being stripped; bchtest: (chipnet) addresses ended up
producing preferred_username="bch_bchtest:qzew3dqcsj0g" — Forgejo rejected
that with "name is invalid ... must be valid alpha or numeric or dash(-_)
or dot characters" because of the colon, callback 500'd, session never
finished. Regex-strip any [a-z]+: prefix so all three prefix families
(bitcoincash, bchtest, bchreg) produce clean usernames.
Verified end-to-end with a Node smoke test signing a real chipnet challenge
with the main wallet from Argus/wallets.json:
bchtest:qzew3dqcsj0guwe5y3uxf9q2xs5ajgy9lca4z093cu
→ bch_qzew3dqcsj0guwe5y3ux (auto-provisioned in Forgejo)
→ 303 to dashboard, session live.
Site:
- Rename the "Tools" nav label to "Theseus" on every subpage. URL slug
/tools/ is kept intact so bookmarks and cross-links survive; the page's
own title + h1 rename to Theseus; homepage product card retitled.
- Remove the /tlds/ self-nav entry so its 7-item header matches every
other subpage (was 8 items, causing the same "header rearranges" glitch
Hephaestus had before).
Auth-proxy (fixes reported by a concurrent session working with a chipnet
wallet):
- verify.ts now auto-detects the CashAddr prefix (bitcoincash, bchtest,
bchreg) instead of hardcoding "bitcoincash". Chipnet wallets sign the
same message with the same key but display bchtest: addresses; the old
code compared their claim against a re-encoded bitcoincash: version and
always rejected. Same key material, different envelope.
- /challenge accepts any of the three known prefixes at the input gate.
- /verify accepts an optional `state` param in the request body — used as
a fallback if the challenge record didn't carry one (which happens when
a scripted caller runs the /verify step without passing state through
/challenge). Ensures RFC 6749 §4.1.2 compliance: the OAuth callback URL
always echoes state when the client provided one.
Behind Caddy's /auth/* → auth-proxy rewrite, absolute fetch('/challenge')
resolved to origin root and hit Forgejo instead of the auth-proxy, so every
real user got "challenge request failed" when clicking sign-in.
Same root cause as the earlier fix for the CSS/JS asset paths — relative
paths work under both direct (:4000) and prefixed (/auth/) mounts.
The **/.env.* catch-all was over-eager and swallowed .env.example too.
Add a specific !**/.env.example negation so template files (which document
the required vars for operators) stay tracked, while real .env.production
etc. stay ignored.
Flip LFS, attachments, packages, and repo-archive stores from local disk
to the 'hephaestus' bucket via s3.silentmode.st:8600 s3d gateway. Cert
there is a real LE cert (CN=navigate.st) that Go's minio driver trusts —
no skip-verify needed. Live git repos + Postgres stay on local SSD;
this only moves cold blobs onto Sia hosts.
Verified live: write→read→delete round-trip on the bucket, plus
Forgejo's own startup log confirming minio init for each store.
Add Hephaestus/caddy/Caddyfile - Caddy reverse-proxies both containers on
{$SITE_HOSTNAME} (from docker-compose .env): /auth/* -> auth-proxy:4000 with
the prefix stripped, / -> forgejo:3000 with a 2GB body cap for git push, LFS,
and release uploads. HTTPS via automatic Lets Encrypt (HTTP-01 on :80); SSH
git access stays on 2222 outside Caddy.
docker-compose.yml wires the new caddy service alongside the two existing
containers; auth-proxy/src/index.ts gets the minor upstream adjustment so
paths line up after Caddy strips the /auth prefix.
Broad-scope commit sweeping in work from parallel sessions plus this session's
dev-only utilities. No single unifying theme — this is the "commit everything
that's ready" pass. Grouped by area below.
AriadneResolver / mobile
* Small updates to BchFetcher, Bns, MainActivity, AriadneVpnService, and the
Android manifest — from a parallel mobile-resolver session.
* AriadneResolver/mobile/webpreview/ — new local dev webview (index.html +
server.mjs) for iterating on the mobile UI without a device.
Email / SnappyMail
* Email/snappymail-plugin/silentmode-addresses — new SnappyMail plugin
(README, CSS, PHP entry, JS) for surfacing @silentmode.st address
management inside the webmail UI.
Hephaestus (Forgejo + auth-proxy)
* auth-proxy/src/oidc.ts + docker-compose.yml updates.
* scripts/bootstrap-auth.sh — idempotent script that registers the wallet
auth-proxy as Forgejo's OIDC provider after `docker compose up -d`. All
secrets read from .env — no literals in the script.
TheseusNavigator / dev tools
* dev/list-tlds.mjs — enumerate every registered BNS name grouped by TLD via
our own indexer.
* dev/show-tlds-bch.mjs — dump the full records payload of the legacy
tlds.bch name (kept as a diagnostic for the list-in-one-NFT era).
Deviant sites + brand
* site/deviant/ — new microsites (anthemus, potidaea, brand, mindmap, main
index) plus the full brand kit under site/deviant/brand/ (logos, icons,
palette, social exports as SVG source + PNG renders).
* site-sirius-x/portal.html — updates.
Coordination
* _coordination/sessions/mobile-resolver.md — parallel-session notes.
Deliberately excluded from this commit:
* scratchpad/ — this session's temp drafts (Sia doc mockups, tlds UPD payloads).
* TheseusNavigator/_prev/ — ~372 MB of prior release binaries; belongs in
a separate artefacts store, not the git tree. Add to .gitignore next pass.