Two real install failures from .116 today: (1) the hard "ElectrumX must
be running" gate — but mempool-api reconnects to electrum on its own and
a resync can take days, so it's now a warning; (2) a 10s podman-ps probe
timeout tripped by ElectrumX compaction disk load — now 45s.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
AppLauncherOverlay sat at z-2400 under BaseModal's z-3000, so an app
opened from e.g. the Transactions modal loaded invisibly underneath it.
z-4000 lets the existing enter animation play over the modal; closing
the app returns to the modal you came from.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Pruned nodes can't run the Mempool app, but tx links blindly opened it
anyway. Now: local app when running; otherwise an external explorer
(default tx1138.com) behind a one-time amber consent modal that spells
out what the other server's operator learns (tx of interest + IP) and
lets the user point at their own instance (placeholder mempool.guide).
Wallet Settings gains an On-chain tab (explorer URL + don't-warn toggle);
tabs renamed Cashu/Fedi so five fit in the row.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Backend streams LND /v1/transactions/subscribe (fires on mempool arrival
and each confirmation) and nudges the /ws/db revision per event; the Home
wallet card subscribes and refetches (debounced 800ms). An incoming
broadcast now appears while the 30s poll is still asleep. Reconnects
forever with capped backoff when LND is down/locked/absent.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
LND's RPC answers before its p2p server finishes loading, so connect/open
during that window failed red with the raw "server is still in the
process of starting". Now: quiet ~30s retry first; if still starting, a
calm amber "still finishing its startup" notice instead of an error.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Android/rust/archy-fips-core: leaf-only fips node as a JNI cdylib (fips
pinned to the fips-native fork rev with VpnService fd support), built by
gradle via cargo-ndk (arm64), tested on host
- ArchyVpnService: split-tunnel VpnService routing only fd00::/8 (MTU 1280,
foreground specialUse); FipsManager handles the one-time VPN consent and
silent auto-start — no settings surface at all
- pairing QR now fully configures the mesh: fnpub/fip/fhost/fudp/ftcp plus
fanchors (the node's seed-anchor list, npub@addr/transport) so the phone
can rendezvous through public anchors when the LAN endpoint is unreachable
- default seed anchors gain the two dual-transport join.fips.network test
anchors (23.182.128.74:443/tcp, 217.77.8.91:443/tcp); anchor adverts are
Nostr kind-37195 events
- device token rides the password field end-to-end: backend accepts tokens
wherever it accepts the password, so scan = instant login (WebSocket auth
+ WebView form injection unchanged); token logins skip TOTP
- ServerEntry.meshIp + IPv6-bracketed URLs; WebView retries the mesh address
on main-frame errors, auto-login and origin checks honor it
- companion v0.5.0 (versionCode 20), arm64 abiFilter; FipsNative.available
gates everything so non-arm64 still runs as a plain companion
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- auth.createDeviceToken / listDeviceTokens / revokeDeviceToken RPCs; only
SHA-256 hashes persist in data_dir/device-tokens.json
- auth.login accepts {token} (same rate limiter, skips TOTP like remember-me)
- pairing QR now carries name (server name, fallback "My Archipelago"),
tok (instant login), and FIPS mesh params from new fips.pair-info RPC
(npub, fips0 ULA, transport ports)
- companion onboarding drops the WireGuard install/tunnel screens — remote
access moves to the FIPS mesh embedded in the companion app
- fix: fips daemon UDP bind now 2121, matching the published container port
and fleet rosters (was upstream's 8668 — inbound UDP was dead on bridged
installs, mesh silently rode TCP 8443)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Plugging in any LoRa radio now surfaces the device setup modal EVERY time
(dismissals clear on unplug; works while mesh is enabled; 2-poll debounce
so ordinary reconnect blips don't flash it), showing what's currently on
the stick before anything is written:
- mesh.probe-device RPC: identifies the firmware read-only in the same
Reticulum->Meshcore->Meshtastic order as auto-detect. Meshtastic yields
region/modem-preset/channels (want_config is a read); MeshCore yields
name/node-id + firmware version via the previously-unused
CMD_DEVICE_QUERY; RNode via the bare KISS DETECT (no daemon spawn).
Path must be a detected candidate port; the live session's port refuses.
- "Keep As Is": manage_radio=false persists in MeshConfig and the session
skips every on-connect config write (region, channel, PHY params, advert
name) — the radio runs exactly as flashed, hot-swappable.
- "Set Up with Archipelago Settings": second screen shows the params that
will be applied (channel, region, the node's persisted RF params - e.g.
the validated Portugal preset - with the per-region community plan as
fallback) before writing anything.
- Stale-type fix: disconnect now resets device_type/firmware_version, so
a swapped stick no longer shows the previous radio's firmware; probed
kind pins device_kind so the right probe runs first on connect.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Both lived only in RAM: every archipelago restart/reboot wiped the whole
chat history (user-reported), and — worse — reset the per-target outbound
sequence counters, so peers' (sender_pubkey, sender_seq) dedup silently
dropped the first messages sent after a reboot as replays.
mesh-messages.json in the data dir (0600 — DM plaintext), restored in
MeshService::new before the listener spawns; a 5s debounced persister
task snapshots at one choke point instead of hooking every mutation path
(store, delivered/transport/encrypted stamps, edits, deletes, prunes).
Atomic write-then-rename; corrupt/missing file skips restore instead of
blocking mesh startup.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Image default is beam 5 on x86 (1 on ARM). Benchmarked on framework-pt
(i5-1135G7, base-int8, real speech): beam 1 transcribes identical text
~45% faster; extra CPU threads made it slower, so only the beam changes.
App revision 3.4.2 > image 3.4.1 so catalog-driven nodes roll the args
change; a 3.4.1-1 suffix would semver-compare LOWER and never ship.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The seeded announce automation blocked state transitions out of None/
unavailable — but None is exactly the sensor's state before the first
received message (and after the in-memory store restarts empty), so a
fresh node's first DM was silently swallowed (framework-pt 2026-07-22).
Only 'unknown' (the HA-restart marker) still blocks; rest sensors don't
restore state, so restart announce-storms remain impossible. Seeder
upgrades an already-seeded automations.yaml by replacing exactly the v1
clause, leaving user edits untouched.
Sensor scan_interval 30->15s: the sensor only carries the latest message
id, so two messages inside one poll window coalesce into one announce —
halving the window halves both the lag and the coalescing odds.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Home wallet card counted every incoming tx with num_confirmations < 3
in the pulsing 'Incoming N' badge. Lightning history hardcodes 1 conf and
ecash/fedimint/ark receives are normalized to 1 conf, so instant payments
qualified permanently — old receives showed as 'incoming' forever (seen
on .228 with week-old lightning orders).
- On-chain keeps confirmation-based logic (< 3 confs, expires naturally).
- Instant rails (lightning/cashu/fedimint/ark) now surface in the incoming
panel only for 5 minutes after receipt — the nice arrival moment without
the perpetual pending state.
- Panel rows: 'Unconfirmed / N conf' badge and mempool link are now
on-chain-only; instant rows get a rail badge instead.
- Home now polls wallet balances+transactions every 30s (like Web5.vue),
so pending on-chain receives actually flip to confirmed and the badge
appears/expires without a manual wallet action.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sensors with a unit (sync %, lightning/onchain sats) rendered the string
'None' when bitcoind is early in IBD or LND is down, which HA rejects
with a ValueError on every 30s scan. Mark them unavailable instead; the
intent scripts already speak a fallback for unavailable states.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Regression: only X-Frame-Options apps were routed to the companion's
in-app WebView; iframeable apps fell through to the iframe session, which
is slower on the phone and loses the native back/forward/reload controls.
Now any launch inside the companion (ArchipelagoNative.openInApp bridge
present) goes to the WebView — both openSession and the legacy open()
overlay fallback. Mobile web/PWA keeps the iframe session. With regression
tests.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
HA's seeded REST sensor reads attributes via json_attributes_path
"$.mesh_message"; a null there makes HA log a "JSON result was not a
dictionary" warning on every 30s scan.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
HA's config-entries store already carries the current schema minor_version,
so entries we append are never migrated — a missing created_at is an
unguarded KeyError in config_entries.async_initialize that crash-loops HA
at boot (hit on framework-pt during install verify). Write created_at/
modified_at/discovery_keys/subentries on both the anthropic and wyoming
entries.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The creds-off-argv script used printf "rpcuser=%s" in the manifest's
custom_args; quadlet copies Exec= into the generated service's ExecStart,
where systemd expands %s (user's shell) at load time — bitcoind's rpc.conf
came out as rpcuser=/bin/bash and every RPC consumer got 401s on quadlet
nodes (framework-pt: bitcoin-status, HA block-height sensor, LND chain RPC).
Two-layer fix: quadlet.rs now escapes % -> %% in Exec/Entrypoint/HealthCmd/
Environment emission (with regression test), and the bitcoin manifests write
rpc.conf with plain echo so the catalog also heals nodes still running older
binaries. Release catalog regenerated with the fixed scripts.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The info card above the action buttons now shrinks with the viewport and
scrolls internally (min-h-0 + overflow-y-auto in a max-h-full flex column),
keeping Cancel / Sign & Publish always visible. The hero disc and viz ring
scale down on narrow or short screens via a --seg-radius CSS variable so
the animation honors the smaller ring.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
pine-openwakeword manifest (wyoming-openwakeword 2.1.0, :10400, /custom model
dir for the future Yo Archy model). Pine 1.3.0: launcher page gains a live
node-status card fed by /api/pine/status via a same-origin nginx proxy, and
copy for the new intents / Claude fallback / mesh announcements. Catalogs,
app-session config, drift ids regenerated; release catalog embeds 56
manifests (unsigned until the ceremony). Framework PT test plan in docs/.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- GET /api/pine/status: public tier (version/uptime/bitcoin/mesh facts) for
the Pine page; bearer-token tier (Lightning balances, latest mesh message)
for the seeded Home Assistant sensors. Token minted 0600 at
secrets/pine-status-token; nginx location ships via the bootstrap
self-heal + canonical ISO conf. Replaces the per-node socat forwarder and
bitcoind RPC credentials living in HA's configuration.yaml.
- pine_ha seeder: REST sensors + four ask-Archy intents (block height,
peers, sync %, Lightning balance) with LLM tool descriptions; Claude
conversation agent (anthropic entry from the node's claude-api-key) set as
pipeline default with prefer_local_intents so exact phrases stay local and
fuzzy ones tool-route through Claude; mesh-message announce automation on
every Assist satellite; bounded config markers with legacy-block migration.
- pine-openwakeword joins the pine stack (all lifecycle sites) — on-node
wake-word engine groundwork for the custom "Yo Archy" model.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Enabling Nostr discoverability now opens a signer overlay (same visual
language as the app NIP-07 identity picker) before anything is published:
a locked signer row fixed to the node's discovery key — deliberately not
pickable, personal identities are never used — plus the exact signed
content (DID, npub, software version, kind 30078/NIP-33 format) and a
Sign & Publish confirm. Disabling stays immediate. Also seeds the mock
with discovery OFF to match the production default, and defaults
dwnSyncLabel to 'Unknown' when the backend omits sync_status.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The mock previously returned a placeholder string with no nostr_npub, so the
new Federation signing-details panel showed 'loading…' forever against the
mock. Now returns a distinct discovery key — 64-char hex plus its real
NIP-19 bech32 encoding (verified against the official test vector) —
mirroring production where the node discovery key is separate from the
personal identity keys.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds a 'Signing details' disclosure showing who signs the presence event —
a locked identity row (styled like the NostrIdentityPicker overlay) fixed to
the node's own discovery key, deliberately not pickable so personal
identities can never be used for node discovery — plus a human-readable
breakdown of the signed content: DID, signing npub, software version, and
the event format (kind 30078, NIP-33 replaceable, d-tag archipelago-node),
with a note that every event carries a NIP-01 Schnorr signature.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
On single-column (mobile) the dashboard cards now order My Apps, Wallet,
Cloud, Network; desktop keeps its existing two-column layout via
lg:order-none resets.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Wallet scan modal: fallback buttons no longer flash on open (spinner while
the camera auto-starts, video hidden until live — also kills the Android
WebView play-glyph), decode rate 10/s -> 4/s (preview visibly lagged on
phones), clear messages for BOLT12 offers and LNURL/lightning addresses
(unsupported by the LND backend; full LNURL-pay is a queued feature),
zero-amount invoices in BIP21 URIs prefill from amount=.
- Pine 1.2.0: launch-page copy reflects the auto-seeded HA wiring (only
speaker pairing stays manual), adds the ask-Archy hint and the
silent-answers power-cycle troubleshooting tip (firmware FIFO bug).
- bitcoin-core/knots: rpcuser/rpcpassword move from bitcoind argv (world-
readable in host ps) to a 0600 config file inside the container tmpfs;
the salted txrelay rpcauth hash stays on argv. Catalog regenerated.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Out of the box, HA needed manual clicks for each Wyoming engine, a
hand-built Assist pipeline, and knew nothing about the node. Now installing
the Pine stack (or HA, whichever comes second) seeds:
- wyoming config entries for pine-whisper (:10300) and pine-piper (:10200)
- an Assist pipeline wired to stt.faster_whisper + tts.piper, and a repair
for the legacy 'homeassistant' conversation-agent id that modern HA
rejects (intent-not-supported on every wake word otherwise)
- 'ask Archy' voice intents (custom_sentences + intent_script), starting
with block height via a mempool REST sensor when that app is present
Seeding is best-effort, idempotent, and never overwrites an existing store
it can't parse; HA restarts only when something was written.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replace the display-mode dropdown with three inline buttons (right panel /
over whole app / fullscreen) so switching iframe modes is a single click.
Active mode is highlighted orange. Mobile keeps its own bar untouched.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
HA 2024.1's Wyoming integration predates ping/pong keepalives. The PineVoice
satellite firmware (wyoming 1.7.2) drops connections idle for ~8s, so HA
looped on 'Satellite disconnected' forever and the speaker never worked.
HA 2026.7.3 pings satellites and holds the connection (verified on
framework-pt: link stays ESTABLISHED, wake word reaches Assist).
Catalog regenerated with the bump — needs the signing ceremony before the
origin publish.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The kiosk image ships no color-emoji font, so the wallet card's 🥜 and ⚓
drew as empty squares on TVs. Swap them for inline stroke SVGs matching
the neighbouring rows (wallet card + scan modal), and add
fonts-noto-color-emoji to the ISO package set so remaining emoji across
the UI (peer files, chat, content) render on future installs.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
App.vue skipped starting the browser-side remote relay on kiosks, citing a
system-level xdotool injector that no longer exists — the backend's
remote-input path is relay-only (validate + broadcast). With no consumer,
companion input was silently dropped on TVs. Start the relay on kiosks
like everywhere else; rides the next release + ISO via the web bundle.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two gaps kept the wallet QR scanner camera-less outside a desktop browser:
- Companion app: the WebView's default WebChromeClient silently denies
getUserMedia. Both WebViews (main + in-app overlay) now implement
onPermissionRequest — granting video capture only, requesting the
app-level CAMERA permission on first use (manifest already declares it).
- Plain-http origins (mobile web/PWA on a LAN node): browsers hide
navigator.mediaDevices entirely, no permission can bring it back. New
"Take photo of QR" fallback uses <input capture=environment> — the
native camera needs no secure context — and decodes the shot locally
with qr-scanner's scanImage. Live preview still used when available.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
All Zeus channel surfaces now read: "Open a channel with Zeus Olympus
node and start sending and receiving Lightning payments. Minimum
150,000 · maximum 1,500,000 on-chain sats required."
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
AIUI persists aiui-theme in localStorage and a stored value beats its
prefers-color-scheme fallback, so kiosk profiles from before the launcher
forced a dark color scheme keep white panels forever. Kiosk boot now pins
the same-origin key to dark, healing existing profiles on next load.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The onboarding-era :global(html.kiosk-mode .view-wrapper) transform:none
rule also matched the dashboard's route wrappers, freezing every list<->
detail depth transition into a jump cut on kiosk. Scope that rule to the
onboarding viewport and give the dashboard kiosk-safe 2D equivalents
(scale + opacity, no translateZ/blur/preserve-3d) that the software
compositor can animate.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
system.kiosk-display.get/set RPCs write /etc/archipelago/kiosk-display.conf
(sourced by the kiosk launcher) and try-restart the kiosk so the choice
applies immediately. The Settings section only appears on nodes that have
the kiosk unit installed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>