Files
archy/.planning/ROADMAP.md
T

40 KiB
Raw Blame History

Roadmap: Archipelago — v1.8.0 Developer-Ready App Platform

Overview

Brownfield milestone starting from a green single-node production gate (5/5 on .228, 2026-06-23). The journey: make federation and mesh rock-solid (node removal, sync, messaging parity), fix the UI slowness users feel on every tab switch, prove the platform across the fleet (multinode pass), make the container lifecycle bulletproof (Quadlet default, self-healing, honest progress, no ghosts), flip manifest distribution from OTA disk files to the signed registry, harden manifest security enforcement to the full ADR-009 bar, ship the archy app developer CLI, and land the decentralized Nostr marketplace — ending at the north star: a third-party developer publishes an app via the signed/decentralized registry and a user installs it on their node.

Phases

Phase Numbering:

  • Integer phases (1, 2, 3): Planned milestone work

  • Decimal phases (2.1, 2.2): Urgent insertions (marked with INSERTED)

  • Phase 1: Federation & Mesh Hardening - Deep review of federation/fleet + mesh code; node removal sticks, sync converges, mesh messaging behaves identically on demo and real nodes

  • Phase 2: UI Performance - Tab switches and secondary screens render fast; worst transitions measured and fixed (completed 2026-07-31)

  • Phase 3: Multinode Verification Pass - Lifecycle gate green on a second node; cross-node federation/mesh/transport suites pass; federation removal sticks

  • Phase 4: Lifecycle Perfection & Quadlet Default - Quadlet backends default, failed-unit self-healing, flap observability, cascade gate, truthful progress

  • Phase 5: Registry-Distributed Manifests - Signed catalog carries full manifests; fleet flipped off OTA disk-file distribution

  • Phase 6: Manifest Security Enforcement - Validation matches ADR-009 mandates; generated security profiles actually applied

  • Phase 7: Developer Tooling CLI - archy app validate/render/local-install/lifecycle-test + developer guide

  • Phase 8: Decentralized Marketplace - DID-signed publish to Nostr relays, trust-tier discovery, verified third-party install end-to-end

  • Phase 9: BotFights Platform Upgrade - Native nostr signer login, one self-contained AI bot-setup prompt, shared public VPS2 match endpoint so all nodes see all fighters, registry updated

  • Phase 12: Bitcoin Node Settings & Core/Knots Parity - Every bitcoind option reachable in the UI, Knots-only options gated to Knots, network mode a setting defaulting to Tor

  • Phase 13: AIUI — Conversational Node Control & Content Surfaces - Human-language node control and settings in AIUI chat, its designed content surfaces wired to real peer/music/movie data, all inside a user-granted capability sandbox that keeps keys and secrets away from the browser and the model

Phase Details

Phase 1: Federation & Mesh Hardening

