diff --git a/.planning/phases/13-aiui-functional-conversational-node-control-and-content-surf/13-CONTEXT.md b/.planning/phases/13-aiui-functional-conversational-node-control-and-content-surf/13-CONTEXT.md new file mode 100644 index 00000000..9ad05849 --- /dev/null +++ b/.planning/phases/13-aiui-functional-conversational-node-control-and-content-surf/13-CONTEXT.md @@ -0,0 +1,319 @@ +# Phase 13: AIUI — Conversational Node Control & Content Surfaces - Context + +**Gathered:** 2026-08-03 +**Status:** Ready for planning + + +## Phase Boundary + +Make the embedded AIUI functional in three directions: (1) **human-language node control** — +a typed request in AIUI chat reaches a real node action and returns a real result; +(2) **conversational settings** — system settings reachable by conversation, scoped to what +the user granted; (3) **content surfaces made real** — peer files, music, IndeeHub movies and +owned/paid content rendered live in the design AIUI already has. All of it inside a +**user-granted capability sandbox** that keeps keys, secrets and identity material away from +both the browser and the model. + +**Not in scope:** cross-node content distribution with payments (the "archipelago content +source"); wallet spends, seed/key operations, federation trust changes and factory reset as +chat-reachable actions; Nostr integration polish; reviving the dead `ContentPanel.vue` +architecture. + + + + +## Implementation Decisions + +### Where the agent loop lives + +- **D-01:** The agent loop (model call → tool call → result → model) runs **node-side in + Rust**. The `archipelago` binary owns the loop, the tool registry, and the model key. AIUI + becomes a thin chat client. Rationale: the key never reaches the browser; tool authorization + sits where session auth already lives; Pine/voice can reuse the same tools later. + — **Reversibility:** costly — the RPC surface becomes a contract AIUI, and later the voice + pipeline, are written against; moving the loop browser-side afterwards means re-homing key + handling and re-implementing every tool in TypeScript. + +- **D-02:** **One assistant, many front doors.** Extend the existing mesh assistant into a + shared service: one tool registry, one backend selector, one place keys live. Mesh/LoRa, + AIUI chat and (later) Pine voice are callers distinguished by permission scope. Avoids two + divergent security models. Note the existing peer-facing controls — `trusted_only`, + `allowed_contacts`, `denied_askers` — are a per-caller scope mechanism that already exists. + +- **D-03:** **Split by nature.** The node-side registry owns everything that reads or changes + the node (system, bitcoin, network, wallet, files, media). The existing `ContextBroker` + keeps only what must run in the browser — `navigate`, `open-app`, `launch-app`, `theme` — + and remains the consent surface pushing `permissions:update`. Nothing is discarded; each + side owns what only it can do. + +- **D-08:** Chat history lives **node-side in the per-node data dir** (`/var/lib/archipelago`), + inheriting the node's backup, factory-reset and future LUKS story rather than growing a + second sensitive-data location. + +### Model backends + +- **D-04:** Backend chain is **local Ollama first, with Claude *and* Routstr as fallbacks**. + Node data never leaves the node when a local model is available. The assistant already + reports `ollama_detected` / `claude_available`, so the selection signals exist. + **Routstr () is explicitly in scope at the user's request** — + it is an OpenAI-compatible endpoint paid per request in Cashu ecash, with providers, models + and prices discovered over Nostr. All three of those substrates already exist in this + codebase (`core/archipelago/src/streaming/` holds Cashu token handling and the + `list-mints`/`configure-mints` RPCs; Nostr discovery is ADR-003/ADR-006). + +- **D-05:** Routstr spending is authorized by a **prepaid budget the user sets**. Inference + spends silently within the allowance, then stops and asks. The ceiling is hard — a + prompt-injected model cannot exceed it. + — **Reversibility:** reversible — the ceiling is a config value, not a contract. + +- **D-07:** The **local model does get tools**, and every write needs confirmation regardless + of backend. A mis-called tool from a weak local model surfaces as a confirmation prompt the + user rejects, not a wrong action. Consequence: the confirm gate does the safety work, so + **backend choice stays a privacy decision rather than a safety one**. + +### Authority and sandboxing + +- **D-06:** Tools are a **curated allowlist of hand-written tools** — each with its own + schema, permission category, and destructive/confirm flag. The model never sees the full RPC + surface. No auto-generation from the dispatcher: every capability the chat has must be a + decision someone made, which is the only way the sandbox claim stays true. + — **Reversibility:** reversible — adding tools later is additive; the allowlist is the point. + +- **D-09:** First-cut authority is **reads within granted categories + app lifecycle + (start/stop/restart) + settings writes**. Explicitly excluded from chat reach: keys, seeds, + wallet spends, federation trust, factory reset. Those stay UI-only. + — **Reversibility:** costly — widening later is safe, but any capability shipped and then + withdrawn breaks a behaviour users will have learned. + +- **D-10:** **Tool authority never derives from content.** Peer-supplied text (file names, + content descriptions, mesh chat, Nostr posts) enters the context inside explicit + untrusted-content delimiters that mark it as data, not instructions. The tool layer takes + its permissions solely from the user's grants and the confirm gate. An injected "now restart + bitcoin" still has to clear a human confirmation naming the real action. Pattern-stripping + filters were considered and **rejected** as an arms race that reads as a guarantee it isn't. + +- **D-11:** Write confirmations render **in neode-ui's trusted chrome, outside the iframe**, + drawn by the host from the node's own description of the pending action — never by AIUI and + never from model-authored text. The iframe cannot spoof, restyle or pre-click it. Uses the + project's mandated Teleport-to-body modal pattern. + — **Reversibility:** costly — this is the load-bearing anti-spoofing property; moving the + dialog inside the iframe later would invalidate the threat model, not just the styling. + +- **D-16:** All 10 permission categories (`apps`, `system`, `network`, `wallet`, `files`, + `media`, `search`, `ai-local`, `notes`, `bitcoin`) **default closed** on a fresh node. + Nothing is shared with the model until deliberately granted. The assistant looks + unconfigured until the user opens categories — accepted cost. + +- **Hard constraint from Phase 10:** the `UNAUTHENTICATED_METHODS` hard-refuse gates and the + loopback/auth boundaries must hold with AIUI on the other side of them. They are not to be + widened to accommodate this phase. See `10-CONTEXT.md` D-01..D-04. + +### Content surfaces + +- **D-12:** **Feed the existing grids from Archy, replacing the LLM-synth source.** AIUI's + design is kept exactly — `FilmGrid`, `SongGrid`, `NewsGrid`, the detail views — and what + fills them changes: peer files, IndeeHub movies, owned/paid content and node media arrive as + real records instead of being regex-scraped out of model prose. + — **Reversibility:** reversible — the grids are prop-driven; the data source behind them is + swappable. + +- **D-13:** **Build a real music library** — albums, artists, tracks, tag/metadata extraction, + an index that stays fresh. The user chose this over the narrower MIME-filtered-files option + after being told no library domain exists today. It lands as **its own wave of plans inside + Phase 13, not blocking the rest** — peer files, movies and conversational control ship on + their own track and the library lights up `SongGrid` when ready. + — **Reversibility:** one-way — an album/artist/track schema and its on-disk index become a + persisted data model with a migration cost once nodes have indexed libraries; changing the + entity model afterwards needs a reindex path, not just a code change. + +- **D-14:** **IndeeHub and peer video are surfaced through the content + paid-unlock + subsystem that already exists** (invoices, `X-Payment-Token`, Range streaming). No new + payment rail. The cross-node "archipelago content source" from the Phase 2 note is deferred + — it is a distribution and payments feature spanning federation, not an AIUI surface. + +### Delivery and the two-repo split + +- **D-15:** AIUI is **built and shipped with the frontend, versioned and verified** — the + rsync path is kept because it is the one that works, but made deliberate: AIUI's commit + pinned in this repo, `VITE_BASE_PATH=/aiui/` enforced by the build script rather than + remembered, and a post-deploy check that **fetches a live asset** instead of trusting a + directory listing. Making AIUI a signed-catalog app was considered and rejected for this + phase: `*-ui` apps are outside the catalog by design today, and changing that platform rule + mid-phase is its own work. + +- **D-17:** AIUI **keeps its standalone mode**; embedded mode delegates to the node. It goes + on working on its own with its own proxy for development and for anyone running it outside a + node; when `embedded=true` it hands the loop, the tools and the key to Archy. The dev loop + stays fast — no node required to work on the UI. + +- **D-18:** **Push access to the AIUI repo is confirmed before planning starts**, treated as a + prerequisite rather than discovered mid-plan. Last time this surfaced at execution and left + neode-ui shipping two query params that were inert no-ops against every deployed AIUI build + until a maintainer merged (see `.planning/WINDOWS.md` window 4). + +### Claude's Discretion + +- What the music library indexes over (own filebrowser `Music` folder, peer audio, or both), + the tag-extraction library, and where the index lives — within D-13's bounds. +- Streaming/token delivery for chat responses; context-window budgeting over node data. +- Which specific tools make the first curated allowlist, within D-09's authority ceiling. +- Routstr provider selection strategy among Nostr-advertised providers. +- Per-category mapping of the 10 permission categories onto individual tools. + + + + +## Canonical References + +**Downstream agents MUST read these before planning or implementing.** + +### The existing AIUI bridge (this is NOT greenfield — read before designing anything) +- `neode-ui/src/types/aiui-protocol.ts` — protocol v1.0.0, `aiui:` message prefix, the + request/response contract. Defines `AIContextCategory` (10 categories) and `AIActionType` + (`install-app | open-app | navigate | launch-app | search-web | read-file | tail-logs`). +- `neode-ui/src/stores/aiPermissions.ts` — the 10 user-toggled permission categories with + labels; `isEnabled` / `toggle`. +- `neode-ui/src/services/contextBroker.ts` — the 624-line origin-scoped postMessage broker + that "checks permissions, fetches data from Pinia stores, sanitizes it (strips sensitive + fields), and responds". The asset D-03 splits. +- `neode-ui/src/services/__tests__/contextBroker.test.ts`, `neode-ui/src/views/__tests__/chatAiuiEmbed.test.ts` — existing coverage to keep green. +- `neode-ui/src/views/Chat.vue` — the iframe embed, `aiuiUrl` construction, origin check, the + `ready` handshake, `allow="microphone"`. + +### The existing node-side assistant (the thing D-02 extends) +- `core/archipelago/src/api/rpc/mesh/assistant.rs` — `mesh.assistant-status` / + `mesh.assistant-configure`; reports `ollama_detected`, `claude_available`, `models`, + `trusted_only`, `allowed_contacts`, `denied_askers`; key at `data_dir/secrets/claude-api-key`. +- `core/archipelago/src/mesh/listener/assist.rs` — `run_assist`, `is_sender_allowed`, + `call_ollama`, `call_claude`, `cap_reply`. **Q&A only — no tool-calling today.** +- `core/archipelago/src/api/rpc/dispatcher.rs` — the method registry (`mesh.assistant-*` at + ~445). **Confirmed: there are no `pine.*` methods** — Pine has no RPC surface. + +### Routstr (new integration, user-requested) +- — org; `routstr-core`, `routstrd`, `routstr-sdk`, `routstr-chat`. +- — protocol docs. +- `core/archipelago/src/streaming/` — existing Cashu handling (`gate.rs` verifies/receives + tokens, `pricing.rs`, `session.rs`) and the `streaming.list-mints` / `.configure-mints` RPCs. + Note: currently `#![allow(dead_code)]`, "suppress dead_code until callers land". + +### Content subsystem (what D-12/D-14 wire the grids to) +- `core/archipelago/src/content_server.rs` — `ContentItem` shape (`id`, `filename`, + `mime_type`, `size_bytes`, `description`, `access`, `availability`, `added_at`), + `AccessControl` (`Free | PeersOnly | Paid`), `parse_range_header`, the paid-preview logic + and the ISOBMFF faststart check. +- `core/archipelago/src/api/handler/content.rs` — `GET /content`, `/content/`, + `/preview`, `/invoice`; Range → 206 with `Content-Range`; 402 body with `price_sats`. +- `core/archipelago/src/api/handler/proxy.rs:188-265` — the peer Range-streaming proxy + (`/api/peer-content//`). Its docstring explains why base64 blobs broke seeking. +- `core/archipelago/src/api/rpc/content.rs` — the `content.*` RPCs including + `browse-peer`, `download-peer*`, `preview-peer`; auto-filing by MIME at ~668. +- `neode-ui/src/composables/useAudioPlayer.ts`, `neode-ui/src/components/GlobalAudioPlayer.vue` + — the singleton bottom-bar player. **Audio never opens the lightbox** — enforced in 5 places. +- `neode-ui/src/api/filebrowser-client.ts` — the scoped-token pattern (`app.filebrowser-token`) + that D-01 follows. **Known leak to fix rather than propagate:** `streamUrl` puts the JWT in + the URL query string. + +### Prior phase context (locked decisions that constrain this phase) +- `.planning/phases/10-key-material-hardening/10-CONTEXT.md` — D-01..D-04, the + `UNAUTHENTICATED_METHODS` hard-refuse gates. **Must not be widened.** +- `.planning/phases/02-ui-performance/02-CONTEXT.md` — D-14 (the shipped AIUI embed defaults) + and the Deferred Ideas block, which is the origin of this phase. +- `.planning/phases/02-ui-performance/02-AIUI-D14.md` — the embed parameter contract, AIUI's + repo location and branch, and the push-access history. +- `.planning/WINDOWS.md` window 4 — the 403 that made D-18 a prerequisite. + +### Project invariants +- `CLAUDE.md` — commit/push discipline, rootless-Podman invariant, the frontend-build verify + rule (grep the built bundle), "verify on the real node before any tag". +- `.planning/PROJECT.md` — ADR-003 (Nostr discovery), ADR-006 (DID-signed, trust tiers), + ADR-008 (dual keys from one seed), ADR-009 (container security). + + + + +## Existing Code Insights + +### Reusable Assets +- **The permission + consent layer already exists** — 10 categories, a store, a broker that + sanitizes, and tests. This phase extends it rather than inventing it. +- **The assistant already abstracts two model backends** and already holds a key server-side + at `data_dir/secrets/claude-api-key` — the pattern D-01 generalizes. +- **Cashu, Nostr and Lightning are all already in-tree**, which is why Routstr is a smaller + lift here than it would be elsewhere. +- **Range-streaming media delivery is solved** — both own files (filebrowser `/api/raw`) and + peer files (the Rust proxy). The grids need data, not a transport. + +### Established Patterns +- Audio belongs to the global bottom-bar player, never the lightbox (enforced in 5 call sites). +- Modals Teleport to body for a full-screen backdrop (project rule, repeatedly reinforced). +- Scoped tokens minted by an authenticated RPC, credentials never reaching the browser. + +### Integration Points +- `dispatcher.rs` — where new assistant/tool RPCs register. +- `ContextBroker.handleMessage` — where the browser-only action split (D-03) lands. +- `ChatPage.vue` → `ContentGridView.vue` → the `*Grid` components — the live render tree the + Archy data must reach (**note `ContentPanel.vue` is dead; do not build through it**). + +### Landmines found during scouting (verified, not assumed) +- **AIUI's grids are fed by regex-parsing the model's own reply text** (`updatePanelFromText` + → `contentExtraction.ts`), resolving IDs against fixture catalogs that are themselves + injected into the system prompt (`useAI.ts:24-34`). The largest data bucket is + LLM-synthesized, not an API awaiting a base URL. +- **Every "real" data path in AIUI is Vite dev middleware** — all six plugins are + `configureServer`/`configurePreviewServer` only, so they are **absent from a static `dist/` + deploy**. On a node, TMDB posters, web search, RSS and filesystem all 404. +- **`vite-fs.ts:7` hardcodes `PROJECTS_ROOT = '/Users/dorian/Projects'`** — broken on any + other machine, including the Linux dev box. +- **`ContentPanel.vue` is dead code**, taking `ArchyAppsGrid` (the Archy bridge grid), + `FavoritesGrid`, `DiscoverPanel`, `RecipeDetail` and `AppDetail` with it. Clicking a recipe + or an app currently does nothing. +- **`ShareModal.vue`'s mime map omits `m4a`/`aac`/`opus`/`wma`** — those share as + `application/octet-stream`, so they never route to the audio player and are auto-filed to + `Documents` instead of `Music`. Relevant to D-13. + + + + +## Specific Ideas + +- Routstr was named by the user directly, with the repo link, and asked to be planned in as + part of the backend work — not treated as a future option. +- The sandbox framing is the user's own: "we must sandbox and protect the users sensitive + keys, information, etc whatever they allow access to." The last clause is the design brief — + authority is bounded by what the user allows, not by what the model asks for. +- The origin of this phase is the user's Phase 2 wording: AIUI "talks to the node safely when + permissioned, without leaking data, **using the same command surface as Pine** and everything + else enableable in settings." D-02's shared-service shape is that sentence made concrete. + + + + +## Deferred Ideas + +- **Cross-node "archipelago content source" with payments** — any IndeeHub install plugs into + every node's content, with payments; same for music. A federation distribution + payments + feature; its own phase (deferred at D-14). +- **AIUI Nostr integration polish** — "make the Nostr integration in AIUI more beautiful." + Carried over from Phase 2's deferred list, still not scoped here. +- **Reviving `ContentPanel.vue` and the plugin-renderer path** — considered and rejected for + this phase; the dead-code inventory should be resolved as cleanup, not as architecture. +- **AIUI's dev-only Vite middleware** (`vite-tmdb`, `vite-rss`, `vite-web-search`, `vite-fs`, + `vite-music-search`, `vite-dev-chats`) — needs a production answer eventually; only the parts + D-12 replaces are in scope now. +- **Pine voice reusing the tool registry** — D-02 makes it possible and is the reason for the + shared-service shape, but wiring the voice pipeline to it is not in this phase. + +### Reviewed Todos (not folded) +- *Connected-nodes list must scroll at row-matched height* — keyword match only; belongs to + Phase 1 (UIFIX-02, already complete). +- *Fedimint gateway must not install with a pre-set password* — keyword match only; Phase 1 + FED-07 territory. +- *Keep FIPS/Tor pills on cloud files and show them on mobile* — keyword match only; Phase 1 + UIFIX-01. + + + +--- + +*Phase: 13-AIUI — Conversational Node Control & Content Surfaces* +*Context gathered: 2026-08-03* diff --git a/.planning/phases/13-aiui-functional-conversational-node-control-and-content-surf/13-DISCUSSION-LOG.md b/.planning/phases/13-aiui-functional-conversational-node-control-and-content-surf/13-DISCUSSION-LOG.md new file mode 100644 index 00000000..924f9ce1 --- /dev/null +++ b/.planning/phases/13-aiui-functional-conversational-node-control-and-content-surf/13-DISCUSSION-LOG.md @@ -0,0 +1,201 @@ +# Phase 13: AIUI — Conversational Node Control & Content Surfaces - Discussion Log + +> **Audit trail only.** Do not use as input to planning, research, or execution agents. +> Decisions are captured in CONTEXT.md — this log preserves the alternatives considered. + +**Date:** 2026-08-03 +**Phase:** 13-aiui-functional-conversational-node-control-and-content-surf +**Areas discussed:** Where the tool-calling loop lives, How much authority the chat gets, Content scope and what "music" means, Two-repo split and delivery + +--- + +## Where the tool-calling loop lives + +| Option | Description | Selected | +|--------|-------------|----------| +| Node-side in Rust | Binary owns loop, tool registry and key; AIUI is a thin client | ✓ | +| Node proxies the model, AIUI runs the loop | Key stays server-side but tools execute through the ContextBroker | | +| Browser-side in AIUI | AIUI calls the model directly; key lives in the browser | | + +**User's choice:** Node-side in Rust +**Notes:** Chosen with the tradeoff stated — this makes the RPC surface a contract AIUI and the later voice pipeline are written against. + +| Option | Description | Selected | +|--------|-------------|----------| +| One assistant, many front doors | Extend the existing mesh assistant into a shared service | ✓ | +| Separate subsystem for AIUI | Leave the radio-shaped mesh assistant alone, build beside it | | +| Shared backend, separate authority | Share the key/plumbing, keep tool registries strictly separate | | + +**User's choice:** One assistant, many front doors +**Notes:** Directly realizes the user's Phase 2 wording — "the same command surface as Pine". + +| Option | Description | Selected | +|--------|-------------|----------| +| Split by nature: node does data+control, broker does UI | Node owns node-touching tools; broker keeps navigate/open-app/theme + consent | ✓ | +| Broker becomes consent-only | Strip back to permissions and theme | | +| Keep the broker as the single front door | Everything forwards through the broker | | + +**User's choice:** Split by nature + +| Option | Description | Selected | +|--------|-------------|----------| +| Local Ollama when present, Claude as fallback | Node data stays local when a local model exists | ✓ (amended) | +| Claude by default, Ollama opt-in | Best tool-calling reliability, context leaves the node | | +| User picks at setup, no default | Explicit choice, no implicit default | | + +**User's choice:** Option 1, **amended by the user** — "but we also want to integrate this as part of it, please plan that too `https://github.com/routstr` so it would be local Ollama or Claude/Routstr as fallback" +**Notes:** Routstr was researched during the discussion rather than assumed: OpenAI-compatible endpoint, Cashu ecash per request, Nostr provider/model/price discovery. All three substrates already exist in-tree, which is why it is a smaller lift here than elsewhere. + +| Option | Description | Selected | +|--------|-------------|----------| +| Prepaid budget, auto-spend within it | Hard ceiling a prompt-injected model cannot exceed | ✓ | +| Confirm every paid request | Maximum control, unusable with a multi-call tool loop | | +| Routstr only when explicitly selected | No automatic fallback to a paid path | | + +**User's choice:** Prepaid budget the user sets + +| Option | Description | Selected | +|--------|-------------|----------| +| Curated allowlist of hand-written tools | Every capability is a deliberate decision | ✓ | +| Auto-generate from the RPC dispatcher | Fast coverage, blast radius = whatever the allowlist forgets | | +| Tiered: curated for writes, generated for reads | Broad reads, hand-written mutations | | + +**User's choice:** Curated allowlist of hand-written tools + +| Option | Description | Selected | +|--------|-------------|----------| +| Local model gets tools, writes confirmed anyway | Confirm gate does the safety work | ✓ | +| Reads local, writes escalate to the strong model | Undercuts the privacy default at the sensitive moment | | +| Require a tool-capable local model | Honest but costs weak-hardware users the feature | | + +**User's choice:** Local model gets tools; every write needs confirmation regardless +**Notes:** Consequence recorded in CONTEXT.md — backend choice becomes a privacy decision, not a safety one. + +| Option | Description | Selected | +|--------|-------------|----------| +| Node-side, in the existing per-node data dir | Inherits backup, factory-reset, future LUKS | ✓ | +| Browser-only, never persisted server-side | Nothing accumulates on disk | | +| Ephemeral — no history at all | Strongest privacy, no memory | | + +**User's choice:** Node-side in the per-node data dir + +--- + +## How much authority the chat gets + +| Option | Description | Selected | +|--------|-------------|----------| +| Reads + app lifecycle + settings writes | Keys, seeds, wallet spends, federation trust, factory reset excluded | ✓ | +| Read-only first | Prove the sandbox before granting power | | +| Full control including wallet and payments | An LLM adjacent to spending authority | | + +**User's choice:** Reads within granted categories + app lifecycle + settings writes + +| Option | Description | Selected | +|--------|-------------|----------| +| Authority never derives from content; untrusted text fenced and labelled | Injected instructions still face a human confirm | ✓ | +| Keep peer content out of the model entirely | Removes the injection path and much of the appeal | | +| Sanitize and strip suspicious patterns | Rejected as an arms race that reads as a guarantee | | + +**User's choice:** Fenced and labelled; authority never derives from content + +| Option | Description | Selected | +|--------|-------------|----------| +| In neode-ui's trusted chrome, outside the iframe | Iframe cannot spoof, restyle or pre-click it | ✓ | +| Inside AIUI, styled as part of the conversation | Better feel, drawn by the influenced context | | +| Node-issued confirmation token, UI-agnostic | Strongest and works for voice; more protocol to build | | + +**User's choice:** neode-ui's trusted chrome, outside the iframe + +| Option | Description | Selected | +|--------|-------------|----------| +| All closed; user opens what they want | Matches the sandbox promise literally | ✓ | +| Low-sensitivity open, sensitive closed | Immediately useful, harder claim to defend | | +| Open on first grant, per-category prompts in context | Just-in-time consent, more moving parts | | + +**User's choice:** All 10 categories default closed + +--- + +## Content scope — and what "music" means + +Presented alongside verified research findings: AIUI's grids are fed by regex-parsing the model's own reply text against fixture catalogs injected into the system prompt; every "real" data path is Vite dev middleware absent from a static `dist/` deploy; `vite-fs.ts:7` hardcodes `/Users/dorian/Projects`; `ContentPanel.vue` is dead code taking `ArchyAppsGrid`, `FavoritesGrid`, `DiscoverPanel`, `RecipeDetail` and `AppDetail` with it. + +| Option | Description | Selected | +|--------|-------------|----------| +| Feed the existing grids from Archy | Keep the design, replace the LLM-synth source | ✓ | +| New Archy-native surfaces alongside | Doubles surface area, splits the design language | | +| Revive ContentPanel and the Archy bridge path | Risks investing in an abandoned architecture | | + +**User's choice:** Feed the existing grids from Archy + +| Option | Description | Selected | +|--------|-------------|----------| +| Audio files from the two transports you already have | MIME-filtered files, no new entities; folds in the m4a/aac/opus mime bug | | +| Build a real library — albums, artists, metadata | A substantial backend domain | ✓ | +| Leave music to wavlake, wire only files and video | Music already works in prod against wavlake | | + +**User's choice:** Build a real library +**Notes:** Chosen after being told explicitly that no library domain exists today and that it deserves its own phase. Concern raised once, user decided, proceeded — sequencing handled by the follow-up below. + +| Option | Description | Selected | +|--------|-------------|----------| +| Its own plans inside Phase 13, not blocking the rest | Phase still delivers if the library runs long | ✓ | +| Library first — the rest follows | Cleanest data model, delays everything visible | | +| Split it into its own phase | Its own discussion round | | + +**User's choice:** Its own non-blocking wave inside Phase 13 + +| Option | Description | Selected | +|--------|-------------|----------| +| Surface this node's + peers' existing content; no new payment rail | Uses the invoice/X-Payment-Token/Range flow that exists | ✓ | +| Include the cross-node content source with payments | The full Phase 2 vision; a federation distribution feature | | +| Movies out of scope this phase | Narrowest cut | | + +**User's choice:** Surface existing content through the existing paid-unlock subsystem + +--- + +## Two-repo split and delivery + +| Option | Description | Selected | +|--------|-------------|----------| +| Built and shipped with the frontend, versioned and verified | Pin the commit, enforce the base path, fetch a live asset to verify | ✓ | +| Make AIUI a real catalog app | Architecturally right; changes a platform rule mid-phase | | +| Vendor AIUI's build output into this repo | One artifact, loses source separation | | + +**User's choice:** Built and shipped with the frontend, versioned and verified + +| Option | Description | Selected | +|--------|-------------|----------| +| Keep standalone; embedded mode delegates to the node | Dev loop stays fast, no node needed to work on the UI | ✓ | +| Embedded-only from here | Less surface, loses AIUI's independent life | | +| Standalone with the node as an optional backend | "Optional" risks the secure path being the forgotten one | | + +**User's choice:** Keep standalone; embedded mode delegates + +| Option | Description | Selected | +|--------|-------------|----------| +| Confirm push access before planning starts | Treats it as a prerequisite, not a mid-plan discovery | ✓ | +| Work on a branch, hand merges to a maintainer | Human gate mid-phase, same inert-until-merged risk | | +| Plan the archy side to degrade gracefully | Robust, but designs for a half-landed state throughout | | + +**User's choice:** Confirm push access before planning starts + +--- + +## Claude's Discretion + +- What the music library indexes over, the tag-extraction library, and where the index lives. +- Streaming/token delivery for chat responses; context-window budgeting over node data. +- Which specific tools make the first curated allowlist, within the authority ceiling. +- Routstr provider selection among Nostr-advertised providers. +- Per-category mapping of the 10 permission categories onto individual tools. + +## Deferred Ideas + +- Cross-node "archipelago content source" with payments (federation distribution feature). +- AIUI Nostr integration polish (carried from Phase 2's deferred list). +- Reviving `ContentPanel.vue` and the plugin-renderer path — cleanup, not architecture. +- A production answer for AIUI's dev-only Vite middleware beyond what this phase replaces. +- Wiring Pine's voice pipeline to the shared tool registry.