- VPN card: relay URLs, device management, invite QR, add participant
- Backend: vpn.invite, vpn.add-participant, vpn.peer-config RPCs
- nvpn v0.3.7 system service (fixes event processing bug in v0.3.4)
- First-boot: auto-configure nvpn with node identity and endpoint
- Service: AF_NETLINK for WireGuard, NoNewPrivileges=no for sudo wg
- TASK-50: networking stack reliability from first install
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Install progress bar replaces action buttons (no overlay)
- Hide status badge during install/uninstall
- Uninstall keeps progress state until container disappears from WebSocket
- Uninstall RPC timeout increased to 660s (Bitcoin UTXO flush)
- Installing apps appear in My Apps immediately as placeholders
- Auto-configure Tor hidden service for every app on install
- Widen Tor module visibility for install hooks
- Only clear stale install entries on error status
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove ReadWritePaths sandbox (causes namespace error when /run/nostr-vpn
doesn't exist after reboot — /run is tmpfs)
- Detect both 'active' and 'activating' states in VPN status check
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add vpn.create-peer, vpn.list-peers, vpn.remove-peer RPC methods
- Generate WireGuard config + QR code (SVG) for mobile device connection
- Add "Add Device" modal on Network page with QR scanner support
- Remove old build-iso.yml (replaced by build-iso-dev.yml)
- Remove container-tests.yml (tests run in dev workflow)
- Remove container orchestration tests from dev workflow (redundant)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Kiosk was redirecting /kiosk → /dashboard, bypassing RootRedirect
and BootScreen entirely. This caused the kiosk to land on Login.vue
showing "server is starting up" in a loop instead of the proper
terminal-style boot progression screen.
Now /kiosk → / → RootRedirect → BootScreen, matching what remote
browsers see.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix vpnStatus type mismatch (provider: string|undefined vs string|null)
- Remove redundant history_dirty assignment in health_monitor.rs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add system.settings.get/set RPC methods for Claude API key management
- Save key to secrets/claude-api-key, restart claude-api-proxy service
- Home Network card now fetches VPN status via vpn.status RPC
- Shows provider name (nostr-vpn, tailscale) instead of just "Connected"
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
FIPS stays in the marketplace as an installable container app.
NostrVPN is the native system service; FIPS is a separate optional app.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Convert NostrVPN from container app to native systemd service
- Auto-configure VPN with node's Nostr identity after onboarding
- Add nostr-vpn.service with proper capabilities (NET_ADMIN, NET_RAW)
- Remove FIPS from marketplace, container config, nginx, image-versions
(consolidated into NostrVPN — same mesh VPN concept)
- Add AIUI inclusion step to dev CI workflow
- AIUI installed on VPS build server for ISO inclusion
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add NostrVPN as a native systemd service (extracted from container)
- Add VPN status detection for nostr-vpn in backend vpn.rs
- ISO build extracts nvpn binary from container image
- First-boot auto-configures NostrVPN with node's Nostr identity
- Change Claude Auth from login iframe to API key input field
- Remove duplicate ChangePasswordSection from Settings.vue
- FIPS and Routstr remain as installable container apps
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add three new marketplace apps:
- Routstr (v0.4.3): Decentralized AI inference proxy with Cashu payments
- Nostr VPN (v0.3.4): Mesh VPN with Nostr signaling + WireGuard tunnels
- FIPS (v0.1.0): Self-organizing encrypted mesh network
Includes status UI dashboards for headless apps (nostr-vpn-ui, fips-ui)
with usage instructions, node identity display, and container logs.
Nostr identity injected via env vars for all three apps.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Critical:
- BUILD_VERSION was hardcoded as "1.3.0-alpha" — now reads from Cargo.toml
This caused ALL ISOs to show v1.3.0 regardless of actual binary version
Kiosk:
- Remove --disable-gpu flags (broke display scaling on some monitors)
- Add --start-fullscreen --window-size for reliable fullscreen
New apps:
- Nostr VPN, FIPS, Routstr, noStrudel, BotFights, NWNN, 484 Kitchen,
Call the Operator, Arch Presentation, Syntropy Institute, T-0
Rust: suppress dead_code and unused_assignments warnings
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Pre-create Documents/Photos/Music/Downloads/Builds dirs for FileBrowser
- Add "Already set up? Log in" link on onboarding intro page
- Prevents users from getting stuck in onboarding loop
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Onboarding:
- Persist current step in localStorage — page refresh resumes where user was
- Router afterEach saves step; guard redirects to saved step, not always intro
- Show npub alongside DID on restore success screen
UI fixes:
- Clipboard polyfill for HTTP contexts (fixes Copy DID crash on non-HTTPS)
- AppCard installing overlay shows for pkg.state=installing (survives refresh)
- Hide uninstall button during installation
- Frontend version bumped to 1.3.2
App store:
- OnlyOffice fully removed from marketplace, curated apps, app config
- Replaced with CryptPad references throughout
- Remove OnlyOffice from ISO capture patterns
Container stability:
- UI containers (bitcoin-ui, lnd-ui, electrs-ui) pull from registry first
- Added --cap-add FOWNER for rootless Podman compatibility
- electrs-ui now included in first-boot loop alongside bitcoin-ui and lnd-ui
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move CompanionIndicator from global App.vue overlay to DashboardSidebar
next to ControllerIndicator. Redesigned as inline sidebar element with
Tailwind classes — shows muted 'Relay' when idle, orange 'Companion'
with pulse dot when actively receiving input.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
CompanionIndicator: show muted icon when relay connected but idle,
orange when companion actively sending input. Removes Transition
wrapper for always-visible relay status.
Add scripts/node-profile.sh utility.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Frontend:
- Add remote-relay.ts: receives companion input via /ws/remote-relay,
dispatches keyboard/mouse/scroll events into browser DOM
- Add CompanionIndicator.vue: NES gamepad icon when companion connected
- Wire relay start/stop to auth state in App.vue
Kiosk:
- Move Chromium data dir to /var/lib/archipelago/chromium-kiosk (encrypted)
- Disable MetricsReporting, AutofillServerCommunication, PasswordManager
- Remove --metrics-recording-only (contradicts disable-metrics)
CSS:
- Fix Chromium ghost rectangles: only apply preserve-3d + backface-visibility
during transitions, not always-on (causes Chromium to skip painting
off-viewport cards)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The outer page wrapper needs path-glass-container for the glass effect.
Only the inner text field grid should be without it.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Proxy paths (/app/name/) break iframes due to root-relative asset
paths. Direct IP:port access works correctly over Tailscale and LAN.
This has been confirmed working on .228 via Tailscale DNS.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Direct port access (http://host:port) fails over Tailscale/VPN and
when ports aren't externally accessible. Now all apps use nginx proxy
paths (/app/name/) on both HTTP and HTTPS.
Also adds missing proxy paths for btcpay, nextcloud, penpot, grafana,
indeedhub. Bumps version to 1.3.1.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The old Kiosk.vue app grid launcher was never intended as the kiosk
display. Redirect /kiosk to /dashboard so the kiosk shows the actual
Archipelago interface.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Backend:
- Add --add-host host.containers.internal:host-gateway to LND and Bitcoin
Knots containers (fixes DNS resolution failure in rootless podman)
- Add --user 0:0 and DAC_OVERRIDE to nginx UI sidecar containers
(fixes chown crash in rootless podman for bitcoin-ui, electrs-ui, lnd-ui)
- Add hostadd to Rust Podman API client for web UI container installs
- Add Chromium privacy flags to kiosk launcher (disable telemetry)
Frontend:
- Fix onboarding reset on raw IP visits (trust localStorage as first-class
signal, skip boot screen when server is up but not onboarded)
- Fix seed regression: persist challenge indices in sessionStorage so going
back from Verify doesn't change which words are asked
- Remove glass container from seed Generate/Verify/Restore screens
- Add Back button to Restore from Seed screen
- Replace Network card: Tor (purple), VPN status (orange), Bitcoin sync (orange)
- Add ElectrumX to curated app list with correct .webp icon
- Install flow: navigate to My Apps immediately with toast, hide
installed/installing apps from marketplace and discover views
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
LND v0.18+ crashes with "netlinkrib: address family not supported"
because rootless podman blocks netlink access for TLS cert SAN
enumeration. Fix: add tlsextraip=0.0.0.0 and tlsextradomain=lnd
to lnd.conf so LND skips interface enumeration.
Also: fix status label to show "crashed" for both exited and
stopped containers with non-zero exit codes (previously only
caught "exited" state, but podman reports "stopped" for
restart-looping containers).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Critical flow fixes:
- Disable boot reconciliation that auto-created ALL containers on
unbundled installs (only FileBrowser should exist on first boot)
- Fix onboarding loop: RootRedirect no longer clears the
neode_onboarding_complete flag on boot screen completion
- Seed phrase persists when navigating back (no regeneration)
UI fixes:
- Boot screen: removed github and save icons from animation loop
- Seed screens: viewport height scaling with 100dvh
- Seed restore: removed outer card container from word input grid
- Seed screens use distinct background (bg-intro-1.jpg)
- Install progress simplified to "Installing" button style
- Uninstall state moved to global store (persists across navigation)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- session.rs: use OnceCell for remember_secret to prevent concurrent
requests on first boot from generating different HMAC secrets, which
caused CSRF token mismatch on every state-changing RPC call (app
install, start, stop all failed with "CSRF token missing or invalid")
- install.rs: write lnd.conf with Bitcoin RPC credentials before LND
container starts (prevents "bitcoin.mainnet must be specified" crash);
inject Bitcoin RPC auth into bitcoin-ui nginx.conf; add proper error
logging to UI container build/run steps; fix UI containers to use
--network=host (they proxy to localhost backend/bitcoin RPC)
- Tor: remove After=tor.service from archipelago-tor-helper.path to
break systemd ordering cycle that prevented Tor from starting on boot
- Seed screen: compact grid layout (2 cols mobile, 4 cols sm+) with
tighter padding to fit kiosk displays without scrolling
- Dockerfiles: remove nonexistent assets/ COPY from bitcoin-ui, fix
electrs-ui to COPY qrcode.js and EXPOSE 50002 (matches nginx.conf)
- image-versions.sh: add UI container image variables for registry
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Uninstall was timing out at 15s default while podman stop takes 30-600s.
Now: uninstall 120s, stop 120s, restart 120s, start 60s.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Chromium kiosk: add --disable-gpu-compositing, --disable-gpu-rasterization,
--disable-software-rasterizer, --renderer-process-limit=1
drops GPU process from 64% to 12% CPU
- Container healthchecks: 30s to 120s interval in first-boot and reconcile
- AppCard: min-height on description so cards dont shift
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace fragmented random key generation with a single 24-word BIP-39
mnemonic that deterministically derives all node keys: Ed25519 (DID),
secp256k1 (Nostr/Bitcoin), BIP-84 xprv (Bitcoin Core), and LND aezeed
entropy. New onboarding flow: seed generate → word verification → identity
naming. Restore path enabled via 24-word entry. Includes seed RPC handlers,
mock backend support, LND/Bitcoin Core wallet-from-seed integration, and
UI polish across settings and discover views.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add AppIconGrid: 4-column swipeable icon grid with page dots for My Apps on mobile
- Tab bar: remove text labels, square icon-only buttons (w-14 h-14), doubled padding
- Hide tab bar and top context tabs when app session is open
- App session header hidden on mobile, replaced with floating glass close button
- App sessions now render fullscreen on mobile without nav chrome
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Every app in curatedApps.ts was hardcoded to docker.io/* instead of
our registry (80.71.235.15:3000/archipelago/*). This caused Bitcoin
Knots and all Discover tab installs to fail with pull errors.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Critical:
- fix: container installs fail with "statfs: no such file or directory"
Root cause: NoNewPrivileges=yes in systemd blocks sudo inside backend.
Fix: use std::fs::create_dir_all + podman unshare chown (no sudo needed)
- fix: Tor services.json never written — \$ARCHY_TOR_DIR escaping bug
- fix: kiosk white screen — increase health wait to 60s, add --disable-gpu
Improvements:
- feat: LUKS encryption badge in Server disk stats (backend detects dm-crypt)
- fix: GRUB theme text scaling on 4:3 monitors — explicit fonts, wider menu
- fix: suppress default Debian MOTD (custom profile.d welcome is enough)
- fix: install error messages now show "Failed to pull/start" instead of
generic "Operation failed" (middleware.rs allowlist expanded)
- fix: container-tests CI — source cargo env before running tests
- docs: interactive container architecture diagram (HTML)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- fix: login disconnect — verify session before WebSocket connect
- fix: 403 on app install — distinguish CSRF vs RBAC errors, only retry CSRF
- fix: health monitor now watches ALL containers (removed skip list for
backend services like nbxplorer, databases, UI containers)
- fix: server.get-state added to CSRF-exempt list (read-only)
- fix: ISO build includes container-specs.sh and lib/common.sh in rootfs
so reconcile actually works on fresh installs
- fix: gamepad nav — improved Server tab zone nav, focus styles, autofocus
- chore: move L484 web-only apps to Services tab
- chore: install store for cross-view install tracking
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Peer rows: tabindex + role=button + Enter handler for D-pad selection
- Zone attributes: mesh-left, mesh-chat, mesh-tools for cross-panel nav
- Actions row: data-controller-container for Up from peers
- Right from peers → chat input, Right from chat → tools tabs (wide)
- Down from tabs → panel fields/buttons in grid fashion
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Down from Identity name input now lands on Personal button (closest)
instead of Continue (wider overlap but further away).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Passphrase input autofocused on mount
- "Download Backup" renamed to "Backup to Continue"
- Continue button autofocused after successful backup download
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Path screen: Continue autofocused after 500ms (was 400ms, missed transition)
- Identity screen: name input autofocused on mount
- path-action-button now shows orange focus glow (removed from suppression list)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove path-action-button from focus-visible suppression list
- Orange glow now shows on Continue when autofocused
- Bump autofocus delay to 500ms to clear slide transition
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- glass-button gets orange glow on focus-visible (was suppressed)
- Input fields get orange border on focus-visible
- Restore link made focusable (tabindex, role, keydown.enter)
- Gamepad nav sounds play via existing fallback handler
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sidebar Right now polls every 100ms (up to 1s) for containers to
appear, instead of a single 200ms retry that missed animations.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Only recall container elements (not nav bar buttons) from focus memory
- Retry after 200ms when containers aren't rendered yet (async route)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>