Goal: Federation and mesh are tight — a structured review of the fleet/federation and mesh code feeds fixes so node removal sticks, sync converges, and mesh messaging (including attachments) behaves identically everywhere it runs Depends on: Nothing (first phase) Requirements: FED-01, FED-02, FED-03, FED-04, FED-05, FED-06, FED-07, UIFIX-01, UIFIX-02, UIFIX-03, UIFIX-04, UIFIX-05, UIFIX-06, FED-08, FED-09 Success Criteria (what must be TRUE):

  1. A structured code review of the federation/fleet area (core/archipelago/src/federation, node sync, FIPS/transport dial layer) and the mesh area (core/archipelago/src/mesh, mesh RPC surface) produces a findings list, and every finding is fixed or explicitly deferred with a reason
  2. Removing a federation node removes it everywhere — it disappears from all UI surfaces, tombstones propagate, and it never reappears after later sync cycles; a failed removal surfaces an error instead of silently no-opping
  3. Federation sync converges: after sync settles, fleet nodes agree on the node list and node status is fresh — stale entries, duplicates, and silent sync failures are gone, and sync errors are visible to the operator
  4. Mesh attachment send works identically on the demo and on real nodes — same modals, same transport decisions, same success — with the demo backend implementing the same RPC surface the UI calls (no "Method not found", no demo-only chooser modal)
  5. Channel-opening between nodes is first-class UI: a user can copy/share their node's Lightning URI; sees a list of trusted (federated) nodes by hostname to open a channel with in one flow; and can browse/request channels with public nodes — built with the existing design system (Teleport-to-body modals, house style), tested live on the :8100 dev preview against archi-dev, and fixed there before any deploy
  6. The invoice/payment "paid" success animation is on-brand: the tick's circle is the screensaver-style ring with the outer EQ-segment lines (reuse neode-ui/src/components/ScreensaverRing.vue, which already ships a compact overlay size), replacing the current burst in the payment success pane (neode-ui/src/components/SendBitcoinModal.vue) and matching wherever else the paid tick appears
  7. Fedimint gateway installs have no pre-set password (BLOCKER, added 2026-07-30): a fresh install generates its gateway credentials per-install via manifest-declared generated_secrets (per the repo secrets invariant) or requires the user to set one — never a baked-in default; existing installs carrying the default password are migrated or flagged. NOTE: phase 1's 10 plans predate this criterion — an additional gap plan is required before phase 1 execution completes
  8. The FIPS/Tor pills on cloud files are kept and visible at mobile widths (UIFIX-01, BLOCKER, added 2026-07-30 — see .planning/todos/pending/2026-07-30-keep-fips-tor-pills-on-cloud-files-and-show-them-on-mobile.md)
  9. The connected-nodes list scrolls at row-matched height instead of growing to fit (UIFIX-02, BLOCKER, added 2026-07-30 — see .planning/todos/pending/2026-07-30-connected-nodes-list-must-scroll-at-row-matched-height.md)
  10. The onboarding tickbox is discoverably visible on short viewports via an on-brand affordance (UIFIX-03, BLOCKER, added 2026-07-30 — see .planning/todos/pending/2026-07-30-onboarding-tickbox-hidden-below-fold-on-short-screens.md)
  11. Paid Files pictures open in the app lightbox, not a browser tab (UIFIX-04, added 2026-07-30 — see .planning/todos/pending/2026-07-30-peer-files-pictures-open-in-tab-not-lightbox.md)
  12. Picture-in-picture closes the lightbox with a fluid on-brand animation (UIFIX-05, added 2026-07-30 — see .planning/todos/pending/2026-07-30-pip-should-close-lightbox-with-fluid-animation.md)
  13. Genuinely slow opens show loader states (UIFIX-06, added 2026-07-30 — see .planning/todos/pending/2026-07-30-missing-loader-states-on-slow-opens.md; 02-08's flagged timing regressions are the starting inventory) NOTE for criteria 713: all were added after phase 1's 10 plans were written — before phase 1 execution completes, create gap plan(s) covering FED-07 + UIFIX-01..06 (existing desktop visuals must remain untouched per the standing visual-invisibility rule; UIFIX items themselves are user-approved visual changes)

Plans: 11/20 plans executed

Plans:

  • 01-20-PLAN.md — URGENT wave 1: doctor stops restarting Tor every 5min (mesh Tor fallback) (FED-09)
  • 01-19-PLAN.md — URGENT wave 1: wallet invoices embed route hints so private-channel nodes can receive (FED-08)
  • 01-01-PLAN.md — Serialize the federation node store and make removal stick (FED-01)
  • 01-02-PLAN.md — Demo mesh/federation RPC parity + automated parity harness (FED-04)
  • 01-03-PLAN.md — On-brand paid tick: ScreensaverRing badge variant on both success surfaces (FED-06)
  • 01-04-PLAN.md — Lightning identity: own-node URI + meshed Lightning peer discovery (FED-05)
  • 01-05-PLAN.md — Federation sync convergence and operator-visible sync errors (FED-02)
  • 01-06-PLAN.md — Lightning URI on the federation sync payload, sharing default decided (FED-05)
  • 01-07-PLAN.md — Channel-open request messaging over the mesh (FED-05)
  • 01-08-PLAN.md — Channel-open UX: own URI, trusted-node picker, meshed-peer requests (FED-05)
  • 01-09-PLAN.md — Structured federation/mesh review + dev-pair deploy (FED-03)
  • 01-10-PLAN.md — Consolidated phase verification on the dev pair (FED-01/02/05/06)

Wave 7 (gap closure — criteria 713, added 2026-07-30 after the original 10 plans were written)

  • 01-11-PLAN.md — No baked-in Fedimint gateway credential: per-install secret on every path (FED-07)
  • 01-12-PLAN.md — Connected-nodes list scrolls at row-matched height instead of growing (UIFIX-02)
  • 01-13-PLAN.md — On-brand scroll cue makes the onboarding tickbox findable on short screens (UIFIX-03)
  • 01-14-PLAN.md — Paid Files open in the app lightbox, with a visible wait and a real error path (UIFIX-04/06)
  • 01-15-PLAN.md — PiP hands off from the lightbox and survives tab changes and buffering (UIFIX-05)

Wave 8 (blocked on Wave 7 completion)

  • 01-16-PLAN.md — Migrate existing installs off the default gateway credential, data preserved (FED-07)
  • 01-17-PLAN.md — FIPS/Tor pills pinned against removal and readable at phone widths (UIFIX-01)

Wave 9 (blocked on Wave 8 completion)

  • 01-18-PLAN.md — Six-fix sign-off on archi-dev-box (UIFIX-01/02/03/04/05/06)

UI hint: yes

Phase 2: UI Performance

Goal: The UI feels fast — switching tabs and opening secondary screens (screens reached from a tab's main page) renders promptly instead of stalling on refetches and remounts Depends on: Nothing (frontend-focused; parallelizable with Phase 1) Requirements: PERF-01, PERF-02, PERF-03 Success Criteria (what must be TRUE):

  1. The slowest tab switches and secondary-screen opens are profiled and the causes named (remount storms, serial RPC waterfalls, uncached fetches) before fixes land
  2. Switching between main tabs renders the target view immediately from cached state, refreshing data in the background — no blank screens or long spinners on tabs already visited this session
  3. Secondary screens open without a blocking full reload; repeat visits are instant
  4. The fixes are verified on real node hardware (not just the dev box) — the sluggishness the user reported is gone on-device

Plans: 11/11 plans executed

Plans: Wave 1

  • 02-01-PLAN.md — Profile every D-09 surface on archi-dev-box and commit the findings doc (PERF-01)

Wave 2 (blocked on Wave 1 completion)

  • 02-02-PLAN.md — TRACER: KeepAlive host, hook reactivation, app-store tab, refresh indicator (PERF-02)
  • 02-03-PLAN.md — Secondary screens: per-item cache, parallel loads, purge on logout (PERF-03)

Wave 3 (blocked on Wave 2 completion)

  • 02-04-PLAN.md — Keep every main tab alive safely: lifecycle audit + full registration (PERF-02)

Wave 4 (blocked on Wave 3 completion)

  • 02-05-PLAN.md — Mesh: cache the six fetch groups, bound the D3 graph and Leaflet map (PERF-02)
  • 02-06-PLAN.md — Server and Home: cache the uncached fan-out, guarantee wallet freshness (PERF-02)
  • 02-07-PLAN.md — Chat/AIUI: stable embed URL + the two D-14 UX defaults (PERF-02)

Wave 5 (blocked on Wave 4 completion)

  • 02-08-PLAN.md — Dev-pair deploy, on-device re-measure, D-11 pass bar (PERF-01/02/03)

Wave 6 (gap closure — blocked on Wave 5 completion)

  • 02-09-PLAN.md — Server.vue KeepAlive remount: name the cause, fix it, pin it (PERF-02)

Wave 7 (gap closure — blocked on Wave 6 completion)

  • 02-10-PLAN.md — Timing-regression verdict: three-way re-measure, clear or name each surface (PERF-02/03)

Wave 8 (gap closure — blocked on Wave 7 completion)

  • 02-11-PLAN.md — Profile the real cause of the six confirmed regressions, fix what's fixable, re-measure (PERF-02/03)

UI hint: yes

Phase 3: Multinode Verification Pass

Goal: The platform's lifecycle and federation guarantees are proven across the fleet, not just on .228 — the declared next exit criterion Depends on: Phase 1 (proves the federation/mesh fixes hold fleet-wide) Requirements: MNODE-01, MNODE-02, MNODE-03 Success Criteria (what must be TRUE):

  1. The 5× destructive lifecycle gate reports 0 failures on a second fleet node (archy-x250-beta), run on-node
  2. The cross-node smoke suite (federation pairing both directions, FIPS anchors, peer content browse) passes between two fleet nodes with every harness RPC time-bounded — a slow node produces a test failure, never an indefinite hang
  3. An operator who removes a federation peer never sees it reappear in the peer list after later sync cycles; a tombstone-write failure is surfaced as an error instead of silently swallowed
  4. The on-air mesh suite passes between two radio-equipped nodes over real RF

Plans: TBD

Phase 4: Lifecycle Perfection & Quadlet Default

Goal: An insanely-reliable container environment — every app installs, runs, restarts, uninstalls, and reinstalls cleanly with honest progress, no ghosts, and automatic recovery Depends on: Phase 3 (Quadlet default-flip is gated on the second-node gate reporting clean) Requirements: LIFE-01, LIFE-02, LIFE-03, LIFE-04, LIFE-05 Success Criteria (what must be TRUE):

  1. Restarting archipelago.service on a fleet node leaves every app container running — no SIGKILL-the-world, no multi-minute reconciler rebuild
  2. An app whose Quadlet unit enters failed state (and was not user-stopped) comes back automatically within a bounded window, with backoff on persistent failure — no operator intervention
  3. An operator can see per-app restart counts in status output, and a flapping app (>N restarts in M minutes) is flagged in logs instead of being invisible
  4. Uninstalling then reinstalling any gated app — including multi-container stacks like immich/btcpay — leaves no ghost My-Apps entries or orphan containers, preserves data per policy, and returns the app healthy, verified by the cascade gate tier
  5. Install and uninstall progress bars move monotonically from real backend progress events and always land on a terminal success/failure state — asserted in the gate, and the single-node gate stays green after all orchestrator changes

Plans: TBD UI hint: yes

Phase 5: Registry-Distributed Manifests

Goal: Manifests ship via the signed registry, not OTA disk files — bumping or adding an app becomes a signed catalog change Depends on: Phase 4 (fleet lifecycle stable under Quadlet default before changing the distribution channel) Requirements: REG-01, REG-02 Success Criteria (what must be TRUE):

  1. A fleet node installs and updates an image-only app from the full manifest embedded in the signed catalog, verified against the pinned release-root key, with no corresponding OTA disk file present (disk remains the fallback for build-source apps)
  2. A tampered or unsigned catalog manifest is rejected and the node falls back safely — it never installs from an unverified manifest
  3. Bumping an app version fleet-wide requires only regenerating, re-signing, and publishing the catalog — no binary OTA, no disk rsync — proven live on the fleet

Plans: TBD

Phase 6: Manifest Security Enforcement

Goal: A third-party manifest cannot weaken node security — declared security policy is fully validated and actually enforced at runtime Depends on: Phase 5 (enforcement guards the registry channel third-party manifests will arrive through) Requirements: SEC-01, SEC-02 Success Criteria (what must be TRUE):

  1. A manifest violating ADR-009 mandates (root user, unpinned latest tag, capability outside the allow-list, disabled seccomp) is rejected at validation with a clear error naming the violation
  2. Security overrides (readonly_root: false, extra capabilities) work only when explicitly listed in the manifest and leave an audit trail
  3. Generated AppArmor/seccomp profiles are applied to containers at creation and verifiably effective on a running app — not just generated and ignored
  4. The single-node lifecycle gate stays green with enforcement on — existing catalog apps all pass the strengthened validation (or carry documented overrides)

Plans: TBD

Phase 7: Developer Tooling CLI

Goal: A third-party developer can build, validate, and test an Archipelago app locally without reading platform internals Depends on: Phase 6 (CLI validation must mirror the final enforced rule set) Requirements: DEV-01, DEV-02, DEV-03, DEV-04 Success Criteria (what must be TRUE):

  1. A developer runs archy app validate on a manifest directory and gets the same pass/fail verdict — including security rules — that a node would enforce at install
  2. A developer runs archy app render and sees the exact Quadlet/podman configuration their manifest produces before ever touching a node
  3. A developer can install their app onto a dev node and run its lifecycle test (install/UI/stop/start/restart/uninstall) from the CLI
  4. A new developer following only the developer guide goes from an empty directory to a running app on a node — no tribal knowledge required

Plans: TBD

Phase 8: Decentralized Marketplace

Goal: The north star — third-party developers publish apps via the decentralized registry and users install them on their nodes Depends on: Phase 7 (publish rides the CLI; installs ride registry distribution from Phase 5 and enforcement from Phase 6) Requirements: MKT-01, MKT-02, MKT-03, MKT-04 Success Criteria (what must be TRUE):

  1. A third-party developer publishes a DID-signed app manifest to public Nostr relays (NIP-78, kind 30078) using the tooling
  2. A node discovers the published app from multiple relays and the app store UI shows its trust tier (Verified / Community / Unverified) per ADR-006 scoring
  3. The node verifies the manifest signature before installation; a tampered or invalid marketplace manifest cannot be installed
  4. A user installs the third-party marketplace-published app on their node and it runs healthy under the standard lifecycle guarantees — the user-chosen success metric, demonstrated end-to-end

Plans: TBD UI hint: yes

Progress

Execution Order: Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 (Phases 1 and 2 are independent and may be worked in parallel.)

Phase Plans Complete Status Completed
1. Federation & Mesh Hardening 11/20 In Progress
2. UI Performance 11/12 Complete 2026-07-31
3. Multinode Verification Pass 0/TBD Not started -
4. Lifecycle Perfection & Quadlet Default 0/TBD Not started -
5. Registry-Distributed Manifests 0/TBD Not started -
6. Manifest Security Enforcement 0/TBD Not started -
7. Developer Tooling CLI 0/TBD Not started -
8. Decentralized Marketplace 0/TBD Not started -
9. BotFights Platform Upgrade 7/7 Executed — awaiting human demo verification 2026-07-31
10. Key-Material Hardening 0/5 Planned — priority override, see phase note -
11. Wallet Experience & LND UI Parity 0/TBD Not started — gated on 10-05's watch-only verdict -

Phase 9: BotFights Platform Upgrade

Goal: BotFights (app + registry) works great on every node: users sign in with the native nostr signer, a single self-contained AI prompt sets up their bot (replacing the confusing docs page), and every node's instance talks to a shared public match endpoint on VPS2 so all fighters are visible and battle across all nodes. Requirements: BOT-01 native nostr signer login; BOT-02 unified AI bot-setup prompt (one copy-paste prompt, no doc-hopping); BOT-03 public shared match/fighter endpoint hosted on VPS2, node instances federate to it by default; BOT-04 registry/manifest + signed catalog updated and republished for the new version Depends on: Nothing (independent app work; parallelizable with Phases 18) Plans: 7 plans

Plans:

  • 09-01-PLAN.md — Arena reverse-proxy tracer: node instances become thin clients of one shared arena (BOT-03)
  • 09-02-PLAN.md — Finish native nostr signer login: JWT-only GET /api/auth/me, bare-pubkey path retired (BOT-01)
  • 09-03-PLAN.md — One self-contained AI bot-setup prompt served at /api/docs/prompt (BOT-02)
  • 09-04-PLAN.md — Canonical public arena on VPS2 + DNS/TLS via nginx-proxy-manager (BOT-03)
  • 09-05-PLAN.md — Build+push botfights:1.2.0, roll the arena, prove cross-instance visibility (BOT-03/BOT-04)
  • 09-06-PLAN.md — Manifest 1.2.0 with generated JWT secret + signed catalog republished (BOT-04)
  • 09-07-PLAN.md — archi-dev-box deploy + demo rehearsal: real signer login, cloud bot from the prompt (BOT-01/02/03/04)

Phase 10: Key-Material Hardening

Goal: Every path that creates, restores, or persists node key material proves the caller is authorized and the material is per-node — closing the three exploitable findings from docs/security/ENTROPY-SEED-AUDIT-2026-07-31.md. A node that is already onboarded must refuse to have its identity replaced; a node flashed from the shared rootfs must never share another node's host keys; and the wallet spending key must not exist in cleartext outside the encrypted envelope. Requirements: KEY-01 (F-01, Critical) seed.generate/seed.restore are unauthenticated (api/rpc/middleware.rs:25) and NodeIdentity::from_seed (identity.rs:79) overwrites node_key/nostr_secret/FIPS key unconditionally — one unauthenticated POST with an attacker-chosen mnemonic hijacks a live node; gate on onboarding-incomplete (the unused identity.rs:117 key_exists guard) + rate-limit; KEY-02 (F-03, High) first-boot per-device secret regeneration is fail-open and its completion marker is set even on failure (image-recipe/_archived/build-auto-installer-iso.sh:1647,:1659,:1663), over a fleet-shared cached rootfs that bakes SSH host keys + the TLS key — make it fail-closed and retried; KEY-03 (F-13, High) the BIP-84 account private key is imported into Bitcoin Core's wallet (api/rpc/bitcoin.rs:203,:229-231), duplicating the spending key outside the encrypted envelope — move to watch-only descriptors per docs/security/PSBT-SIGNING-ARCHITECTURE.md; KEY-04 on-node verification of C-3/C-4/C-6 from the audit's UNVERIFIED checklist (host-key uniqueness across two real nodes, rootfs tar contents on the build host, unauthenticated LAN reachability of the RPC endpoint); KEY-05 (F-10a, Medium, added 2026-08-02) a defaulted RNG cannot be inherited anywhere in the crate. The audit's F-10 recorded this as 2 call sites; it is 41 raw matches across 15 files (session.rs 16 → 4 prod + 12 test, pine_ha.rs 6, wallet/bdhke.rs 4 → 2 prod — Cashu proof secret + blinding factor, genuine key material, storage_crypto.rs 1 — AEAD nonce, mesh/x3dh.rs 2 — prekey identifiers, not key material, corrected 2026-08-02, +10 more; full table in the audit's §F-10a. Per-site prod/test classification is KEY-05's Task 1, not an assumption). Nothing is broken today — rand::random()/thread_rng() are ChaCha12 seeded from getrandom(2) — but this is the exact T1 structural shape that produced the 2026-07-30 COLDCARD defect, now with key material in its blast radius. Five layers, all required: (a) sealed allowlist trait at key-generation seams (private supertrait, so no other module or crate can implement it; exactly one production impl, OsRng) — this also retires the impl rand::CryptoRng for CountingRng false promise at seed.rs:656; (b) clippy.toml disallowed-methods banning rand::thread_rng/rand::random crate-wide, so enforcement is a compile failure in CI rather than a review convention (no clippy.toml exists today; CI already runs clippy); (c) cargo-deny failing on duplicate rand majors — two coexist today, which is the mechanism by which a bump could silently rebind (absorbs R-05); (d) degenerate-entropy runtime check before key generation (rejects all-zero / counter-like draws — the one layer that would catch the Coldcard failure on the device rather than in review); (e) persist the CSPRNG-readiness verdict that seed.rs:59 already computes and discards, so a node can answer after the fact "was the pool seeded when this key was born?" (absorbs R-09). Supersedes R-13 Depends on: Nothing (independent security work; parallelizable with Phases 18). Priority override: F-01 is Critical and live on every fleet node — this phase should be planned and executed ahead of its numeric position, which reflects append order in a shared roadmap, not sequencing. Plans: 6 plans

EXECUTION GATE (user instruction, 2026-08-02): do not begin executing this phase until (a) the concurrent agent working Phase 1 has finished, and (b) their changes are synced and accounted for. Rationale: Phase 10 edits middleware.rs, identity.rs, seed_rpc.rs, bitcoin.rs and — under KEY-05 — ~15 further files across the same crate that agent is actively committing to. Verify a clean tree and a fetched gitea-ai/main before starting.

KEY-05 is planned as 10-06 (added 2026-08-02). The other 5 plans predate KEY-05 and are unchanged by it. 10-06 is wave 2 because it shares seed.rs with 10-05 and api/rpc/auth.rs with 10-01; see its <file_collision_analysis>.

Plans:

Wave 1 (parallel — no shared files)

  • 10-01-PLAN.md — Identity-mutating unauthenticated RPCs hard-refuse on a provisioned node, with the byte-identity regression suite (KEY-01)
  • 10-03-PLAN.md — First-boot secret regeneration retries then fails closed, and the rootfs tar ships identity-free (KEY-02/KEY-04 C-4)
  • 10-05-PLAN.md — Delete the Bitcoin Core xprv-import path; make LND's PSBT round trip first-class, tested and honestly documented (KEY-03)

Wave 2 (each blocked on its wave-1 sibling)

  • 10-02-PLAN.md — On-node C-6 exposure measurement, live refusal proof, and the fresh-node onboarding non-regression (KEY-01/KEY-04) — depends on 10-01
  • 10-04-PLAN.md — Fleet detection of image-baked host secrets, guarded one-time rotation, and C-3 two-node verification (KEY-02/KEY-04) — depends on 10-03
  • 10-06-PLAN.md — A defaulted RNG cannot be inherited anywhere in the crate: sealed allowlist, clippy ban, cargo-deny, degenerate-entropy check, persisted CSPRNG verdict (KEY-05) — depends on 10-01 and 10-05

Phase 11: Wallet Experience & LND UI Parity

Goal: The wallet is something a user chooses and understands, not something that just appears. A first-run wallet screen lets them pick a wallet type and route accordingly; seed handling reuses the SeedQR + seed-words patterns already shipped; and the day-to-day Lightning interface offers what umbrelOS's LND UI offers, so nothing is missing for someone arriving from Umbrel. Requirements: WALLET-01 first-run wallet-type chooser (an intro/initial screen presenting the available wallet types with plain-language trade-offs, routing into the matching setup flow) — the available types depend on Phase 10's 10-05 watch-only verdict, so this requirement is gated on that evidence, not on assumption; WALLET-02 seed handling in the wallet flow reuses the existing SeedQR + seed-words components rather than reimplementing them (neode-ui/src/utils/seedqr.ts, OnboardingSeedGenerate.vue, SeedRevealPanel.vue, WalletScanModal.vue) — including the standing constraint that the LND aezeed is text-only by design and has no SeedQR; WALLET-03 evidence-based umbrelOS LND UI parity — produce a feature-by-feature comparison matrix from the actual Umbrel interface (researched, not assumed), classify each row as already-shipped / gap / deliberately-not-wanted, and close the gaps worth closing; WALLET-04 the resulting interface is house-style (Teleport-to-body modals, existing design system) and verified on the :8100 dev preview against archi-dev before any deploy; WALLET-05 the PSBT air-gap round trip is a real, usable flow — the standard two-scan dance (node displays the unsigned PSBT as an animated QR → offline signer scans and signs → signer displays the signed PSBT → node scans it back with the camera → finalize + broadcast). Three sub-gaps, all verified 2026-08-01: (a) no UI existslnd.create-psbt/lnd.finalize-psbt and their rpc-client.ts:417 wrappers are called by nothing but unit tests; (b) no animated-QR encoderqrcode/qrloop are dependencies and useAnimatedQRDecoder.ts + WalletScanModal.vue already handle the inbound scan, but nothing encodes a PSBT for display; (c) format interop is wrong for real signers — the animated format in use is qrloop (Ledger's), while Passport/SeedSigner speak BC-UR (ur:crypto-psbt) and Coldcard Q speaks BBQr; BC-UR is the priority given the existing Passport-Prime-compatible SeedQR work. WALLET-05 is meaningless until 10-05's watch-only verdict landslnd.create-psbt funds from LND's own wallet whose keys LND holds, so until LND is watch-only against the external signer the offline device would produce a signature the node does not need Depends on: Phase 10 — specifically 10-05, which produces the evidence-backed verdict on whether LND can be provisioned watch-only against an external signer. WALLET-01's list of offerable wallet types is a direct consequence of that verdict; building the chooser first would mean guessing at what it can offer. 10-05 also deletes the dead Core wallet path, so this phase never has to represent it in the UI. Plans: 0 plans

Already shipped — do not rebuild (verified 2026-08-01): LightningChannelsPanel.vue, SendBitcoinModal.vue, ReceiveBitcoinModal.vue, WalletScanModal.vue, WalletSettingsModal.vue, SeedRevealPanel.vue, LndSeedBackupPrompt.vue, utils/seedqr.ts, and the channels All/Active/Pending/Closed tabs. The parity matrix (WALLET-03) must start from this inventory so the phase closes real gaps instead of re-implementing existing surfaces.

Plans:

  • TBD (run /gsd-plan-phase 11 to break down)

Phase 12: Bitcoin Node Settings & Core/Knots Parity

Goal: The Bitcoin node's configuration is something the operator chooses in the UI, not something baked into three shell scripts. Every option umbrelOS surfaces for its Bitcoin app is reachable, the options that exist only on Knots are surfaced separately from the ones Core shares, and the node's network mode is a first-class setting whose default is Tor, not clearnet.

Requirements: BTCSET-01 a single source of truth for bitcoind arguments — today they are hardcoded and duplicated across scripts/first-boot-containers.sh:666, scripts/container-specs.sh:193-202 and apps/bitcoin-knots/manifest.yml:43, which is the exact triplication that produced the lnd-ui bridge/host defect (HTTP 000, found 2026-08-02); a persisted settings model must replace it, with those three call sites rendering FROM it rather than restating it; BTCSET-02 network mode is a setting, defaulting to Tor — Tor / clearnet / both, wired to the archy-net SOCKS listener shipped in f0494193 via -onion=<gw>:9050 (onion-only) or -proxy= (everything), with the operator's 2026-08-02 choice of onion-only as the shipped default for the "both" mode; inbound onion is out of scope and must be stated as such in the UI — it needs Tor's ControlPort, deliberately disabled for security, so the node can reach .onion peers but stays unlisted; BTCSET-03 Core options surfaced (prune, dbcache, txindex, maxconnections, maxmempool, mempoolexpiry, persistmempool, blocksonly, peerbloomfilters, blockfilterindex, and the rest of the umbrelOS set, researched from getumbrel/umbrel-bitcoin rather than assumed); BTCSET-04 Knots-only options surfaced separately and gated to Knots (datacarrier, datacarriersize, permitbaremultisig, rejectparasites, maxscriptsize, the spam-filter family) — offering a Knots-only flag on Core would produce a node that refuses to start, so the gate is a correctness requirement, not a cosmetic one; BTCSET-05 house-style UI verified on the :8100 dev preview against archi-dev before any deploy, mobile included.

The hazard this phase must not get wrong: several of these options are not freely reversible. Turning txindex on forces a full reindex; turning prune on is destructive to block data and cannot be undone without a full resync; lowering prune below what is already pruned is meaningless. Any setting in that class must be labelled, confirmed, and — where it implies hours of resync on a node that is somebody's wallet backend — refused or gated rather than silently applied. Changing any option at all requires a bitcoind restart, which interrupts LND, electrs and the fedimint gateways that depend on it.

Depends on: f0494193 (the archy-net SOCKS listener) for BTCSET-02's Tor path to exist at all. Independent of Phases 111 otherwise.

Plans: 0 plans

Plans:

  • TBD (run /gsd-plan-phase 12 to break down)

Phase 13: AIUI — Conversational Node Control & Content Surfaces

Goal: AIUI stops being a beautiful shell and becomes the node's conversational front door. Today it is embedded in neode-ui/src/views/Chat.vue as an iframe, its D-14 embed defaults are honoured, and its surfaces are designed — but the chat cannot do anything to the node, and the content views are not wired to real data. This phase makes it functional in three directions at once: (1) ask the node in human language and have it act — the capability Pine already demonstrates through voice becomes reachable from typed chat; (2) talk to the system's settings conversationally instead of hunting through screens; (3) surface the node's content beautifully — peer files, music, IndeeHub movies, owned/paid content — in the design AIUI already has but does not yet fill.

Requirements: AIUI-01, AIUI-02, AIUI-03, AIUI-04, AIUI-05, AIUI-06

Requirement detail:

  • AIUI-01 — human-language node control. A typed request in AIUI chat ("restart bitcoin", "how much space is left", "who's connected") reaches a real node action and returns a real result. The Pine stack (core/archipelago/src/api/rpc/pine_status.rs, .../package/pine_ha.rs, the wyoming/Home-Assistant voice pipeline) already proves the intent→action path exists for voice; this requirement is about exposing that capability over a permissioned tool-calling bridge the browser can reach — not about handing the chat raw RPC. Whether a text entry point exists today or must be built is the first thing the phase research must settle.
  • AIUI-02 — conversational settings. The system settings surfaced across neode-ui become reachable by conversation, scoped to what the user has granted.
  • AIUI-03 — content surfaces made real. AIUI's designed-but-empty content views render live node data: peer files (the /content, /content/<id>, /api/peer-content/<onion>/<id> subsystem and the content.* RPCs), music (today only a MIME branch and a hardcoded Music folder — there is no library domain, so scope must be honest about what "music" means here), IndeeHub movies, and owned/paid content. Playback must respect the existing rules: audio belongs to the global bottom-bar player, never the lightbox; media streams via Range requests, never base64 blobs.
  • AIUI-04 — sandboxed by construction, permissioned by the user. (see hazard below — this is the gating requirement, not a nice-to-have)
  • AIUI-05 — delivery and build. AIUI is a *-ui app outside the signed catalog; it reaches nodes on the frontend rsync, which is how the /assets 404 happened (fixed in fbec7006). A functional AIUI needs a delivery path an operator can actually receive updates through, and the VITE_BASE_PATH=/aiui/ build requirement pinned so a hand-built bundle cannot ship a black page.
  • AIUI-06 — verified on device, in the real embedded iframe on archi-dev-box, mobile included — not only in the local dev:mock loop.

The hazard this phase must not get wrong — an LLM is now touching a node that holds keys. AIUI runs in the browser and talks to a model. The node holds wallet keys, LND macaroons, Fedimint credentials, node identity and per-app secrets, and Phase 10 is currently hardening exactly that material. So: secrets never reach the browser or the model context — the existing pattern where credentials stay server-side and the client gets a scoped token (app.filebrowser-token) is the model to follow, not an exception to it. The chat gets an explicit, user-granted capability scope — it can reach only what the user has allowed, defaults closed, and the grant is visible and revocable. Destructive and identity-touching operations are confirmed by the human, never executed on model say-so alone; the Phase-10 hard-refuse gates and the loopback/auth boundaries must hold with AIUI on the other side of them, not be widened to accommodate it. Prompt injection is in the threat model: peer-supplied content (filenames, descriptions, chat) will enter the model's context, so tool authority must not be derivable from anything a peer controls. Note also the known leak to resolve rather than propagate: filebrowser-client.ts puts a JWT in the media URL query string.

Depends on: Independent of Phases 112 for its UI and content work. Its security model must not contradict Phase 10 (Key-Material Hardening) — coordinate rather than widen. AIUI's own source lives in a separate repository (git.tx1138.com/lfg2025/AIUI, branch development, cloned at ~/Projects/AIUI), so this phase spans two repos and needs push access to both.

Plans: 14/15 plans executed

Plans:

Wave 1 (tracer + the two independent security/spike tracks)

  • 13-01-PLAN.md — TRACER: typed AIUI chat reaches a real node tool and returns a real result (AIUI-01)
  • 13-02-PLAN.md — Close the live unauthenticated model proxies: session-gated Rust forwarder, port-3142 sidecar deleted (AIUI-04)
  • 13-03-PLAN.md — Routstr protocol spike + capability coverage matrix (AIUI-01)

Wave 2

  • 13-04-PLAN.md — Music library: one-way entity-model decision + lofty legitimacy gate + tag extraction (AIUI-03)
  • 13-05-PLAN.md — Curated tool registry, D-09 authority ceiling, D-16 default-closed grants, conversational settings (AIUI-01/02)
  • 13-06-PLAN.md — Content surfaces: ContentItem → Film/Song/Podcast adapter, AIUI grids fed from Archy (AIUI-03)

Wave 3

  • 13-07-PLAN.md — Music index + music.* RPCs + freshness (AIUI-03)
  • 13-08-PLAN.md — D-11 confirm gate: node-authored, nonce-bound, rendered in trusted chrome (AIUI-01/04)

Wave 4

  • 13-09-PLAN.md — AIUI delivery: enforced build, pinned commit, live-asset verify, iframe sandbox mechanism (AIUI-04/05)
  • 13-10-PLAN.md — D-04 chain: Ollama tool-calling + D-08 node-side history (AIUI-01)
  • 13-11-PLAN.md — SongGrid lit from the real library + the m4a/aac/opus/wma share-mime fix (AIUI-03)

Wave 5

  • 13-12-PLAN.md — D-10 untrusted-content boundary + cloud-egress guardrails + rate limiting (AIUI-04)

Wave 6

  • 13-13-PLAN.md — Routstr backend + D-05 hard budget ceiling (AIUI-01)

Wave 7

  • 13-14-PLAN.md — Eval harness: ScriptedBackend suite, EV-01..EV-18, cross-backend parity (AIUI-01/04)

Wave 8

  • 13-15-PLAN.md — On-device sign-off: archi-dev-box, embedded iframe, desktop + mobile (AIUI-06)

Track note (D-13): the music-library track (13-04 → 13-07 → 13-11) is independent — no plan on the control or content track depends on any music plan, and neither does the phase-closing gate. 13-15 depends on 13-06, 13-09 and 13-14 only, so there is no path from it to 13-04, 13-07 or 13-11: if the music track slips or is deferred, 13-15 records that at its step 7b and the control and content work still closes and ships. 13-11 is therefore a terminal plan of the phase rather than a gate on it.