diff --git a/.planning/phases/02-ui-performance/02-CONTEXT.md b/.planning/phases/02-ui-performance/02-CONTEXT.md
new file mode 100644
index 00000000..b0b81a9a
--- /dev/null
+++ b/.planning/phases/02-ui-performance/02-CONTEXT.md
@@ -0,0 +1,170 @@
+# Phase 2: UI Performance - Context
+
+**Gathered:** 2026-07-30
+**Status:** Ready for planning
+
+
+## Phase Boundary
+
+Make the existing neode-ui Vue SPA feel fast: main-tab switches render immediately from
+cached state with background refresh (PERF-02), secondary screens open without blocking
+reloads and are instant on repeat visits (PERF-03), and every fix is preceded by profiling
+that names the measured cause (PERF-01). Verified on real node hardware (archi-dev-box),
+not just the dev workstation. Plus two folded-in AIUI UX defaults (see D-14) — no other
+AIUI/content-federation work belongs here.
+
+
+
+
+## Implementation Decisions
+
+### Caching Approach (PERF-02)
+- **D-01:** Main tabs use BOTH `` around the RouterView (component instances,
+ scroll position, and in-page state survive tab switches) AND `useCachedResource`
+ stale-while-revalidate for their data. Today no `` exists anywhere — every
+ tab switch fully remounts the view.
+- **D-02:** Which views get converted is decided by profiling (D-09), not blanket
+ conversion — "fixes are targeted, not guessed" (PERF-01). Already-fast views are left
+ alone.
+- **D-03:** Heavy views (Mesh with its D3 graph + Leaflet map) ARE kept alive, but
+ KeepAlive's `max` instance cap is set so the oldest unused views evict — bounded memory
+ on low-power nodes.
+- **D-04:** Secondary screens (AppDetails, server sub-pages, etc.) get `useCachedResource`
+ keyed per item (e.g. `app-details:${appId}`) but NO KeepAlive — unbounded item counts
+ would bloat an instance cache. Repeat opens paint instantly from the data cache.
+
+### Refresh / Staleness UX
+- **D-05:** Background refresh on a cached view shows a SUBTLE indicator (small
+ spinner/shimmer in the header/tab area driven by `loadState === 'refreshing'`) — not
+ invisible, not stale-age badges.
+- **D-06:** Default TTL 30s (the hook's default); per-view tuning is Claude's discretion
+ (shorter for fast-moving data like mesh peers/sync status, longer for near-static data
+ like the app catalog).
+- **D-07:** Background refresh failures are silent keep-last-value — cached data stays on
+ screen, retry on next focus/TTL; no toast. Errors surface only on explicit user refresh.
+- **D-08:** sessionStorage persistence ON (instant paint after reload) except for large
+ payloads (file lists, media), which stay memory-only — the hook's `persist: false`.
+
+### Profiling & Verification (PERF-01, PERF-03)
+- **D-09:** Profiling starting set = ALL main surfaces: Apps/app store (+ AppDetails),
+ Mesh, Wallet (+ send flows), Cloud/Files, Server, Network, and Web5. User confirmed all
+ of these feel slow, "often app store".
+- **D-10:** Profiling produces a COMMITTED findings doc in the phase directory: each slow
+ surface → measured cause (remount storm / serial RPC waterfall / uncached fetch) →
+ intended fix. Written and committed BEFORE fixes land.
+- **D-11:** On-device verification target is **archi-dev-box**. Pass bar: NO visible
+ spinner/blank on revisit of a tab or secondary screen already visited this session;
+ first visits may still show loading.
+
+### Fix Scope
+- **D-12:** Backend (`core/`) changes are ADDITIVE ONLY: new aggregate/batch RPC endpoints
+ and cheap response-shaping are allowed when profiling names a backend cause; NO refactors
+ of existing handlers and NOTHING touching the orchestrator (keeps the lifecycle gate out
+ of play).
+- **D-13:** Serial fetch waterfalls in views are fixed client-side by parallelizing
+ (`Promise.all`) plus rpc-client request dedup. Aggregate endpoints (per D-12) only where
+ a screen genuinely needs 3+ dependent calls.
+- **D-14:** Folded-in AIUI UX defaults (small, in-scope ride-alongs): (a) the AIUI chat
+ starts EXPANDED, (b) on mobile AIUI starts on the CHAT view, not the context view
+ (current start-on-context is wrong). Everything else AIUI-related is deferred (see
+ Deferred Ideas).
+- **D-15:** Deploy discipline: dev pair only this phase — no OTA. Fleet rollout rides the
+ normal release train later.
+
+### Claude's Discretion
+- Per-view TTL values (D-06).
+- KeepAlive `max` cap value and eviction tuning (D-03).
+- Choice between client-side parallelization and a new aggregate endpoint per screen,
+ within D-12/D-13 bounds.
+- Exact placement/styling of the subtle refresh indicator (D-05), consistent with the
+ existing design system.
+
+
+
+
+## Canonical References
+
+**Downstream agents MUST read these before planning or implementing.**
+
+### Frontend caching / data layer
+- `neode-ui/src/composables/useCachedResource.ts` — The existing SWR hook (memory →
+ sessionStorage → fetch, sticky-ready, refreshing state, focus revalidation,
+ abort-on-unmount). The pattern to EXTEND, not reinvent.
+- `neode-ui/src/stores/resources.ts` — Shared resource store backing the hook.
+- `neode-ui/src/api/rpc-client.ts` — RPC client (retry/backoff, dedup option, abort
+ signals) — waterfall fixes build on its dedup + signal support.
+- `neode-ui/src/App.vue` — Root RouterView (line ~8) where KeepAlive wrapping lands;
+ note the splash/isReady gating around first reveal.
+
+### Project-level
+- `.planning/codebase/CONVENTIONS.md` — Vue/TS conventions (script setup, composable
+ patterns, store patterns).
+- `.planning/codebase/STRUCTURE.md` — Where views/components/stores/composables live.
+- `CLAUDE.md` — Commit/push discipline, build notes (grep built bundle before shipping),
+ invariants.
+
+
+
+
+## Existing Code Insights
+
+### Reusable Assets
+- `useCachedResource` + `resources` store: production-quality SWR already used by 8 views
+ (Monitoring, Cloud, Server, Federation, Credentials, Web5, FIPS cards) — main tabs just
+ don't use it yet.
+- `rpc-client.ts` `dedup: true` option: shares in-flight requests across concurrent
+ callers — key for waterfall/parallelization fixes.
+
+### Established Patterns
+- 44 routes are already lazy-loaded (`import()` in `router/index.ts`) — route-level code
+ splitting is NOT the problem.
+- Views fire multiple `onMounted` fetches (Cloud 4, Server/Mesh/ContainerAppDetails 3…) —
+ the likely refetch-on-remount storm PERF-01 will quantify.
+- No `` anywhere in the codebase today.
+
+### Integration Points
+- `App.vue` RouterView is the single mount point for KeepAlive.
+- Pinia stores (`stores/*.ts`) hold global state; per-view fetch logic migrates into
+ `useCachedResource` keys rather than new ad-hoc stores.
+
+
+
+
+## Specific Ideas
+
+- UI changes verified on the :8100 dev preview against archi-dev BEFORE deploy (carried
+ forward from Phase 1 discipline).
+- Frontend build gotcha (CLAUDE.md): grep `web/dist/neode-ui` for new strings after
+ `npm run build` — the build can silently no-op.
+- Pass bar phrasing from the user: revisited surfaces paint content immediately; the
+ sluggishness reported on-device must be gone on archi-dev-box.
+
+
+
+
+## Deferred Ideas
+
+Captured verbatim from the user during this discussion — new capabilities that belong in
+their own phase (candidate: "AIUI & Content Federation"; add via `/gsd-phase add`):
+
+- **AIUI permissioned node access:** the AI UI talks to the node safely when permissioned,
+ without leaking data, using the same command surface as Pine and everything else
+ enableable in settings.
+- **AIUI content deep-dive:** deep dive into the content AIUI finds and serves — "make it
+ perfect".
+- **AIUI peer media:** show peer videos and files in AIUI.
+- **IndeeHub cross-node content source with payments:** peer files/videos made available
+ on IndeeHub by other nodes for films — an "archipelago content source" so any IndeeHub
+ install plugs into every node's uploaded/served IndeeHub content, with payments; same
+ for music files and everything else.
+- **AIUI Nostr integration polish:** make the Nostr integration in AIUI more beautiful.
+
+(The two small AIUI UX defaults — chat starts expanded; mobile starts on chat — were
+folded INTO this phase as D-14 and are not deferred.)
+
+
+
+---
+
+*Phase: 2-UI Performance*
+*Context gathered: 2026-07-30*
diff --git a/.planning/phases/02-ui-performance/02-DISCUSSION-LOG.md b/.planning/phases/02-ui-performance/02-DISCUSSION-LOG.md
new file mode 100644
index 00000000..4d18ead4
--- /dev/null
+++ b/.planning/phases/02-ui-performance/02-DISCUSSION-LOG.md
@@ -0,0 +1,170 @@
+# Phase 2: UI Performance - 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-07-30
+**Phase:** 2-ui-performance
+**Areas discussed:** Caching approach, Refresh/staleness UX, Profiling targets, Fix scope: backend RPC
+
+---
+
+## Caching approach
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| KeepAlive + SWR | KeepAlive for main tabs AND useCachedResource for data | ✓ |
+| SWR only | Extend useCachedResource, keep full remounts | |
+| KeepAlive only | Instances alive, ad-hoc data refresh | |
+
+**User's choice:** KeepAlive + SWR (recommended)
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Profiling decides | Convert only surfaces PERF-01 names as slow | ✓ |
+| All main tabs | Blanket conversion | |
+
+**User's choice:** Profiling decides (recommended)
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Keep alive, cap count | Include heavy views (Mesh D3+Leaflet), KeepAlive max cap | ✓ |
+| Exclude heavy views | Only lightweight tabs kept alive | |
+| You decide | Per-view by measurement | |
+
+**User's choice:** Keep alive, cap count (recommended)
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| SWR, no KeepAlive | Per-item cache keys, no instance cache | ✓ |
+| Same as main tabs | KeepAlive + SWR for secondary screens too | |
+| You decide | Per screen by cardinality | |
+
+**User's choice:** SWR, no KeepAlive for secondary screens (recommended)
+
+---
+
+## Refresh/staleness UX
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Invisible | Content updates in place, no indicator | |
+| Subtle indicator | Small spinner/shimmer while refreshing | ✓ |
+| Stale-age badges | Show data age via isStale/ageMs | |
+
+**User's choice:** Subtle indicator (declined the "Invisible" recommendation)
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| 30s, per-view tuning | Hook default; Claude tunes per view | ✓ |
+| Short (10s) everywhere | Fresher, more RPC chatter | |
+| Long (60s+) everywhere | Minimal chatter | |
+
+**User's choice:** 30s with per-view tuning (recommended)
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Silent keep-last | Keep cached data, retry on focus/TTL | ✓ |
+| Toast on failure | Surface every background failure | |
+
+**User's choice:** Silent keep-last (recommended)
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Yes, except large payloads | sessionStorage persist, skip big lists | ✓ |
+| Memory only | Cold start on every reload | |
+
+**User's choice:** Persist except large payloads (recommended)
+
+---
+
+## Profiling targets
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Apps tab + AppDetails | App browser + detail/log screens | ✓ |
+| Mesh tab | Map, contacts, messages | ✓ |
+| Wallet tab + send flows | Balances, send/receive | ✓ |
+| Cloud/Files + Server | File browser, node status/settings | ✓ |
+
+**User's choice:** All four, plus free-text additions: "network and web 5 and cloud and often app store"
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| .228 | Designated gate/test node | |
+| .198 dev pair | Other dev-pair node | |
+| Whichever node showed it | User names the node | |
+
+**User's choice:** Free-text: **archi-dev-box**
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Committed findings doc | Profiling report in phase dir before fixes | ✓ |
+| Findings in plans only | No standalone report | |
+
+**User's choice:** Committed findings doc (recommended)
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| No visible spinner on revisit | Subjective-but-crisp pass bar | ✓ |
+| Numeric budgets | ms budgets measured on-device | |
+
+**User's choice:** No visible spinner on revisit (recommended)
+
+---
+
+## Fix scope: backend RPC
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Additive changes only | New aggregate/batch endpoints ok; no refactors/orchestrator | ✓ |
+| Frontend only | Backend untouched | |
+| Whatever profiling justifies | Any backend change, gate re-runs as needed | |
+
+**User's choice:** Additive changes only (recommended)
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Parallelize + dedup | Promise.all + rpc-client dedup | ✓ |
+| Aggregate endpoints | Combined-payload RPCs for 3+ call screens | |
+| You decide per view | Per-screen by measurement | |
+
+**User's choice:** Parallelize + dedup (recommended)
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Dev pair only, no OTA | Verify on dev nodes; fleet rollout via release train | ✓ |
+| OTA when verified | Fleet OTA as part of this phase | |
+
+**User's choice:** Dev pair only (recommended)
+
+---
+
+## Scope routing (freeform input)
+
+During area selection the user requested a large AIUI/IndeeHub scope expansion. Routed via
+a follow-up question:
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| New phase, discuss next | Add roadmap phase + full discuss-phase | |
+| Backlog only for now | Keep in Deferred Ideas | |
+| Fold the small UX fixes into Phase 2 | Chat-expanded + mobile-starts-on-chat ride along; big work deferred | ✓ |
+
+**Notes:** The two UX defaults became D-14 in CONTEXT.md. All other AIUI/IndeeHub items
+recorded verbatim in Deferred Ideas.
+
+## Claude's Discretion
+
+- Per-view TTL values
+- KeepAlive max cap / eviction tuning
+- Parallelization vs aggregate endpoint per screen (within additive-only bound)
+- Refresh indicator placement/styling
+
+## Deferred Ideas
+
+- AIUI permissioned node access (Pine-parity command surface, no data leaks)
+- AIUI content deep-dive ("make it perfect")
+- AIUI peer videos and files
+- IndeeHub cross-node content source with payments (films, music, everything)
+- AIUI Nostr integration polish