2026-09-08 11:59:44 +02:00
<!doctype html>
< html lang = "en" >
< head >
< meta charset = "utf-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1" >
< title > theseus.x — Extensions< / title >
< meta name = "description" content = "Signed over-the-air update endpoint for Theseus's bundled add-ons. Each entry is Ed25519-signed by the Silent Mode operator; verified on every install without waiting for a Theseus release." >
site-theseus-x: text-only sidebar on wide, icons on narrow, relative links
Sidebar redesign:
- Wide (>1180px): labels only, no icons, no border-left outline, no
background tint on active — just the label going acid green when
the section is in view. Sidebar moved down (+34px top padding) so
the first link doesn't crowd the topnav.
- Medium (720-1180px): icon rail only.
- Mobile (<720px): bottom bar with icons only.
- Background dropped from rgba(.82) to rgba(.42) — the backdrop-blur
already carries the separation, less panel-heavy against the hero.
- "On this page" section header dropped: the sidebar is close enough
to the topnav that the label reads as chrome rather than nav.
- Active state is now colour only (acid on the label); the left
border stripe and highlight background are gone.
Nav path fix (broken link on the silentmode.st mirror):
Root-absolute nav paths like /plug-ins/ resolved to
silentmode.st/plug-ins/ (404) instead of silentmode.st/theseus/plug-ins/
when a reader browsed the fallback mirror. Rewrote every topnav link,
cross-page prose link and favicon href to relative form
(plug-ins/, ../plug-ins/, assets/favicon.svg, …). Works on both the
BCNR name and the silentmode.st/theseus/ mount.
2026-09-20 17:07:17 +02:00
< link rel = "icon" href = "../assets/favicon.svg" type = "image/svg+xml" >
< link rel = "mask-icon" href = "../assets/favicon.svg" color = "#d6ff3d" >
2026-09-08 11:59:44 +02:00
< meta property = "og:type" content = "website" >
< meta property = "og:site_name" content = "theseus.x" >
< meta property = "og:title" content = "theseus.x — Extensions" >
< meta property = "og:description" content = "Signed OTA update endpoint for Theseus's bundled add-ons. Ed25519, no cert authority, no app-store gatekeeper." >
< meta property = "og:url" content = "https://theseus.x/extensions/" >
< style >
:root{
--bg:#0b0e14; --panel:#141a24; --panel2:#18202c; --line:rgba(255,255,255,.09);
--ink:#e7eaf1; --mut:#8b98a9; --dim:#5e6678; --acid:#d6ff3d;
--ok:#4fd1a5;
}
*{box-sizing:border-box}
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:900px;margin:0 auto;padding:0 1.2rem}
2026-09-20 16:17:08 +02:00
.topnav{position:fixed;top:0;left:0;right:0;z-index:20;display:flex;gap:2px;align-items:center;flex-wrap:wrap;
2026-09-20 16:33:58 +02:00
padding:10px 1.2rem;background:rgba(11,14,20,.88);backdrop-filter:blur(10px)}
2026-09-08 11:59:44 +02:00
.topnav .brand{font-weight:600;color:var(--ink);text-decoration:none;margin-right:14px;font-size:15px;letter-spacing:.2px;display:flex;align-items:center;gap:8px}
.topnav .brand .g{color:var(--acid)}
.topnav .brand svg{width:20px;height:20px}
2026-09-20 16:17:08 +02:00
.topnav a{color:var(--mut);text-decoration:none;padding:6px 12px;border-radius:8px;font-size:14px;
display:inline-flex;align-items:center;gap:6px}
2026-09-08 11:59:44 +02:00
.topnav a:hover{color:var(--ink);background:var(--panel)}
.topnav a.here{color:var(--acid);background:rgba(214,255,61,.08)}
2026-09-20 16:17:08 +02:00
.topnav a .g{color:var(--acid)}
.topnav a svg.tabicon{width:15px;height:15px;flex:none}
2026-09-20 15:54:01 +02:00
.topnav a.get{margin-left:auto;background:rgba(214,255,61,.10);color:var(--acid);font-weight:500}
.topnav a.get:hover{background:rgba(214,255,61,.18)}
site-theseus-x: adaptive edge sidebar (labels → icons → bottom bar)
Sidebar was a small strip in the middle of the page. Now it lives on
the left edge as a proper column, sized to be reachable — 220px full
mode with icon + label per link, on the operator's brand backdrop.
Breakpoints:
>1180px full sidebar, icon + label, "ON THIS PAGE" section header
<=1180px 64px icon rail, labels drop, tooltips on hover
<=720px bottom bar strip, icons only, spans page width
body padding-left carries the sidebar width so the topnav and page
content flow as one column beside the rail — no overlap on any width.
Home has 4 icons (What it is / Features / Download / Verify), Plug-ins
has 3 (Aegis / Ariadne's Thread / vs extensions), Extensions has 6
(Bundled / Community / Build & publish / Updates / Operator key /
Roadmap).
2026-09-20 16:11:57 +02:00
/* Adaptive edge nav: full-width panel at left edge on wide,
icon rail on medium, bottom bar with icons on mobile. */
2026-09-20 17:46:55 +02:00
:root{--sn-w:200px;--tn-h:52px}
body{padding-top:var(--tn-h)}
2026-09-20 16:17:08 +02:00
.sidenav{position:fixed;top:var(--tn-h);left:0;bottom:0;width:var(--sn-w);z-index:15;
2026-09-20 17:46:55 +02:00
background:transparent;padding:56px 12px 22px 18px;
overflow-y:auto;transition:width .15s ease;pointer-events:none}
site-theseus-x: adaptive edge sidebar (labels → icons → bottom bar)
Sidebar was a small strip in the middle of the page. Now it lives on
the left edge as a proper column, sized to be reachable — 220px full
mode with icon + label per link, on the operator's brand backdrop.
Breakpoints:
>1180px full sidebar, icon + label, "ON THIS PAGE" section header
<=1180px 64px icon rail, labels drop, tooltips on hover
<=720px bottom bar strip, icons only, spans page width
body padding-left carries the sidebar width so the topnav and page
content flow as one column beside the rail — no overlap on any width.
Home has 4 icons (What it is / Features / Download / Verify), Plug-ins
has 3 (Aegis / Ariadne's Thread / vs extensions), Extensions has 6
(Bundled / Community / Build & publish / Updates / Operator key /
Roadmap).
2026-09-20 16:11:57 +02:00
.sidenav a{display:flex;align-items:center;gap:14px;color:var(--mut);text-decoration:none;
2026-09-20 17:46:55 +02:00
padding:9px 12px;border-radius:10px;
font-size:14.5px;font-weight:500;opacity:.35;pointer-events:auto;
transition:opacity .12s,color .12s,background .12s,backdrop-filter .12s}
site-theseus-x: adaptive edge sidebar (labels → icons → bottom bar)
Sidebar was a small strip in the middle of the page. Now it lives on
the left edge as a proper column, sized to be reachable — 220px full
mode with icon + label per link, on the operator's brand backdrop.
Breakpoints:
>1180px full sidebar, icon + label, "ON THIS PAGE" section header
<=1180px 64px icon rail, labels drop, tooltips on hover
<=720px bottom bar strip, icons only, spans page width
body padding-left carries the sidebar width so the topnav and page
content flow as one column beside the rail — no overlap on any width.
Home has 4 icons (What it is / Features / Download / Verify), Plug-ins
has 3 (Aegis / Ariadne's Thread / vs extensions), Extensions has 6
(Bundled / Community / Build & publish / Updates / Operator key /
Roadmap).
2026-09-20 16:11:57 +02:00
.sidenav a .ic{flex:none;width:22px;font-size:18px;line-height:1;text-align:center;
site-theseus-x: text-only sidebar on wide, icons on narrow, relative links
Sidebar redesign:
- Wide (>1180px): labels only, no icons, no border-left outline, no
background tint on active — just the label going acid green when
the section is in view. Sidebar moved down (+34px top padding) so
the first link doesn't crowd the topnav.
- Medium (720-1180px): icon rail only.
- Mobile (<720px): bottom bar with icons only.
- Background dropped from rgba(.82) to rgba(.42) — the backdrop-blur
already carries the separation, less panel-heavy against the hero.
- "On this page" section header dropped: the sidebar is close enough
to the topnav that the label reads as chrome rather than nav.
- Active state is now colour only (acid on the label); the left
border stripe and highlight background are gone.
Nav path fix (broken link on the silentmode.st mirror):
Root-absolute nav paths like /plug-ins/ resolved to
silentmode.st/plug-ins/ (404) instead of silentmode.st/theseus/plug-ins/
when a reader browsed the fallback mirror. Rewrote every topnav link,
cross-page prose link and favicon href to relative form
(plug-ins/, ../plug-ins/, assets/favicon.svg, …). Works on both the
BCNR name and the silentmode.st/theseus/ mount.
2026-09-20 17:07:17 +02:00
display:none;justify-content:center;align-items:center}
site-theseus-x: adaptive edge sidebar (labels → icons → bottom bar)
Sidebar was a small strip in the middle of the page. Now it lives on
the left edge as a proper column, sized to be reachable — 220px full
mode with icon + label per link, on the operator's brand backdrop.
Breakpoints:
>1180px full sidebar, icon + label, "ON THIS PAGE" section header
<=1180px 64px icon rail, labels drop, tooltips on hover
<=720px bottom bar strip, icons only, spans page width
body padding-left carries the sidebar width so the topnav and page
content flow as one column beside the rail — no overlap on any width.
Home has 4 icons (What it is / Features / Download / Verify), Plug-ins
has 3 (Aegis / Ariadne's Thread / vs extensions), Extensions has 6
(Bundled / Community / Build & publish / Updates / Operator key /
Roadmap).
2026-09-20 16:11:57 +02:00
.sidenav a .lb{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
2026-09-20 17:46:55 +02:00
.sidenav a:hover{opacity:1;color:var(--ink);background:rgba(11,14,20,.72);backdrop-filter:blur(8px)}
.sidenav a.active{opacity:.85;color:var(--acid)}
.sidenav a.active:hover{opacity:1}
site-theseus-x: adaptive edge sidebar (labels → icons → bottom bar)
Sidebar was a small strip in the middle of the page. Now it lives on
the left edge as a proper column, sized to be reachable — 220px full
mode with icon + label per link, on the operator's brand backdrop.
Breakpoints:
>1180px full sidebar, icon + label, "ON THIS PAGE" section header
<=1180px 64px icon rail, labels drop, tooltips on hover
<=720px bottom bar strip, icons only, spans page width
body padding-left carries the sidebar width so the topnav and page
content flow as one column beside the rail — no overlap on any width.
Home has 4 icons (What it is / Features / Download / Verify), Plug-ins
has 3 (Aegis / Ariadne's Thread / vs extensions), Extensions has 6
(Bundled / Community / Build & publish / Updates / Operator key /
Roadmap).
2026-09-20 16:11:57 +02:00
@media (max-width:1180px){
:root{--sn-w:64px}
2026-09-20 16:17:08 +02:00
.sidenav{padding:22px 6px}
site-theseus-x: adaptive edge sidebar (labels → icons → bottom bar)
Sidebar was a small strip in the middle of the page. Now it lives on
the left edge as a proper column, sized to be reachable — 220px full
mode with icon + label per link, on the operator's brand backdrop.
Breakpoints:
>1180px full sidebar, icon + label, "ON THIS PAGE" section header
<=1180px 64px icon rail, labels drop, tooltips on hover
<=720px bottom bar strip, icons only, spans page width
body padding-left carries the sidebar width so the topnav and page
content flow as one column beside the rail — no overlap on any width.
Home has 4 icons (What it is / Features / Download / Verify), Plug-ins
has 3 (Aegis / Ariadne's Thread / vs extensions), Extensions has 6
(Bundled / Community / Build & publish / Updates / Operator key /
Roadmap).
2026-09-20 16:11:57 +02:00
.sidenav .lbl{display:none}
.sidenav a{justify-content:center;padding:12px 4px;gap:0}
site-theseus-x: text-only sidebar on wide, icons on narrow, relative links
Sidebar redesign:
- Wide (>1180px): labels only, no icons, no border-left outline, no
background tint on active — just the label going acid green when
the section is in view. Sidebar moved down (+34px top padding) so
the first link doesn't crowd the topnav.
- Medium (720-1180px): icon rail only.
- Mobile (<720px): bottom bar with icons only.
- Background dropped from rgba(.82) to rgba(.42) — the backdrop-blur
already carries the separation, less panel-heavy against the hero.
- "On this page" section header dropped: the sidebar is close enough
to the topnav that the label reads as chrome rather than nav.
- Active state is now colour only (acid on the label); the left
border stripe and highlight background are gone.
Nav path fix (broken link on the silentmode.st mirror):
Root-absolute nav paths like /plug-ins/ resolved to
silentmode.st/plug-ins/ (404) instead of silentmode.st/theseus/plug-ins/
when a reader browsed the fallback mirror. Rewrote every topnav link,
cross-page prose link and favicon href to relative form
(plug-ins/, ../plug-ins/, assets/favicon.svg, …). Works on both the
BCNR name and the silentmode.st/theseus/ mount.
2026-09-20 17:07:17 +02:00
.sidenav a .ic{display:inline-flex}
site-theseus-x: adaptive edge sidebar (labels → icons → bottom bar)
Sidebar was a small strip in the middle of the page. Now it lives on
the left edge as a proper column, sized to be reachable — 220px full
mode with icon + label per link, on the operator's brand backdrop.
Breakpoints:
>1180px full sidebar, icon + label, "ON THIS PAGE" section header
<=1180px 64px icon rail, labels drop, tooltips on hover
<=720px bottom bar strip, icons only, spans page width
body padding-left carries the sidebar width so the topnav and page
content flow as one column beside the rail — no overlap on any width.
Home has 4 icons (What it is / Features / Download / Verify), Plug-ins
has 3 (Aegis / Ariadne's Thread / vs extensions), Extensions has 6
(Bundled / Community / Build & publish / Updates / Operator key /
Roadmap).
2026-09-20 16:11:57 +02:00
.sidenav a .lb{display:none}
}
@media (max-width:720px){
:root{--sn-w:0px}
body{padding-left:0;padding-bottom:64px}
.sidenav{top:auto;bottom:0;left:0;right:0;width:100%;height:auto;
site-theseus-x: text-only sidebar on wide, icons on narrow, relative links
Sidebar redesign:
- Wide (>1180px): labels only, no icons, no border-left outline, no
background tint on active — just the label going acid green when
the section is in view. Sidebar moved down (+34px top padding) so
the first link doesn't crowd the topnav.
- Medium (720-1180px): icon rail only.
- Mobile (<720px): bottom bar with icons only.
- Background dropped from rgba(.82) to rgba(.42) — the backdrop-blur
already carries the separation, less panel-heavy against the hero.
- "On this page" section header dropped: the sidebar is close enough
to the topnav that the label reads as chrome rather than nav.
- Active state is now colour only (acid on the label); the left
border stripe and highlight background are gone.
Nav path fix (broken link on the silentmode.st mirror):
Root-absolute nav paths like /plug-ins/ resolved to
silentmode.st/plug-ins/ (404) instead of silentmode.st/theseus/plug-ins/
when a reader browsed the fallback mirror. Rewrote every topnav link,
cross-page prose link and favicon href to relative form
(plug-ins/, ../plug-ins/, assets/favicon.svg, …). Works on both the
BCNR name and the silentmode.st/theseus/ mount.
2026-09-20 17:07:17 +02:00
padding:4px 4px;flex-direction:row;background:rgba(11,14,20,.52);
site-theseus-x: adaptive edge sidebar (labels → icons → bottom bar)
Sidebar was a small strip in the middle of the page. Now it lives on
the left edge as a proper column, sized to be reachable — 220px full
mode with icon + label per link, on the operator's brand backdrop.
Breakpoints:
>1180px full sidebar, icon + label, "ON THIS PAGE" section header
<=1180px 64px icon rail, labels drop, tooltips on hover
<=720px bottom bar strip, icons only, spans page width
body padding-left carries the sidebar width so the topnav and page
content flow as one column beside the rail — no overlap on any width.
Home has 4 icons (What it is / Features / Download / Verify), Plug-ins
has 3 (Aegis / Ariadne's Thread / vs extensions), Extensions has 6
(Bundled / Community / Build & publish / Updates / Operator key /
Roadmap).
2026-09-20 16:11:57 +02:00
display:flex;justify-content:space-around;overflow-x:auto}
.sidenav .lbl{display:none}
site-theseus-x: text-only sidebar on wide, icons on narrow, relative links
Sidebar redesign:
- Wide (>1180px): labels only, no icons, no border-left outline, no
background tint on active — just the label going acid green when
the section is in view. Sidebar moved down (+34px top padding) so
the first link doesn't crowd the topnav.
- Medium (720-1180px): icon rail only.
- Mobile (<720px): bottom bar with icons only.
- Background dropped from rgba(.82) to rgba(.42) — the backdrop-blur
already carries the separation, less panel-heavy against the hero.
- "On this page" section header dropped: the sidebar is close enough
to the topnav that the label reads as chrome rather than nav.
- Active state is now colour only (acid on the label); the left
border stripe and highlight background are gone.
Nav path fix (broken link on the silentmode.st mirror):
Root-absolute nav paths like /plug-ins/ resolved to
silentmode.st/plug-ins/ (404) instead of silentmode.st/theseus/plug-ins/
when a reader browsed the fallback mirror. Rewrote every topnav link,
cross-page prose link and favicon href to relative form
(plug-ins/, ../plug-ins/, assets/favicon.svg, …). Works on both the
BCNR name and the silentmode.st/theseus/ mount.
2026-09-20 17:07:17 +02:00
.sidenav a{flex:1;min-width:56px;padding:10px 6px;justify-content:center;gap:0}
.sidenav a .ic{display:inline-flex}
site-theseus-x: adaptive edge sidebar (labels → icons → bottom bar)
Sidebar was a small strip in the middle of the page. Now it lives on
the left edge as a proper column, sized to be reachable — 220px full
mode with icon + label per link, on the operator's brand backdrop.
Breakpoints:
>1180px full sidebar, icon + label, "ON THIS PAGE" section header
<=1180px 64px icon rail, labels drop, tooltips on hover
<=720px bottom bar strip, icons only, spans page width
body padding-left carries the sidebar width so the topnav and page
content flow as one column beside the rail — no overlap on any width.
Home has 4 icons (What it is / Features / Download / Verify), Plug-ins
has 3 (Aegis / Ariadne's Thread / vs extensions), Extensions has 6
(Bundled / Community / Build & publish / Updates / Operator key /
Roadmap).
2026-09-20 16:11:57 +02:00
.sidenav a .lb{display:none}
}
2026-09-20 15:54:01 +02:00
2026-09-08 11:59:44 +02:00
header.hero{text-align:center;padding:3.5rem 1.2rem 1rem}
h1{font-size:clamp(1.8rem,4.5vw,2.4rem);margin:.6rem 0 .3rem;letter-spacing:-.3px}
h1 .g{color:var(--acid)}
.tag{color:var(--mut);font-size:1.02rem;max-width:640px;margin:0 auto}
2026-09-20 15:54:01 +02:00
section{padding:2rem 0;border-top:1px solid var(--line);margin-top:1.6rem;scroll-margin-top:72px}
2026-09-08 11:59:44 +02:00
section:first-of-type{border-top:none;margin-top:1rem}
h2{font-size:1.35rem;margin:0 0 .5rem}
.lede{color:var(--mut);margin:0 0 1.2rem;max-width:720px}
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:12.5px;color:var(--ink);margin:.8rem 0}
.ext{background:var(--panel);border:1px solid var(--line);border-radius:14px;padding:20px 22px;margin:1rem 0}
.ext h3{margin:0 0 .3rem;font-size:1.15rem;display:flex;align-items:center;gap:10px}
.ext h3 .icon{font-size:1.4rem}
.ext .cur{color:var(--acid);font-size:12px;font-weight:600;letter-spacing:.14em;text-transform:uppercase}
.ext .desc{color:var(--mut);font-size:14px;margin:.3rem 0 .8rem}
.ext .verifybox{margin-top:.9rem;padding-top:.8rem;border-top:1px solid var(--line);font-size:11.5px;color:var(--dim)}
.ext .verifybox .lbl{color:var(--mut);font-size:12px;margin-bottom:6px}
.ext .h{display:flex;gap:8px;flex-wrap:wrap;align-items:baseline;margin-top:4px}
.ext .h b{color:var(--mut);font-weight:600;min-width:70px}
.ext .h code{font-family:ui-monospace,monospace;font-size:10.5px;color:#c9d4e3;word-break:break-all;background:transparent;border:none;padding:0}
.ext .meta{color:var(--dim);font-size:12.5px;margin-top:.4rem}
.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:1.4rem 0}
.note b{color:var(--ink)}
.pubkey{background:#0e131b;border:1px solid var(--line);border-radius:8px;padding:10px 12px;
font-family:ui-monospace,monospace;font-size:11px;color:#c9d4e3;word-break:break-all;margin:.6rem 0}
.flow{background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:16px 20px;margin-top:1rem;color:var(--mut);font-size:14px}
.flow ol{margin:0;padding-left:20px}
.flow li{margin:.4rem 0}
.flow b{color:var(--ink)}
footer{color:var(--dim);font-size:12.5px;margin:3rem 0 2rem;text-align:center}
footer a{color:var(--mut)}
< / style >
< / head >
< body >
< nav class = "topnav" >
site-theseus-x: text-only sidebar on wide, icons on narrow, relative links
Sidebar redesign:
- Wide (>1180px): labels only, no icons, no border-left outline, no
background tint on active — just the label going acid green when
the section is in view. Sidebar moved down (+34px top padding) so
the first link doesn't crowd the topnav.
- Medium (720-1180px): icon rail only.
- Mobile (<720px): bottom bar with icons only.
- Background dropped from rgba(.82) to rgba(.42) — the backdrop-blur
already carries the separation, less panel-heavy against the hero.
- "On this page" section header dropped: the sidebar is close enough
to the topnav that the label reads as chrome rather than nav.
- Active state is now colour only (acid on the label); the left
border stripe and highlight background are gone.
Nav path fix (broken link on the silentmode.st mirror):
Root-absolute nav paths like /plug-ins/ resolved to
silentmode.st/plug-ins/ (404) instead of silentmode.st/theseus/plug-ins/
when a reader browsed the fallback mirror. Rewrote every topnav link,
cross-page prose link and favicon href to relative form
(plug-ins/, ../plug-ins/, assets/favicon.svg, …). Works on both the
BCNR name and the silentmode.st/theseus/ mount.
2026-09-20 17:07:17 +02:00
< a class = "brand" href = "../" >
2026-09-08 11:59:44 +02:00
< svg viewBox = "0 0 64 64" aria-hidden = "true" >
< rect width = "64" height = "64" rx = "12" fill = "#0b0e14" / >
< path d = "M32 6 L38 32 L26 32 Z" fill = "#e04e4e" / >
< path d = "M38 32 L32 58 L26 32 Z" fill = "#d6ff3d" / >
< path d = "M6 32 L32 27 L58 32 L32 37 Z" fill = "#d6ff3d" opacity = ".55" / >
< circle cx = "32" cy = "32" r = "3" fill = "#0b0e14" / >
< / svg >
2026-09-20 15:54:01 +02:00
< span > Theseus< span class = "g" > .X< / span > < / span >
2026-09-08 11:59:44 +02:00
< / a >
site-theseus-x: text-only sidebar on wide, icons on narrow, relative links
Sidebar redesign:
- Wide (>1180px): labels only, no icons, no border-left outline, no
background tint on active — just the label going acid green when
the section is in view. Sidebar moved down (+34px top padding) so
the first link doesn't crowd the topnav.
- Medium (720-1180px): icon rail only.
- Mobile (<720px): bottom bar with icons only.
- Background dropped from rgba(.82) to rgba(.42) — the backdrop-blur
already carries the separation, less panel-heavy against the hero.
- "On this page" section header dropped: the sidebar is close enough
to the topnav that the label reads as chrome rather than nav.
- Active state is now colour only (acid on the label); the left
border stripe and highlight background are gone.
Nav path fix (broken link on the silentmode.st mirror):
Root-absolute nav paths like /plug-ins/ resolved to
silentmode.st/plug-ins/ (404) instead of silentmode.st/theseus/plug-ins/
when a reader browsed the fallback mirror. Rewrote every topnav link,
cross-page prose link and favicon href to relative form
(plug-ins/, ../plug-ins/, assets/favicon.svg, …). Works on both the
BCNR name and the silentmode.st/theseus/ mount.
2026-09-20 17:07:17 +02:00
< a href = "../plug-ins/" > Plug-ins< / a >
2026-09-08 11:59:44 +02:00
< a class = "here" href = "./" > Extensions< / a >
2026-09-20 16:33:58 +02:00
< a href = "https://sirius.x/" title = "Register a BCNR name" > < svg class = "tabicon" viewBox = "0 0 64 64" aria-hidden = "true" > < rect width = "64" height = "64" rx = "12" fill = "#0b0e14" / > < path d = "M32 4 L36.4 27.6 L60 32 L36.4 36.4 L32 60 L27.6 36.4 L4 32 L27.6 27.6 Z" fill = "#d6ff3d" / > < / svg > < span > Sirius< span class = "g" > .X< / span > < / span > < / a >
site-theseus-x: text-only sidebar on wide, icons on narrow, relative links
Sidebar redesign:
- Wide (>1180px): labels only, no icons, no border-left outline, no
background tint on active — just the label going acid green when
the section is in view. Sidebar moved down (+34px top padding) so
the first link doesn't crowd the topnav.
- Medium (720-1180px): icon rail only.
- Mobile (<720px): bottom bar with icons only.
- Background dropped from rgba(.82) to rgba(.42) — the backdrop-blur
already carries the separation, less panel-heavy against the hero.
- "On this page" section header dropped: the sidebar is close enough
to the topnav that the label reads as chrome rather than nav.
- Active state is now colour only (acid on the label); the left
border stripe and highlight background are gone.
Nav path fix (broken link on the silentmode.st mirror):
Root-absolute nav paths like /plug-ins/ resolved to
silentmode.st/plug-ins/ (404) instead of silentmode.st/theseus/plug-ins/
when a reader browsed the fallback mirror. Rewrote every topnav link,
cross-page prose link and favicon href to relative form
(plug-ins/, ../plug-ins/, assets/favicon.svg, …). Works on both the
BCNR name and the silentmode.st/theseus/ mount.
2026-09-20 17:07:17 +02:00
< a class = "get" href = "../#download" > Get Theseus< / a >
2026-09-08 11:59:44 +02:00
< / nav >
2026-09-20 15:54:01 +02:00
< aside class = "sidenav" aria-label = "On this page" >
site-theseus-x: adaptive edge sidebar (labels → icons → bottom bar)
Sidebar was a small strip in the middle of the page. Now it lives on
the left edge as a proper column, sized to be reachable — 220px full
mode with icon + label per link, on the operator's brand backdrop.
Breakpoints:
>1180px full sidebar, icon + label, "ON THIS PAGE" section header
<=1180px 64px icon rail, labels drop, tooltips on hover
<=720px bottom bar strip, icons only, spans page width
body padding-left carries the sidebar width so the topnav and page
content flow as one column beside the rail — no overlap on any width.
Home has 4 icons (What it is / Features / Download / Verify), Plug-ins
has 3 (Aegis / Ariadne's Thread / vs extensions), Extensions has 6
(Bundled / Community / Build & publish / Updates / Operator key /
Roadmap).
2026-09-20 16:11:57 +02:00
< a href = "#bundled" title = "Bundled" > < span class = "ic" aria-hidden = "true" > 📦< / span > < span class = "lb" > Bundled< / span > < / a >
< a href = "#community" title = "Community" > < span class = "ic" aria-hidden = "true" > 👥< / span > < span class = "lb" > Community< / span > < / a >
< a href = "#build" title = "Build & publish" > < span class = "ic" aria-hidden = "true" > 🔨< / span > < span class = "lb" > Build & publish< / span > < / a >
< a href = "#updates" title = "How updates work" > < span class = "ic" aria-hidden = "true" > 🔄< / span > < span class = "lb" > How updates work< / span > < / a >
< a href = "#operator-key" title = "Operator key" > < span class = "ic" aria-hidden = "true" > 🔑< / span > < span class = "lb" > Operator key< / span > < / a >
< a href = "#roadmap" title = "Roadmap" > < span class = "ic" aria-hidden = "true" > 🗺< / span > < span class = "lb" > Roadmap< / span > < / a >
2026-09-20 15:54:01 +02:00
< / aside >
2026-09-08 11:59:44 +02:00
< header class = "hero" >
< h1 > Theseus < span class = "g" > Extensions< / span > < / h1 >
feat: community extensions — publish with a BCDN name, install from Settings, theseus.x catalog
Anyone who owns a BCDN name can now publish a Theseus extension, and every
Theseus can install it with the publisher's signature verified locally.
Gateway (Argus/src/gateway/public-gateway.mjs):
PUT /api/ext/<name>/<id>/<version> takes the gzipped tar, checks two BCH
message signatures against the name's current NFT owner (one authorises
the upload, one is stored in the channel), inspects the package
(addon.json at the root, id/version/main match, 8 MB cap), enforces
first-publisher ownership of an id and monotonic versions, and writes the
tarball, the extension's updates.json and community/catalog.json to Sia.
GET /api/ext/catalog reads the catalog back with CORS.
Theseus:
lib/publisher-sig.mjs recovers the signer of a channel entry; main.js
compares it with the publisher name's owner from Theseus's own chain
index before installing or updating, so neither the relay nor a tampered
catalog can pass off code under a trusted name. addon-updater.js gains
installCommunity() and accepts publisher-signed entries in the regular
update check (operator Ed25519 entries unchanged). Settings › Extensions
shows the community catalog with Install / Update; Settings › Plug-ins
links to theseus.x/plug-ins.
theseus.x:
/plug-ins/ is a separate page for the first-party plug-ins (Aegis,
Ariadne's Thread) with live versions and hashes; /extensions/ lists the
bundled extensions, the community catalog, and how to build and publish;
/extensions/publish/ signs and uploads a package in the browser with the
wallet that holds the publisher's name (session helper + wallet bundle
copied alongside).
2026-09-20 15:26:30 +02:00
< p class = "tag" > Add-ons for Theseus Navigator — the ones that ship in the box and the ones anyone can
publish. Every package is signed (by the Silent Mode operator, or by the publisher's own BCDN name)
and verified on your device before install. No cert authority, no app-store gatekeeper.
site-theseus-x: text-only sidebar on wide, icons on narrow, relative links
Sidebar redesign:
- Wide (>1180px): labels only, no icons, no border-left outline, no
background tint on active — just the label going acid green when
the section is in view. Sidebar moved down (+34px top padding) so
the first link doesn't crowd the topnav.
- Medium (720-1180px): icon rail only.
- Mobile (<720px): bottom bar with icons only.
- Background dropped from rgba(.82) to rgba(.42) — the backdrop-blur
already carries the separation, less panel-heavy against the hero.
- "On this page" section header dropped: the sidebar is close enough
to the topnav that the label reads as chrome rather than nav.
- Active state is now colour only (acid on the label); the left
border stripe and highlight background are gone.
Nav path fix (broken link on the silentmode.st mirror):
Root-absolute nav paths like /plug-ins/ resolved to
silentmode.st/plug-ins/ (404) instead of silentmode.st/theseus/plug-ins/
when a reader browsed the fallback mirror. Rewrote every topnav link,
cross-page prose link and favicon href to relative form
(plug-ins/, ../plug-ins/, assets/favicon.svg, …). Works on both the
BCNR name and the silentmode.st/theseus/ mount.
2026-09-20 17:07:17 +02:00
First-party plug-ins (Aegis, Ariadne's Thread) have their < a href = "../plug-ins/" > own page< / a > .< / p >
2026-09-08 11:59:44 +02:00
< / header >
< div class = "wrap" >
feat: community extensions — publish with a BCDN name, install from Settings, theseus.x catalog
Anyone who owns a BCDN name can now publish a Theseus extension, and every
Theseus can install it with the publisher's signature verified locally.
Gateway (Argus/src/gateway/public-gateway.mjs):
PUT /api/ext/<name>/<id>/<version> takes the gzipped tar, checks two BCH
message signatures against the name's current NFT owner (one authorises
the upload, one is stored in the channel), inspects the package
(addon.json at the root, id/version/main match, 8 MB cap), enforces
first-publisher ownership of an id and monotonic versions, and writes the
tarball, the extension's updates.json and community/catalog.json to Sia.
GET /api/ext/catalog reads the catalog back with CORS.
Theseus:
lib/publisher-sig.mjs recovers the signer of a channel entry; main.js
compares it with the publisher name's owner from Theseus's own chain
index before installing or updating, so neither the relay nor a tampered
catalog can pass off code under a trusted name. addon-updater.js gains
installCommunity() and accepts publisher-signed entries in the regular
update check (operator Ed25519 entries unchanged). Settings › Extensions
shows the community catalog with Install / Update; Settings › Plug-ins
links to theseus.x/plug-ins.
theseus.x:
/plug-ins/ is a separate page for the first-party plug-ins (Aegis,
Ariadne's Thread) with live versions and hashes; /extensions/ lists the
bundled extensions, the community catalog, and how to build and publish;
/extensions/publish/ signs and uploads a package in the browser with the
wallet that holds the publisher's name (session helper + wallet bundle
copied alongside).
2026-09-20 15:26:30 +02:00
< section id = "bundled" >
< h2 > Bundled extensions< / h2 >
< p class = "lede" > Ship with every Theseus build and update over the operator-signed channel. Versions and hashes
are read from each add-on's signed < code > updates.json< / code > when this page loads.< / p >
2026-09-20 14:39:07 +02:00
< div class = "ext" id = "screenshot" data-ext = "screenshot" >
< h3 > < span class = "icon" > 📸< / span > Screenshot < span class = "cur" style = "margin-left:auto" > current < span data-live = "version" > 0.6.5< / span > < / span > < / h3 >
2026-09-08 11:59:44 +02:00
< div class = "desc" > Capture the current tab — visible viewport, entire scrollable page, or a rectangle
2026-09-20 14:39:07 +02:00
you draw. The capture opens in a full-tab editor: crop, annotate, line tool, resizable text,
redact, save.< / div >
feat: community extensions — publish with a BCDN name, install from Settings, theseus.x catalog
Anyone who owns a BCDN name can now publish a Theseus extension, and every
Theseus can install it with the publisher's signature verified locally.
Gateway (Argus/src/gateway/public-gateway.mjs):
PUT /api/ext/<name>/<id>/<version> takes the gzipped tar, checks two BCH
message signatures against the name's current NFT owner (one authorises
the upload, one is stored in the channel), inspects the package
(addon.json at the root, id/version/main match, 8 MB cap), enforces
first-publisher ownership of an id and monotonic versions, and writes the
tarball, the extension's updates.json and community/catalog.json to Sia.
GET /api/ext/catalog reads the catalog back with CORS.
Theseus:
lib/publisher-sig.mjs recovers the signer of a channel entry; main.js
compares it with the publisher name's owner from Theseus's own chain
index before installing or updating, so neither the relay nor a tampered
catalog can pass off code under a trusted name. addon-updater.js gains
installCommunity() and accepts publisher-signed entries in the regular
update check (operator Ed25519 entries unchanged). Settings › Extensions
shows the community catalog with Install / Update; Settings › Plug-ins
links to theseus.x/plug-ins.
theseus.x:
/plug-ins/ is a separate page for the first-party plug-ins (Aegis,
Ariadne's Thread) with live versions and hashes; /extensions/ lists the
bundled extensions, the community catalog, and how to build and publish;
/extensions/publish/ signs and uploads a package in the browser with the
wallet that holds the publisher's name (session helper + wallet bundle
copied alongside).
2026-09-20 15:26:30 +02:00
< div class = "meta" > Settings › Extensions · < span data-live = "count" > < / span > < / div >
2026-09-08 11:59:44 +02:00
< div class = "verifybox" >
< div class = "lbl" > Signed update manifest — SHA-256 verified before install< / div >
2026-09-20 14:39:07 +02:00
< div class = "h" > < b > updates.json< / b > < code > < a href = "./screenshot/updates.json" > theseus.x/extensions/screenshot/updates.json< / a > < / code > < / div >
< div class = "h" > < b > Tarball< / b > < code > < a data-live = "url" href = "./screenshot/screenshot-0.6.5.tar.gz" > screenshot-0.6.5.tar.gz< / a > < / code > < / div >
< div class = "h" > < b > sha256< / b > < code data-live = "sha256" > 87ae730d329ff9f552bbf513efba19bd14bb016bb90e24f7b62868434dadda60< / code > < / div >
2026-09-08 11:59:44 +02:00
< / div >
< / div >
2026-09-20 14:39:07 +02:00
< div class = "ext" id = "notepad" >
< h3 > < span class = "icon" > 📝< / span > Notepad < span class = "cur" style = "margin-left:auto" > bundled 0.1.0< / span > < / h3 >
< div class = "desc" > Right-sidebar notes. Text lives on this machine only and autosaves as you type.< / div >
feat: community extensions — publish with a BCDN name, install from Settings, theseus.x catalog
Anyone who owns a BCDN name can now publish a Theseus extension, and every
Theseus can install it with the publisher's signature verified locally.
Gateway (Argus/src/gateway/public-gateway.mjs):
PUT /api/ext/<name>/<id>/<version> takes the gzipped tar, checks two BCH
message signatures against the name's current NFT owner (one authorises
the upload, one is stored in the channel), inspects the package
(addon.json at the root, id/version/main match, 8 MB cap), enforces
first-publisher ownership of an id and monotonic versions, and writes the
tarball, the extension's updates.json and community/catalog.json to Sia.
GET /api/ext/catalog reads the catalog back with CORS.
Theseus:
lib/publisher-sig.mjs recovers the signer of a channel entry; main.js
compares it with the publisher name's owner from Theseus's own chain
index before installing or updating, so neither the relay nor a tampered
catalog can pass off code under a trusted name. addon-updater.js gains
installCommunity() and accepts publisher-signed entries in the regular
update check (operator Ed25519 entries unchanged). Settings › Extensions
shows the community catalog with Install / Update; Settings › Plug-ins
links to theseus.x/plug-ins.
theseus.x:
/plug-ins/ is a separate page for the first-party plug-ins (Aegis,
Ariadne's Thread) with live versions and hashes; /extensions/ lists the
bundled extensions, the community catalog, and how to build and publish;
/extensions/publish/ signs and uploads a package in the browser with the
wallet that holds the publisher's name (session helper + wallet bundle
copied alongside).
2026-09-20 15:26:30 +02:00
< div class = "meta" > Settings › Extensions · no update channel yet — ships with each Theseus release.< / div >
2026-09-20 14:39:07 +02:00
< / div >
site-theseus-x/extensions: list PDF Editor 0.1.0 + Word editor 0.1.0
Two first-party extensions shipped without ever appearing on the
catalog page. Added:
📄 PDF Editor — bundled, full-tab PDF reader/annotator (highlight,
mark up, reorder/rotate/drop pages, fill forms, save a new copy;
annotations written as real PDF content). Opens from the toolbar
menu and from the "Open PDF in editor" right-click on any link.
📝 Word editor — .docx open/edit/save in a full Theseus tab.
Ribbon-style formatting, tables, lists, images and links;
headers, footers, footnotes, page setup and the document's own
styles are preserved through a round-trip. Listed as a community
extension (Settings › Extensions › Community); channel path
mirrors the addon.json updateURL (extensions/community/docx-editor).
Both cards carry data-ext hooks so the manifest-fill script picks up
version + tarball + sha256 from a signed updates.json when the
channel is published — for now the baked-in 0.1.0 is the fallback.
2026-09-21 01:39:55 +02:00
< div class = "ext" id = "pdf-editor" data-ext = "pdf-editor" >
< h3 > < span class = "icon" > 📄< / span > PDF Editor < span class = "cur" style = "margin-left:auto" > current < span data-live = "version" > 0.1.0< / span > < / span > < / h3 >
< div class = "desc" > Open a PDF in a full tab — read, highlight, mark up, reorder or rotate or drop pages,
fill form fields, save a new copy. Annotations are written as real PDF content, the original
is never touched. Opens from the toolbar's PDF Editor menu or the right-click < i > Open PDF in editor< / i >
on any link.< / div >
< div class = "meta" > Settings › Extensions · < span data-live = "count" > signed update channel< / span > < / div >
< div class = "verifybox" >
< div class = "lbl" > Signed update manifest — SHA-256 verified before install< / div >
< div class = "h" > < b > updates.json< / b > < code > < a href = "./pdf-editor/updates.json" > theseus.x/extensions/pdf-editor/updates.json< / a > < / code > < / div >
< div class = "h" > < b > Tarball< / b > < code > < a data-live = "url" href = "./pdf-editor/pdf-editor-0.1.0.tar.gz" > pdf-editor-0.1.0.tar.gz< / a > < / code > < / div >
< div class = "h" > < b > sha256< / b > < code data-live = "sha256" > —< / code > < / div >
< / div >
< / div >
feat: community extensions — publish with a BCDN name, install from Settings, theseus.x catalog
Anyone who owns a BCDN name can now publish a Theseus extension, and every
Theseus can install it with the publisher's signature verified locally.
Gateway (Argus/src/gateway/public-gateway.mjs):
PUT /api/ext/<name>/<id>/<version> takes the gzipped tar, checks two BCH
message signatures against the name's current NFT owner (one authorises
the upload, one is stored in the channel), inspects the package
(addon.json at the root, id/version/main match, 8 MB cap), enforces
first-publisher ownership of an id and monotonic versions, and writes the
tarball, the extension's updates.json and community/catalog.json to Sia.
GET /api/ext/catalog reads the catalog back with CORS.
Theseus:
lib/publisher-sig.mjs recovers the signer of a channel entry; main.js
compares it with the publisher name's owner from Theseus's own chain
index before installing or updating, so neither the relay nor a tampered
catalog can pass off code under a trusted name. addon-updater.js gains
installCommunity() and accepts publisher-signed entries in the regular
update check (operator Ed25519 entries unchanged). Settings › Extensions
shows the community catalog with Install / Update; Settings › Plug-ins
links to theseus.x/plug-ins.
theseus.x:
/plug-ins/ is a separate page for the first-party plug-ins (Aegis,
Ariadne's Thread) with live versions and hashes; /extensions/ lists the
bundled extensions, the community catalog, and how to build and publish;
/extensions/publish/ signs and uploads a package in the browser with the
wallet that holds the publisher's name (session helper + wallet bundle
copied alongside).
2026-09-20 15:26:30 +02:00
< / section >
< section id = "community" >
< h2 > Community extensions< / h2 >
< p class = "lede" > Published by BCDN name holders, signed with the wallet that holds the name. Theseus installs them
from < b > Settings › Extensions › Community< / b > and re-checks every signature against the name's current owner
in its own chain index — the relay cannot substitute code under a trusted name.< / p >
< div id = "communityList" > < div class = "ext" style = "color:var(--dim)" > Loading the catalog…< / div > < / div >
< div class = "note" > < b > Trust, stated plainly.< / b > A community extension runs with the same access as any add-on —
treat one like an unsigned executable from that publisher. The signature proves < i > who< / i > published it,
not that it is safe.< / div >
< / section >
2026-09-20 14:39:07 +02:00
feat: community extensions — publish with a BCDN name, install from Settings, theseus.x catalog
Anyone who owns a BCDN name can now publish a Theseus extension, and every
Theseus can install it with the publisher's signature verified locally.
Gateway (Argus/src/gateway/public-gateway.mjs):
PUT /api/ext/<name>/<id>/<version> takes the gzipped tar, checks two BCH
message signatures against the name's current NFT owner (one authorises
the upload, one is stored in the channel), inspects the package
(addon.json at the root, id/version/main match, 8 MB cap), enforces
first-publisher ownership of an id and monotonic versions, and writes the
tarball, the extension's updates.json and community/catalog.json to Sia.
GET /api/ext/catalog reads the catalog back with CORS.
Theseus:
lib/publisher-sig.mjs recovers the signer of a channel entry; main.js
compares it with the publisher name's owner from Theseus's own chain
index before installing or updating, so neither the relay nor a tampered
catalog can pass off code under a trusted name. addon-updater.js gains
installCommunity() and accepts publisher-signed entries in the regular
update check (operator Ed25519 entries unchanged). Settings › Extensions
shows the community catalog with Install / Update; Settings › Plug-ins
links to theseus.x/plug-ins.
theseus.x:
/plug-ins/ is a separate page for the first-party plug-ins (Aegis,
Ariadne's Thread) with live versions and hashes; /extensions/ lists the
bundled extensions, the community catalog, and how to build and publish;
/extensions/publish/ signs and uploads a package in the browser with the
wallet that holds the publisher's name (session helper + wallet bundle
copied alongside).
2026-09-20 15:26:30 +02:00
< section id = "build" >
< h2 > Build and publish your own< / h2 >
< p class = "lede" > An extension is a folder with an < code > addon.json< / code > and a main script. Package it, sign it with
the wallet that holds one of your BCDN names, and it is listed above within a minute. Nothing to apply for.< / p >
< div class = "flow" >
< ol >
< li > < b > Write it.< / b > The manifest and a CommonJS entry that exports < code > activate(api)< / code > :
< pre > my-ext/
addon.json {"id":"my-ext","name":"My Extension","version":"1.0.0",
"description":"…","author":"you.bch","icon":"✨",
"main":"index.js","capabilities":["sidebar-panel"]}
index.js module.exports = { activate(api) {
api.registerSidebarPanel({ id:"main", title:"My Extension", icon:"✨", page:"panel.html" });
} };
panel.html plain HTML, runs in the sidebar; window.silentmode.storage for local state< / pre >
The bundled < a href = "https://code.silentmode.st/silentmode/theseus/src/branch/master/TheseusNavigator/bundled-addons/notepad" > Notepad< / a >
is the smallest complete example; < a href = "https://code.silentmode.st/silentmode/theseus/src/branch/master/TheseusNavigator/addons-host.js" > addons-host.js< / a >
is the full API. < code > id< / code > is < code > [a-z0-9._-]< / code > , 2– 64 chars, and belongs to the first name that publishes it.< / li >
< li > < b > Test it locally.< / b > Settings › Extensions › < i > Open extensions folder< / i > , drop the folder in, < i > Reload< / i > .< / li >
< li > < b > Package it.< / b > < code > tar -czf my-ext-1.0.0.tar.gz -C my-ext .< / code > (max 8 MB; < code > addon.json< / code > at the root or in a single top folder).< / li >
< li > < b > Publish it.< / b > Open < a class = "btn" href = "./publish/" style = "display:inline-block;padding:.35rem .8rem;border-radius:8px;background:var(--acid);color:#0b0e14;font-weight:650;text-decoration:none" > Publish an extension →< / a >
sign in with the recovery phrase of the wallet that holds your name, pick the package, and sign. The gateway
verifies the signature against the name's on-chain owner, stores the package on Sia, and updates the catalog.
New versions: same page, higher version number, same name.< / li >
< / ol >
< / div >
< p class = "lede" style = "margin-top:1rem" > Prefer the command line? The upload is one signed < code > PUT< / code > :
< code > PUT https://silentmode.st/api/ext/< your-name> /< id> /< version> < / code > with the tarball as body and headers
< code > x-bns-ts< / code > , < code > x-bns-sig< / code > (over < code > sha256("BNS-EXT1\n< name> \n< id> \n< version> \n< sha256> \n< ts> ")< / code > )
and < code > x-bns-entry-sig< / code > (over < code > sha256("silentmode.extension-v1|< id> |< version> |< sha256> |< name> ")< / code > ),
both 65-byte BCH message signatures by the name's owner key.< / p >
2026-09-08 11:59:44 +02:00
< / section >
2026-09-20 14:39:07 +02:00
< script >
feat: community extensions — publish with a BCDN name, install from Settings, theseus.x catalog
Anyone who owns a BCDN name can now publish a Theseus extension, and every
Theseus can install it with the publisher's signature verified locally.
Gateway (Argus/src/gateway/public-gateway.mjs):
PUT /api/ext/<name>/<id>/<version> takes the gzipped tar, checks two BCH
message signatures against the name's current NFT owner (one authorises
the upload, one is stored in the channel), inspects the package
(addon.json at the root, id/version/main match, 8 MB cap), enforces
first-publisher ownership of an id and monotonic versions, and writes the
tarball, the extension's updates.json and community/catalog.json to Sia.
GET /api/ext/catalog reads the catalog back with CORS.
Theseus:
lib/publisher-sig.mjs recovers the signer of a channel entry; main.js
compares it with the publisher name's owner from Theseus's own chain
index before installing or updating, so neither the relay nor a tampered
catalog can pass off code under a trusted name. addon-updater.js gains
installCommunity() and accepts publisher-signed entries in the regular
update check (operator Ed25519 entries unchanged). Settings › Extensions
shows the community catalog with Install / Update; Settings › Plug-ins
links to theseus.x/plug-ins.
theseus.x:
/plug-ins/ is a separate page for the first-party plug-ins (Aegis,
Ariadne's Thread) with live versions and hashes; /extensions/ lists the
bundled extensions, the community catalog, and how to build and publish;
/extensions/publish/ signs and uploads a package in the browser with the
wallet that holds the publisher's name (session helper + wallet bundle
copied alongside).
2026-09-20 15:26:30 +02:00
// Bundled cards: fill from each add-on's signed manifest (relative URLs work on every origin the page is served from).
2026-09-20 14:39:07 +02:00
(async () => {
feat: community extensions — publish with a BCDN name, install from Settings, theseus.x catalog
Anyone who owns a BCDN name can now publish a Theseus extension, and every
Theseus can install it with the publisher's signature verified locally.
Gateway (Argus/src/gateway/public-gateway.mjs):
PUT /api/ext/<name>/<id>/<version> takes the gzipped tar, checks two BCH
message signatures against the name's current NFT owner (one authorises
the upload, one is stored in the channel), inspects the package
(addon.json at the root, id/version/main match, 8 MB cap), enforces
first-publisher ownership of an id and monotonic versions, and writes the
tarball, the extension's updates.json and community/catalog.json to Sia.
GET /api/ext/catalog reads the catalog back with CORS.
Theseus:
lib/publisher-sig.mjs recovers the signer of a channel entry; main.js
compares it with the publisher name's owner from Theseus's own chain
index before installing or updating, so neither the relay nor a tampered
catalog can pass off code under a trusted name. addon-updater.js gains
installCommunity() and accepts publisher-signed entries in the regular
update check (operator Ed25519 entries unchanged). Settings › Extensions
shows the community catalog with Install / Update; Settings › Plug-ins
links to theseus.x/plug-ins.
theseus.x:
/plug-ins/ is a separate page for the first-party plug-ins (Aegis,
Ariadne's Thread) with live versions and hashes; /extensions/ lists the
bundled extensions, the community catalog, and how to build and publish;
/extensions/publish/ signs and uploads a package in the browser with the
wallet that holds the publisher's name (session helper + wallet bundle
copied alongside).
2026-09-20 15:26:30 +02:00
const cmp = (a, b) => { const x = String(a).split(".").map(Number), y = String(b).split(".").map(Number); for (let i = 0; i < Math.max ( x . length , y . length ) ; i + + ) { const d = (x[i] | | 0 ) - ( y [ i ] | | 0 ) ; if ( d ) return d ; } return 0 ; } ;
2026-09-20 14:39:07 +02:00
for (const card of document.querySelectorAll(".ext[data-ext]")) {
const id = card.dataset.ext;
try {
const r = await fetch("./" + id + "/updates.json", { cache: "no-store" });
if (!r.ok) continue;
const m = await r.json();
const list = (m.addons || []).slice().sort((x, y) => cmp(y.version, x.version));
const top = list[0]; if (!top) continue;
const set = (k, f) => card.querySelectorAll('[data-live="' + k + '"]').forEach(f);
set("version", (el) => { el.textContent = top.version; });
set("sha256", (el) => { el.textContent = top.sha256 || "—"; });
set("url", (el) => { el.href = top.url; el.textContent = String(top.url).split("/").pop(); });
set("count", (el) => { el.textContent = list.length + " signed version" + (list.length === 1 ? "" : "s") + " on the channel"; });
} catch {}
}
feat: community extensions — publish with a BCDN name, install from Settings, theseus.x catalog
Anyone who owns a BCDN name can now publish a Theseus extension, and every
Theseus can install it with the publisher's signature verified locally.
Gateway (Argus/src/gateway/public-gateway.mjs):
PUT /api/ext/<name>/<id>/<version> takes the gzipped tar, checks two BCH
message signatures against the name's current NFT owner (one authorises
the upload, one is stored in the channel), inspects the package
(addon.json at the root, id/version/main match, 8 MB cap), enforces
first-publisher ownership of an id and monotonic versions, and writes the
tarball, the extension's updates.json and community/catalog.json to Sia.
GET /api/ext/catalog reads the catalog back with CORS.
Theseus:
lib/publisher-sig.mjs recovers the signer of a channel entry; main.js
compares it with the publisher name's owner from Theseus's own chain
index before installing or updating, so neither the relay nor a tampered
catalog can pass off code under a trusted name. addon-updater.js gains
installCommunity() and accepts publisher-signed entries in the regular
update check (operator Ed25519 entries unchanged). Settings › Extensions
shows the community catalog with Install / Update; Settings › Plug-ins
links to theseus.x/plug-ins.
theseus.x:
/plug-ins/ is a separate page for the first-party plug-ins (Aegis,
Ariadne's Thread) with live versions and hashes; /extensions/ lists the
bundled extensions, the community catalog, and how to build and publish;
/extensions/publish/ signs and uploads a package in the browser with the
wallet that holds the publisher's name (session helper + wallet bundle
copied alongside).
2026-09-20 15:26:30 +02:00
// Community catalog
const box = document.getElementById("communityList");
const esc = (s) => String(s || "").replace(/[& < >"']/g, (c) => ({ "&":"& ","< ":"< ",">":"> ",'"':"" ","'":"' " })[c]);
try {
const r = await fetch("./community/catalog.json", { cache: "no-store" });
const cat = r.ok ? await r.json() : { extensions: [] };
const list = Array.isArray(cat.extensions) ? cat.extensions : [];
if (!list.length) { box.innerHTML = '< div class = "ext" style = "color:var(--dim)" > Nothing published yet — yours could be the first. See < a href = "#build" > Build and publish your own< / a > .< / div > '; return; }
box.innerHTML = list.map((e) => `
< div class = "ext" id = "ext-${esc(e.id)}" >
< h3 > < span class = "icon" > ${esc(e.icon || "🧩")}< / span > ${esc(e.name)} < span class = "cur" style = "margin-left:auto" > v${esc(e.latest)}< / span > < / h3 >
< div class = "desc" > ${esc(e.description)}< / div >
< div class = "meta" > Published by < b > ${esc(e.publisher)}< / b > · ${esc(String(e.versions || 1))} version${e.versions === 1 ? "" : "s"} · updated ${esc(String(e.updatedAt || "").slice(0, 10))}${e.capabilities & & e.capabilities.length ? " · " + esc(e.capabilities.join(", ")) : ""}< / div >
< div class = "verifybox" >
< div class = "lbl" > Publisher-signed channel — verified by Theseus against ${esc(e.publisher)}'s current owner< / div >
< div class = "h" > < b > updates.json< / b > < code > < a href = "${esc(e.updatesUrl)}" > ${esc(String(e.updatesUrl).replace(/^https?:\/\/[^/]+\/bns\//, ""))}< / a > < / code > < / div >
< div class = "h" > < b > Tarball< / b > < code > < a href = "${esc(e.tarballUrl)}" > ${esc(String(e.tarballUrl).split("/").pop())}< / a > < / code > < / div >
< div class = "h" > < b > sha256< / b > < code > ${esc(e.sha256)}< / code > < / div >
< div class = "h" > < b > Install< / b > < code > Theseus › Settings › Extensions › Community › Install< / code > < / div >
< / div >
< / div > `).join("");
} catch (e) { box.innerHTML = '< div class = "ext" style = "color:var(--dim)" > Catalog unavailable right now.< / div > '; }
2026-09-20 14:39:07 +02:00
})();
< / script >
2026-09-20 15:54:01 +02:00
< section id = "updates" >
2026-09-08 11:59:44 +02:00
< h2 > How updates work< / h2 >
< p class = "lede" > Same mechanism a Firefox XPI update uses, cut down to what a name-native browser needs.< / p >
< div class = "flow" >
< ol >
< li > Every 30 seconds after boot Theseus fetches < code > updates.json< / code > for each installed add-on that declares an < code > updateURL< / code > in its manifest.< / li >
< li > Each entry carries an Ed25519 signature over < code > silentmode.addon-update-v1|< id> |< version> |< sha256> < / code > . Theseus verifies against a small set of operator public keys baked into the build. Unsigned or badly-signed entries are dropped silently.< / li >
< li > If a signed version beats what's installed, Theseus downloads the tarball, re-checks its sha256, and stages the new copy under < code > < userData> /addons-updates-staged/< id> -< version> /< / code > .< / li >
< li > On the next Theseus launch, < code > promoteStagedUpdates< / code > moves the staged copy into < code > addons/< id> /< / code > . Any prior copy is renamed to < code > addons-backups/< id> -< oldver> -< timestamp> /< / code > so hand-edits survive.< / li >
2026-09-20 14:39:07 +02:00
< li > Settings › Extensions has a < b > Check for updates< / b > button and shows what is staged; first-party plug-ins (Aegis) can also stage and restart from their own panel.< / li >
2026-09-08 11:59:44 +02:00
< / ol >
< / div >
< / section >
2026-09-20 15:54:01 +02:00
< section id = "operator-key" >
2026-09-08 11:59:44 +02:00
< h2 > Operator key< / h2 >
< p class = "lede" > The Ed25519 public key baked into Theseus 0.3.19+.
Rotation is by adding a new pubkey and shipping a Theseus release that carries both, then a follow-up release removing the old — during the overlap, entries can be signed by either.< / p >
< div class = "pubkey" > 732b1263a236b0030383a2376597cfa43c3624b3ca2912a46134f8f2a06e6012< / div >
< p style = "color:var(--dim);font-size:12.5px;margin-top:.6rem" > Generated 2026-09-07. Held offline by the Silent Mode operator.< / p >
< / section >
2026-09-20 15:54:01 +02:00
< section id = "roadmap" >
2026-09-08 11:59:44 +02:00
< h2 > Roadmap< / h2 >
< p class = "lede" > The endpoint is generic — any bundled add-on can advertise an < code > updateURL< / code > .
Concrete next-steps:< / p >
< ul style = "color:var(--mut);font-size:14px;line-height:1.7" >
< li > On-BCNR pubkey publication so rotation is auditable end-to-end.< / li >
< li > Multi-sig (N-of-M operator keys) so a single compromised private key can't push code.< / li >
2026-09-20 14:39:07 +02:00
< li > Extend the channel to < b > Notepad< / b > (bundled, no channel yet).< / li >
2026-09-08 11:59:44 +02:00
< / ul >
< / section >
< footer >
Silent Mode · < a href = "https://code.silentmode.st/silentmode/theseus/src/branch/master/TheseusNavigator/docs/ADDON-UPDATES.md" > source & operator brief< / a >
< / footer >
< / div >
2026-09-20 19:20:30 +02:00
< script >
// Sidenav scroll-spy: highlight the section currently in view.
// Uses scroll-position tracking so short sections at the end of the page
// still activate their link when the reader scrolls to them.
(() => {
const links = document.querySelectorAll(".sidenav a[href^='#']");
if (!links.length) return;
const entries = [];
links.forEach((a) => { const el = document.querySelector(a.getAttribute("href")); if (el) entries.push({ el, link: a }); });
if (!entries.length) return;
const setActive = (link) => { links.forEach((l) => l.classList.remove("active")); link.classList.add("active"); };
const update = () => {
const doc = document.documentElement;
const scrollBottom = window.scrollY + window.innerHeight;
if (scrollBottom >= (doc.scrollHeight - 4)) { setActive(entries[entries.length - 1].link); return; }
const line = window.scrollY + window.innerHeight * 0.35;
let active = entries[0].link;
for (const e of entries) {
if (e.el.getBoundingClientRect().top + window.scrollY < = line) active = e.link;
else break;
}
setActive(active);
};
window.addEventListener("scroll", update, { passive: true });
window.addEventListener("resize", update);
update();
})();
< / script >
2026-09-08 11:59:44 +02:00
< / body >
< / html >