diff --git a/.papercuts/troubleshooting.md b/.papercuts/troubleshooting.md
index 26e9ddc5c..e96b4e76e 100644
--- a/.papercuts/troubleshooting.md
+++ b/.papercuts/troubleshooting.md
@@ -1,5 +1,7 @@
# Troubleshooting
+- `.papercuts/` is ignored even when its troubleshooting file is present in the PR branch, so persisting a required update needs an explicit `git add -f`.
+- Layout stabilization must race `animation.finished` against a short timeout because paused or infinite document animations never settle; keep geometry polling as the authoritative E2E readiness check.
- Pi 0.80.10 can choose the oldest oversized user turn as `firstKeptEntryId`, leaving both summary inputs empty and producing a no-op checkpoint. When the journal has a newer turn, retry `prepareCompaction` with a minimal retained-tail budget; still refuse the checkpoint if both summary inputs remain empty.
- `Session.getEntries()` includes abandoned branches. Synchronization markers must be read from `Session.getBranch()` or a rolled-back partial write can still look committed.
- Child-runtime unit tests load outside Electron. Keep usage accounting behind an injected callback (with a production-only dynamic import) instead of statically importing the Electron-backed singleton into the reusable child registry.
@@ -28,6 +30,7 @@
- An Electron E2E teardown deadline must exceed the app's sequential bounded shutdown phases. A 10-second fixture timeout can kill and report a healthy process while foreground, subagent, and packaged-soak drains are still inside their documented 6s + 5s + 5s ceilings.
- Image generation can return a baked checkerboard or an opaque/RGB file even when asked for transparent onboarding art. Inspect the generated pixels, dimensions, and alpha channel before copying it into `renderer/assets/onboarding/`; extract the real background and resample only after visual inspection.
- GitHub release create/edit requests can return HTTP 503 after committing server-side state. Publication must re-read the exact tag, target SHA, draft state, and asset set before retrying or reconciling; never treat an unavailable lookup as a missing release.
+- A main-process fallback that reads `settings.lastProviderId` as "the app's last provider" is reading a dead key: the UI persists its real selection in renderer localStorage (`aiden-agent.providerId`/`aiden-agent.model`) and only the Telegram flow ever wrote the settings key. Any main-process consumer (scheduler, tools) must either receive the selection explicitly or have attended chat starts seed the settings fallback.
- A physical XCTest transport spike can keep secrets out of the project and scheme: use a private temporary Derived Data directory, create an injected `.xctestrun` copy beside its `Build/Products` payload, inject an ephemeral canonical pairing-bootstrap JSON into that copy, then use `test-without-building`. Xcode still requires the physical device to remain unlocked through preflight and launch.
- A copied `.xctestrun` resolves `__TESTROOT__` relative to its own location. Keep the injected copy beside `Build/Products` (or deliberately rewrite every relative product path), and derive the advertised LAN address from the default-route interface instead of assuming Wi-Fi is `en0`; otherwise Xcode reports a missing test product or the phone silently times out against a link-local adapter.
- Simulator networking does not prove iOS Local Network privacy readiness. A direct physical LAN request fails as `Local network prohibited` when the host app omits `NSLocalNetworkUsageDescription`; lock both that key and the canonical `NSBonjourServices` value with an XCTest that inspects the built application bundle.
@@ -379,6 +382,8 @@ owns; reopen the terminal before judging the final live state.
- Zsh does not split scalar loop values by default; use explicit delimiters in pairwise merge probes so branch names are not accidentally concatenated.
- Standalone green PRs still conflicted in shared settings, test registries, and UI fixtures. Assemble the exact combined stack and retain every feature's test registration before merging to main.
+- UX review (2026-09-05): the active Xcode installation rejects tools until its license is accepted. Git and desktop C helpers can use the separately installed Command Line Tools via `DEVELOPER_DIR=/Library/Developer/CommandLineTools`; helper build scripts replace the child environment, so this run compiled their unchanged C sources with the same flags directly. iOS physical-device discovery/test remains blocked; do not claim it passed.
+- Electron E2E failure diagnostics called `app.process()` outside their try/catch; a closed Electron target hid the original launch error. Keep that call within the best-effort diagnostic block. The isolated E2E profile also cannot establish native Bot Keychain authority; the editor test injects a test-owned IPC catalog and captures the submitted access, while storage/authority tests run separately.
## 2026-09-10 — Google catalog PR validation
@@ -386,3 +391,41 @@ The main checkout's shared node_modules matched Pi's pinned version but lacked
postcss-value-parser and @xterm/addon-web-links required by this worktree. The
resulting type errors disappeared after replacing the temporary dependency
symlink with this checkout's own npm ci. Full type-check and lint then passed.
+
+## 2026-09-09 — Draft chat planning
+
+- The checkout has no `.memory/` directory despite AGENTS.md referencing it; used current source and the plan index for project context.
+- Native verification: no physical iOS device is online and local Java/Android SDK tools are unavailable. Run generic iOS build-for-testing and shared Remote contract suites; device XCTest and Android runtime acceptance remain unavailable locally.
+- Draft lifecycle regression tests intercepted `chats:appendMessage` for first-send failures; updated that fault injection to the new atomic `chats:createWithFirstMessage` boundary.
+- Empty-chat migration must distinguish header-only Pi journals (created by the old Todo snapshot read even before Send) from real private records; preserving every journal would leave ordinary abandoned chats behind.
+- Completed Pi v3-to-v4 promotion adds lane/navigation records even for a header-only source. Empty cleanup must validate the real receipt, backup digest, and exact migration scaffolding rather than treating all promoted records as user history.
+
+## 2026-09-10 — PR #102 readiness
+
+- The initial source-scanning theory incorrectly credited explicit 1x encode arguments that are already Electron's defaults. Exercise the actual fix with a valid oversized PNG through `providers:save`, relaunch, and verify the recovered, decodable 64px-or-smaller result.
+- Treat user-supplied provider PNGs as original-color artwork; an alpha mask turns fully opaque icons into solid squares and disagrees with native clients.
+- Model Pad animation settling must ignore infinite animations and retain a bounded timeout so hosted Electron runs cannot wait forever.
+- The cold hosted responsive matrix can reach its last 390px case only as the shared 90-second test budget expires, while a warm retry passes in 24 seconds. Give this exhaustive case an explicit bounded 180-second budget without relaxing geometry assertions.
+- On hosted Electron, Playwright `fill("")` can leave a controlled search unchanged; use the native value setter plus a bubbling input event for deterministic test cleanup.
+
+## 2026-09-10 — PR96 readiness rebase
+
+- The branch predated the unified Settings work and conflicted in headings, accessible switch names, shared test fixtures, and the tracked-but-ignored papercut log. Resolve these contracts additively and use `git add -f` for the already tracked `.papercuts/troubleshooting.md`.
+- A parent save handler showed a toast but resolved its promise, making the editor's inline retry state unreachable. Propagate the rejection after the toast so the review dialog keeps the user's choices and exposes the error.
+- Progressive disclosure made two inherited E2E locators inaccessible: tests must open the exact Remote or Telegram details before asserting the controls inside, rather than spending the full timeout waiting for hidden semantics.
+- A single rollback `try` coupled external Tailscale route cleanup to local listener/state cleanup; keep independently knowable cleanup steps best-effort and report external versus local uncertainty separately.
+- Distinct cleanup messages need branch-specific regressions: cover both newly enabled access being disabled and pre-existing access staying enabled when route removal fails.
+- Hosted Electron can leave a controlled scheduled-task search unchanged after Playwright `fill("")`; use the native value setter plus a bubbling input event for deterministic cleanup.
+
+## 2026-09-10 — PR #81 readiness rebase
+
+- The stale terminal migration conflicted with newer browser-link integration and expanded package scripts; preserve current `main` scripts and link routing, then layer the Ghostty-specific test/build hooks back in before regenerating the lockfile.
+- `npm ci` completed without Electron's macOS payload, and the first focused Playwright command omitted this repo's explicit config; install the payload with `node node_modules/electron/install.js` and pass `--config=playwright.config.ts`.
+- Canvas terminal link detection and host navigation policy had separate truth sources, so unsupported file-like text gained a dead click affordance. Pass the host policy into the surface and filter hover and activation together.
+- Ghostty correctly encodes modified keys, but Meta chords belong to the host; suppress unhandled Meta press/release pairs after terminal copy and paste handling. Do not key this off `navigator.platform`: Chromium may reduce it even in a macOS Electron renderer.
+- The terminal Playwright fixture launches compiled renderer output; rebuild before interpreting a focused E2E failure after source edits, or the test exercises the previous bundle.
+
+## 2026-09-11 — 0.40.0 integration
+
+- E2E chat-title expectations assume the deterministic chat-model route. On a Mac where the native Foundation Models helper reports `ready`, automatic titles come from Apple Intelligence instead, so `chat-message-queue` sidebar-title lookups fail locally while passing in CI; probe the helper or move it aside before treating those failures as regressions.
+- `git add` on the tracked-but-ignored `.papercuts/troubleshooting.md` still needs `-f` after conflict resolution.
diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md
index de65c6199..d4c358ae6 100644
--- a/THIRD_PARTY_NOTICES.md
+++ b/THIRD_PARTY_NOTICES.md
@@ -12,6 +12,29 @@ The above copyright notice and this permission notice shall be included in all c
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+## Ghostty / libghostty-vt
+
+Aiden's in-app terminal uses a WebAssembly build of Ghostty's `libghostty-vt`
+(`renderer/lib/ghostty-terminal/vendor/ghostty-vt.wasm`) plus a 112-byte PTY
+callback trampoline. The browser host is adapted from T3 Code's MIT-licensed
+`libghostty-vt` adapter.
+
+Ghostty: Copyright (c) 2024-2026 Mitchell Hashimoto and Ghostty contributors
+T3 Code adapter: Copyright (c) 2026 T3 Tools Inc.
+
+MIT License. See `renderer/lib/ghostty-terminal/GHOSTTY-LICENSE` and
+https://github.com/pingdotgg/t3code/blob/main/LICENSE
+
+## Symbols Nerd Font Mono
+
+Vendored as `renderer/lib/ghostty-terminal/fonts/SymbolsNerdFontMono-Regular.woff2`
+for terminal prompt glyphs.
+
+Copyright (c) 2014 Ryan L McIntyre
+
+MIT License. See `renderer/lib/ghostty-terminal/fonts/LICENSE`
+
+
## Chart.js
Chart.js is vendored into `resources/generative-ui` for sandboxed Generative UI artifacts.
diff --git a/android/app/src/main/java/sbtbiswas/AidenOnTheGo/features/remote/AidenPairingScreen.kt b/android/app/src/main/java/sbtbiswas/AidenOnTheGo/features/remote/AidenPairingScreen.kt
index ab75319ab..bbf038979 100644
--- a/android/app/src/main/java/sbtbiswas/AidenOnTheGo/features/remote/AidenPairingScreen.kt
+++ b/android/app/src/main/java/sbtbiswas/AidenOnTheGo/features/remote/AidenPairingScreen.kt
@@ -9,6 +9,8 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.selection.selectable
+import androidx.compose.foundation.selection.selectableGroup
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions
@@ -21,6 +23,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.semantics.Role
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.KeyboardCapitalization
@@ -183,21 +186,30 @@ fun AidenPairingScreen(
// Pair New Mac Section
Text(
- text = "Pair New Mac",
+ text = "Connect your Mac",
style = MaterialTheme.typography.titleSmall,
fontWeight = FontWeight.Bold,
color = palette.secondary
)
Spacer(modifier = Modifier.height(8.dp))
- // M3 Expressive 3-Tab Pill Segmented Group
+ Text(
+ text = "On your Mac, open Settings → Aiden On The Go → Connect a device. Then scan its code here.",
+ style = MaterialTheme.typography.bodyMedium,
+ color = palette.secondary
+ )
+ Spacer(modifier = Modifier.height(12.dp))
+
+ // QR first, with a camera-free setup code fallback.
Surface(
color = palette.raised,
shape = RoundedCornerShape(20.dp),
modifier = Modifier.fillMaxWidth()
) {
Row(
- modifier = Modifier.padding(4.dp)
+ modifier = Modifier
+ .padding(4.dp)
+ .selectableGroup()
) {
// Tab 0: Scan QR
Surface(
@@ -205,7 +217,11 @@ fun AidenPairingScreen(
shape = RoundedCornerShape(16.dp),
modifier = Modifier
.weight(1f)
- .tactilePress { selectedTab = 0 }
+ .selectable(
+ selected = selectedTab == 0,
+ role = Role.Tab,
+ onClick = { selectedTab = 0 }
+ )
) {
Box(
contentAlignment = Alignment.Center,
@@ -226,7 +242,11 @@ fun AidenPairingScreen(
shape = RoundedCornerShape(16.dp),
modifier = Modifier
.weight(1f)
- .tactilePress { selectedTab = 1 }
+ .selectable(
+ selected = selectedTab == 1,
+ role = Role.Tab,
+ onClick = { selectedTab = 1 }
+ )
) {
Box(
contentAlignment = Alignment.Center,
@@ -241,31 +261,16 @@ fun AidenPairingScreen(
}
}
- // Tab 2: Paste JSON
- Surface(
- color = if (selectedTab == 2) palette.accent else Color.Transparent,
- shape = RoundedCornerShape(16.dp),
- modifier = Modifier
- .weight(1f)
- .tactilePress { selectedTab = 2 }
- ) {
- Box(
- contentAlignment = Alignment.Center,
- modifier = Modifier.padding(vertical = 8.dp)
- ) {
- Text(
- text = "Paste JSON",
- style = MaterialTheme.typography.labelMedium,
- fontWeight = FontWeight.Bold,
- color = if (selectedTab == 2) Color.White else palette.secondary
- )
- }
- }
+
}
}
Spacer(modifier = Modifier.height(16.dp))
+ TextButton(onClick = { selectedTab = if (selectedTab == 2) 0 else 2 }) {
+ Text(if (selectedTab == 2) "Back to scanning" else "Advanced: paste connection details")
+ }
+
errorMessage?.let { msg ->
Surface(
color = palette.danger.copy(alpha = 0.12f),
@@ -325,7 +330,7 @@ fun AidenPairingScreen(
colors = sbtbiswas.AidenOnTheGo.ui.theme.aidenTextFieldColors(),
value = endpointUrl,
onValueChange = { endpointUrl = it },
- label = { Text("Mac Address (HTTPS Endpoint)") },
+ label = { Text("Mac address") },
singleLine = true,
shape = RoundedCornerShape(12.dp),
modifier = Modifier.fillMaxWidth()
diff --git a/docs/aiden-on-the-go-remote-access.md b/docs/aiden-on-the-go-remote-access.md
index 958dd183b..49bd89cab 100644
--- a/docs/aiden-on-the-go-remote-access.md
+++ b/docs/aiden-on-the-go-remote-access.md
@@ -1,14 +1,15 @@
# Aiden On The Go remote access
-Aiden Agent can expose a small authenticated API to Aiden On The Go on iPhone and iPad. Remote Access is off by default. Aiden must remain running on the Mac, although its window may be closed.
+Aiden Agent can expose a small authenticated API to Aiden On The Go on phones and tablets. Phone access is off by default. Aiden must remain running on the Mac, although its window may be closed.
## Local Network setup
-1. Open **Settings → Remote Access** in Aiden Agent.
-2. Choose **Local Network** or **Local Network + Tailscale**.
-3. Turn on **Enable Remote Access**.
-4. Add only the folders the phone or iPad may explore. Selecting the entire home directory requires a second confirmation on the Mac; the filesystem root is never allowed.
-5. Choose **Pair over Local Network** and scan the one-time QR code in Aiden On The Go.
+1. Open **Settings → Aiden On The Go** in Aiden Agent.
+2. Choose **On the same Wi-Fi**, then **Connect a device**.
+3. Review what Aiden will enable and choose **Enable and show code**.
+4. Scan the code in Aiden On The Go. If the camera is unavailable, use the setup code instead.
+
+After choosing the method, setup takes two desktop actions. Scanning and any phone permissions are additional steps. Existing ready connections can add a device directly. Under **Workspace access**, approve any additional folders the phone may browse; existing workspace access is unchanged. Approving the whole home folder requires a separate confirmation.
The Mac advertises `_aiden-agent._tcp` with Bonjour only while Local Network access is running. LAN traffic uses a per-install P-256 HTTPS identity. The QR contains the private CA trust anchor and the server public-key pin so the mobile client can validate the hostname, certificate chain, and pinned key. A certificate renewal keeps the server key; an identity-key change requires pairing again.
@@ -16,19 +17,22 @@ The Mac advertises `_aiden-agent._tcp` with Bonjour only while Local Network acc
Tailscale supplies reachability and network encryption, but Aiden still requires its own device credential on every request.
-1. Install Tailscale on the Mac and sign in to the intended tailnet.
-2. Ensure HTTPS certificates are available for the tailnet. Aiden reports this prerequisite rather than enabling it silently.
-3. In **Settings → Remote Access**, select **Tailscale** or **Local Network + Tailscale** and enable Remote Access.
-4. Review the exact command-equivalent route preview, then choose **Connect**.
-5. Pair with **Pair over Tailscale** after the stable `https://…ts.net/api/aiden/v1` address appears.
+1. Install Tailscale on the Mac and phone, sign in to the intended network, and make sure HTTPS is authorized for the Mac’s Tailscale name.
+2. Open **Settings → Aiden On The Go** and choose **Away from home**.
+3. Choose **Connect a device → Enable and show code**. Aiden turns on access, sets up its private connection, checks it, and shows the one-time code.
+4. Scan the code on your phone.
+
+Aiden checks installation, sign-in, HTTPS availability, and route ownership before setup. Missing prerequisites remain user actions. Conflicts and uncertain changes direct you to the advanced **Connection** controls; setup never silently replaces another route. If setup fails, Aiden removes only access introduced by that attempt where the outcome is known. An uncertain external change remains available for explicit verification.
+
+**This Mac settings** contains the Mac name and enable switch; **Connection** contains the saved mode and technical controls. Closing the code window stops pairing; phone access remains enabled until switched off. Removing a device’s access is separate from turning off all phone access.
Aiden owns only `/api/aiden/v1`, proxies it to the loopback-only HTTP listener's matching `/api/aiden/v1` base, and verifies the resulting route. The matching target base is required because Tailscale strips the public `--set-path` prefix before proxying. On macOS, Aiden invokes Tailscale's shared app executable in its documented explicit CLI mode, so Finder and Dock launches do not depend on terminal environment variables. First-time connection works from an empty Serve configuration only after the node's exact Tailscale certificate domain proves HTTPS was already authorized. Aiden never enables Tailscale Funnel, never runs `tailscale serve reset`, never completes Tailscale authorization for you, and never changes unrelated Serve handlers. **Disconnect** removes only the exact route and target recorded by Aiden. A conflict is reported instead of being overwritten.
## Devices, credentials, and revocation
-Each phone or iPad receives a separate random credential. Aiden persists only a fast lookup digest, a salted scrypt digest, and redacted device metadata—not the credential or pairing secret. Pairing QR codes expire after five minutes and work once.
+Each phone or tablet receives a separate random credential. Aiden persists only a fast lookup digest, a salted scrypt digest, and redacted device metadata—not the credential or pairing secret. Pairing QR codes expire after five minutes and work once.
-Use **Revoke** beside a paired device to invalidate it immediately. Revocation does not rotate model-provider credentials or affect other paired devices. Pair the device again to restore access.
+Use **Remove access** beside a paired device to invalidate it immediately. Revocation does not rotate model-provider credentials or affect other paired devices. Pair the device again to restore access.
## Offline behavior
diff --git a/docs/aiden-remote-api-v1.md b/docs/aiden-remote-api-v1.md
index 5b43ab151..d70262074 100644
--- a/docs/aiden-remote-api-v1.md
+++ b/docs/aiden-remote-api-v1.md
@@ -148,6 +148,8 @@ The OpenAPI document owns exact request/response shapes. This section owns behav
### Bootstrap/device
+Pairing accepts `iphone`, `ipad`, `mac`, and `linux` device types. This additive request vocabulary does not change existing response DTOs, grant inventories, or device-owned stream authority. A desktop receives the same legacy grants unless it separately negotiates existing Bot capabilities; being a desktop does not authorize controlling another device's streams or terminals. Older servers reject desktop types, so desktop callers must report an update requirement rather than impersonating a phone.
+
- The locally displayed QR encodes the OpenAPI `PairingPayload` envelope as canonical JSON. Its `PairingBootstrap` contains protocol version, instance ID, HTTPS API endpoint, P-256 SPKI SHA-256 fingerprint, high-entropy single-use secret, and expiry; its trust member selects the bundled private LAN CA or system trust for Tailscale. The phone must decode and validate the complete envelope, configure hostname plus SPKI verification, and only then exchange the secret. A fingerprint learned from `/pairing/exchange` is confirmation, never the trust bootstrap.
- `POST /pairing/manual-bootstrap`: returns that exact canonical `PairingPayload` encrypted with AES-256-GCM. A uniformly random 100-bit Crockford Base32 setup code is shown only through local Electron IPC and derives the encryption key with HKDF-SHA256. The client sends `{}` to the selected exact endpoint, validates the bounded response, derives and authenticates the envelope locally, requires the decrypted endpoint and expiry to match, and then uses the normal pinned `/pairing/exchange`. The setup code never appears in a URL, request, log, persistent state, Bonjour record, or public status projection. LAN users select a discovered Mac; Tailscale users provide its canonical private endpoint. QR and manual entry share one window and one synchronously consumed exchange secret.
- `GET /health`: minimal readiness and protocol version.
diff --git a/docs/design/desktop-connections-proposal.html b/docs/design/desktop-connections-proposal.html
new file mode 100644
index 000000000..2dd2d0fa2
--- /dev/null
+++ b/docs/design/desktop-connections-proposal.html
@@ -0,0 +1,37 @@
+
+
+
+
+
+
Aiden — Connections proposal
+
+
UI proposal · Sample data only. No devices are contacted.
+
+
+
+
Connections
+
Devices you can control from here
◎
Studio Mac
Connected
◎
Linux workstation
Offline · Last connected 12 minutes ago
Chats and files stay on the device where they were created. Turning a connection off disconnects this client; it does not stop work already running there.
+
Devices that can control this device
Allow connectionsUse your existing Local Network or Tailscale setup.
Travel Mac
Last connected 1 hour ago
iPad
Connected
Existing transport settings and approved folders remain here. SSH and keep-awake are outside this proposal.
+
Review API changes
Studio Mac is offline. Showing saved content; reconnect before sending or controlling work.
Check the API changes in this workspace.
I’m checking the routes and their tests.Running on Studio Mac · Reviewing files
Folders on Studio Mac
Only folders approved on this device are shown.
Existing chats stay on their original device. Choose New chat to select another device.
+
+
+
diff --git a/docs/plans/README.md b/docs/plans/README.md
index 54218fa9e..d487e5a76 100644
--- a/docs/plans/README.md
+++ b/docs/plans/README.md
@@ -6,6 +6,10 @@ This directory is the source of truth for Aiden's implementation plans. The engi
| Plan | Status | Current state |
| -------------------------------------------------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| [Scheduled-Task Provider and Pi Rollout Recovery](scheduled-provider-and-pi-rollout-recovery-plan.md) | Implemented | Attended chat starts seed the scheduler's provider fallback, tasks pin providers explicitly (editor picker + prefilled drafts + honest `schedule_task` gating), Pi-rollout-ineligible chats generate journalless over in-memory sessions with the fail-closed contract preserved, and remote request journal events carry method/route evidence — green in the recovery worktree; release-owner stage advance (B1) and machine remediation remain. |
+| [Desktop multi-host control](desktop-multi-host-control-plan.md) | Active | Outbound connection foundation and regression coverage implemented. Full sidebar/chat/runtime integration remains incomplete; interactive UI proposal approved on 2026-09-09. |
+| [Draft Agent Chats](draft-agent-chats-plan.md) | Implemented | Transient desktop drafts, atomic first-message creation, and the one-time legacy empty-chat migration are implemented with Electron regression coverage; PR CI and merge pending. |
+| [Nontechnical User Journey UX](nontechnical-user-journey-ux-plan.md) | Active | Approved ten-journey UX pass implemented for review: guided phone setup, four AI choices, two-step Create a bot, setup acknowledgements, recovery, and native pairing copy. Broader audit backlog and physical-device acceptance remain open. |
| [Aiden Assistant](aiden-assistant-plan.md) | Partial | The dock, Markdown rendering, and confirmed provider-connection/model-pinned project-or-MCP automation creation/editing ship; settings tools and proactivity remain planned. |
| [Aiden On The Go](aiden-on-the-go-plan.md) | Active | Version 0.1.0 build 22 is `VALID` and `IN_BETA_TESTING` for Internal Testers. Android matches iOS's app-icon switcher, Workspace hierarchy, warm scoped Bots/Usage/SSE lifecycle, Usage dashboard, image showcase/gallery, keyboard-safe elevated composer, and split Photo/File pickers. Both clients support native in-process dictation or bounded no-retention transcription by the paired Mac's local Parakeet model. iOS also ships progressive onboarding, bidirectional media, reliable mobile approvals, typed activity timelines, semantic haptics, and one-chat-per-Bot conversations with companion vision for text-only models. Physical iPad/manual permission-system-UI acceptance, privacy publication, final store assets, and external/public-release decisions remain open. |
| [Unified Workspace Sidebar](unified-workspace-sidebar-plan.md) | Active | Phases 1 and 2 ship the unified workspace/chat outline plus a feature-negotiated, transcript-free paginated summary read on Electron, iOS/iPadOS, and Android; physical-device performance acceptance remains open. |
@@ -16,6 +20,7 @@ This directory is the source of truth for Aiden's implementation plans. The engi
| [Dynamic Model Catalog](dynamic-model-catalog-plan.md) | Implemented | Validated pi.dev overlays, offline `0600` cache hydration, scoped setup refresh, four-hour launch refresh, force refresh, Pi metadata fallback, and Mac/iOS projection ship on pinned Pi 0.84.4. |
| [Generative UI Artifacts](generative-ui-artifacts-plan.md) | Active | Phases 0–6 shipped: chat-scoped `render_artifact`, strict sandboxed preview/export hosts, verified vendored Chart.js/Plotly/KaTeX, permission-aware `/visualize`, crash-recoverable authoritative storage/copies, descriptor-relative workspace reads, one-iframe handoff/expansion, visible failure states, and route-stable Responding/Visualizing activity. Three-agent PR review findings are remediated with focused regression coverage. |
| [Generation Progress Notes](generation-progress-notes-plan.md) | Planned | No implementation yet. |
+| [Libghostty workspace terminal](libghostty-terminal-plan.md) | Implemented | The workspace drawer uses Ghostty's official `libghostty-vt` WASM (T3-style runtime, PTY trampoline, canvas surface); node-pty sessions are unchanged. Packaged Mac acceptance remains. |
| [Logging and Diagnostics Upgrade](logging-and-diagnostics-upgrade-plan.md) | Implemented | Phases 0–7 are implemented: bounded typed desktop journals, main-owned renderer evidence, local support export/delete, native categorical parity, and CI/release gates. Signed/notarized `v0.35.0` passed packaged diagnostics acceptance; physical-device termination receipts remain. |
| [Long-thread payload upgrades](long-thread-payload-upgrade-plan.md) | Partial | Investigation complete: T3’s O(N²) stdout store does not exist here. No-op `toolRunning` timeline republish is skipped; Remote gzip, stream-journal debounce, chat JSON/attachments, and transcript windowing remain planned. |
| [Model Insights](model-insights-plan.md) | Partial | A dedicated benchmark-only OpenRouter key, manual fetch, exact source-aware offline cache, metric-selectable collision-free capability suggestions, progressive canvas-first Pad UX, axis provenance, attribution, and direct-AA retirement ship; device-local pace signals remain. |
diff --git a/docs/plans/desktop-multi-host-control-plan.md b/docs/plans/desktop-multi-host-control-plan.md
new file mode 100644
index 000000000..9137026f0
--- /dev/null
+++ b/docs/plans/desktop-multi-host-control-plan.md
@@ -0,0 +1,174 @@
+# Desktop multi-host control
+
+Status: Active — outbound connection foundation implemented; full multi-host experience incomplete; UI proposal approved on 2026-09-09.
+Date: 2026-09-09
+Source baseline: `e42b147925e0d6ecbe050687eeb272e2e841233e`.
+
+## Intended outcome
+
+Any Aiden desktop can act as the user's control surface for its own work and multiple paired Aiden installations. Chats, providers, tools, files, and execution remain authoritative on their originating host. The client aggregates authorized views and sends actions to that host. A machine can be both client and server; no permanent primary machine or central account is required.
+
+The requested experience includes remote chat discovery and filtering in the existing sidebar, a subtle globe on remote chats, live Aiden activity and control, new chats on another host, and a composer host selector followed by that host's workspace/folder selection. macOS and Linux share the protocol; supported actions depend on host capabilities.
+
+The user authorized implementation and a PR on 2026-09-09 after three GPT-5.6 Sol Medium exploration lanes and two GPT-6 Astra Medium planning lanes. The user approved the Connections/sidebar/composer proposal on 2026-09-09; material departures still require signoff. The first implementation slice is documented below.
+
+
+## Implementation checkpoint — 2026-09-09
+
+Implemented in this branch:
+
+- Main-process outbound registry with encrypted atomic storage, pinned HTTPS, authenticated installation identity, independent host dispatch and bounded request/queue limits.
+- Desktop pairing from the canonical QR payload and manual-payload cryptographic decoder. Mac/Linux client classifications preserve existing grants. Manual bootstrap network acquisition is not yet wired.
+- Typed IPC for paired-host management and a closed set of existing remote API operations, with document cancellation and credential-free renderer views. Every response is checked against the bundled API schema with structural/byte limits; validators are compiled lazily and cached.
+- Bounded HTTPS JSON and linear SSE byte framing (1 MiB per frame, 16 MiB/16,384 frames per session, 30-second frame deadline and five-minute absolute session cap). Stream subscription IPC, replay/reconnect reconciliation and renderer consumption remain outstanding.
+- Focused transport/registry tests, including real Remote API pairing over HTTPS, native manual crypto fixture, persistence failure, shutdown, cancellation and host isolation.
+- An interactive [Connections and sidebar proposal](../design/desktop-connections-proposal.html), using sample data only, approved by the user on 2026-09-09. It is not production UI.
+
+Not implemented: multi-host sidebar aggregation/filtering, ChatPane adapter and host-scoped cache migration, production host/folder selector, cross-origin live run observation/control, terminal leases, remote Environment surfaces, onboarding, and Linux combined-branch validation. Existing remote stream ownership checks and grants remain unchanged. This foundation alone does not deliver desktop-to-desktop chat control in the app.
+
+Validation: TypeScript, lint, production build, remote contract/service suites and focused Android client tests pass (one legacy-port test skipped because port 65535 was occupied). The physical-iPad XCTest attempt failed before execution because Xcode could not mount the developer disk image; simulator use is prohibited by ios/AGENTS.md. Two fresh-context adversarial/security reviewers examined the foundation; their protocol, idempotency, document-lifetime, pairing-lock and shutdown/cancellation findings received fixes and regression coverage.
+
+## Existing foundations and gaps
+
+| Area | Existing source and behavior | Required change |
+| --- | --- | --- |
+| Reachability and trust | `main/services/aiden-remote-service.ts`, `aiden-remote-pairing.ts`, `aiden-remote-tls-identity.ts`, `aiden-remote-tailscale.ts`; per-device credentials, pinned LAN HTTPS, Tailscale route, one-use QR/manual pairing | Desktop outbound client and encrypted paired-host registry; broaden mobile-only client classifications compatibly |
+| Mobile client precedent | `ios/AidenOnTheGo/Models/AidenInstallation.swift`; Android installation store and remote client | Reuse installation identity, activation leases, rollback, pinning, bounded decoders, and reconnect semantics |
+| Chat discovery | `main/services/aiden-remote-chats.ts`; feature-negotiated, transcript-free summaries, 100 default/200 maximum per page | Multi-host aggregation and event-driven invalidation; no full-transcript list polling |
+| Chat execution | Existing atomic idempotent remote turn admission, SSE, attachments, cancellation and approvals | Normalize local and remote operations behind one desktop session interface |
+| Observe another origin | `aiden-remote-streams.ts:592` restricts streams to their creating device; `chat-generation-owner.ts` distinguishes renderer/device ownership | Separate host-run observer and controller authority, including locally initiated work |
+| Desktop state | `renderer/lib/ipc.ts`, `queries.ts`, `workspace-context.tsx`, `renderer/main/chat-pane.tsx` use local APIs and bare IDs | Host-scoped references, routes, caches, drafts, async leases and action dispatch |
+| Composer/sidebar | `renderer/components/composer.tsx` has static Local text; `chat-sidebar.tsx` already has workspace/recent projections and search | Approved host selector, host filter, remote indicator and source-aware actions |
+| Files and Git | Existing authenticated workspace/browser/file/Git endpoints | Adapt existing surfaces; never pass remote paths to local APIs |
+| Terminals | `main/services/terminal.ts`, `main/handlers/terminal.ts` bind PTYs to renderer documents | Host session ownership, attach/control leases, resumable output and dedicated grants |
+| Browser/subagents | Existing desktop Environment surfaces; remote API does not provide full parity | Explicit per-surface remote contracts or visible capability limitations; no implicit local execution |
+
+Ordinary chat summaries exclude reserved Assistant records and Bot homes. “All chats” must account for existing conversation areas and their grants; it must not silently mean only regular chats or expose internal child transcripts.
+
+## Linux evidence
+
+Live branch investigation on 2026-09-09 found:
+
+- [PR #71](https://github.com/sambitcreate/aiden-agent/pull/71), `6a397578cb2f127284ef17d1b12359ef47d77022`, open and conflicting with current main. The branches have 178 main-only and 222 Linux-only commits. Its earlier successful checks do not validate today's combined state.
+- [PR #89](https://github.com/sambitcreate/aiden-agent/pull/89), `e0f4836667316d9921ab91d02985ac30f0b6a102`, draft follow-up with failing Linux/verification checks at inspection. It includes Wayland Vulkan and Tailscale operator-error handling.
+- The branch contains AppImage/deb/rpm support for x64/arm64, X11/Wayland handling, Linux credential-store safeguards and Tailscale executable discovery. Inspect its `docs/linux.md` and `main/services/host-platform-capabilities.ts` during integration.
+- Its capability gates disable Bots, computer use, Apple Foundation Models, accessibility paste, hold-to-talk dictation and some native integrations. Do not advertise them merely because a Mac controller supports them.
+
+Build the protocol/platform seams against current main. Validate against an isolated combined Linux checkout before declaring Linux support. Branch reconciliation is a dependency, not an already completed deliverable.
+
+## Backend architecture decisions
+
+### Host identity and dispatch
+
+- Use authenticated server `instanceId` as remote identity. Display name and endpoint are mutable metadata, not identity. Local execution has a stable adapter identity; reject accidental pairing back to the same installation.
+- Every chat, workspace, run, terminal, attachment, browser/artifact reference, query, draft and navigation selection carries `{hostId, resourceId}`. Include host identity in persisted UI state and event envelopes.
+- Place a typed host router and remote connection manager in Electron main. The renderer gets safe metadata and typed operations; it never receives bearer credentials or implements trust exceptions.
+- Retain the local IPC fast path through the same interface. Do not send local actions through HTTP. Adapt one ChatPane rather than creating separate local and remote chat products.
+- Capture host identity when an operation starts. Switching selection cannot retarget it. Fence late responses with connection/activation generations and cancel obsolete reads.
+- Sidebar filter, selected conversation host and new-chat composer host are separate state. Never implement a global IPC destination toggle: it would also retarget unrelated windows, delayed mutations and local Settings.
+- Existing chats remain host-bound in the recommended baseline. Selecting another host affects a new chat context; migration, replication and automatic failover require separate requirements.
+- Model selection, skills, tools and workspace permissions come from the execution host. Never substitute a similarly named local provider or copy inference credentials.
+
+### Connections and security
+
+- Reuse LAN/Tailscale and current manual pairing first. Tailscale supplies reachability; Aiden's revocable credential still authorizes each request.
+- Persist credentials through the platform credential abstraction; Linux must reject insecure plaintext fallback. Publish a paired registry entry only after credential persistence succeeds, with rollback on failure.
+- Validate canonical endpoints, TLS identity, response bounds and negotiated features. Do not forward authorization across redirects or automatically replace a changed server identity.
+- Pairing direction is explicit: A controlling B does not authorize B to control A or C. Outbound connection enablement is separate from inbound Remote Access enablement.
+- Keep protocol v1 endpoints and existing mobile grants intact. Add negotiated host observation/control/terminal capabilities; neither client type nor an old broad chat grant silently implies new authority.
+- On old hosts, use existing supported reads/actions and explicitly identify unavailable capabilities. Never simulate host-wide control by weakening device-owned stream checks.
+
+### Live work and control
+
+- Add a host-run registry fed by the main-owned runtime lifecycle. Include local desktop and paired-device origins; inventory Bot, schedule, Telegram and child-run paths so visible activity is complete within granted conversation scope.
+- Keep generation ownership separate from observation and control. New host-level observers receive safe projections; controllers send commands validated against current grants, run identity, revision and original owner.
+- Preserve current stream device checks. Do not forge a renderer owner or convert another device's credential into the controller's authority.
+- Stop and approval decisions require atomic race handling. Repeated requests use the same idempotency identity; conflicting approval decisions resolve once. Host-only approvals remain host-only unless their exact policy is deliberately extended.
+- Disconnection detaches the view and does not cancel a running turn. Revoking an observer removes its authority without cancelling unrelated local work. Restart reports actual interrupted/recoverable state and never retries inference automatically.
+- Add resumable host metadata events with epoch, sequence and a snapshot watermark. A journal gap triggers an explicit bounded resync; opening the snapshot and subscription cannot lose intervening changes.
+
+### Terminals and process meaning
+
+The proposed baseline covers Aiden-managed work: chat runs, parent/subagent activity and interactive terminals. Arbitrary OS process management is a separate scope decision.
+
+Terminal scope remains pending the user's answer. The existing remote security contract explicitly excludes generic remote terminals/client-authored shell execution. Including interactive terminals therefore requires a deliberate new capability, updated threat model and version-negotiated contract; existing chat grants cannot acquire shell authority implicitly.
+
+- Introduce host-owned terminal sessions with local and remote attachment adapters. Maintain workspace and grant validation before input/resize/close operations.
+- Define a single input/resize controller lease; additional authorized clients can observe. Lease loss, transfer and competing input need deterministic behavior.
+- Keep sequence-numbered bounded output, replay-gap signals, input/output byte limits, per-host/per-device caps and slow-consumer backpressure.
+- Disconnecting a client does not kill its remote PTY. Session close, explicit stop, expiry policy, revocation and host shutdown have separate tested semantics. Output history is not a surviving process after reboot.
+- Add safe subagent summary/control operations through the existing coordinator if required by the signed-off scope; do not expose private child prompts, credentials or journals.
+
+### Full surface audit
+
+| Surface | Routing and scope requirement |
+| --- | --- |
+| Chat history, search, rename, delete, archive, retry/edit | Host-qualified reads/actions with complete pagination; enumerate actual supported remote operations before enabling controls |
+| Composer, models, skills and tools | Execution-host inventory and authority; atomic remote start; host-qualified drafts and attachment staging |
+| Runs, approvals and structured questions | Host-run discovery, audience-safe projection and exactly-once decisions; some sensitive questions/approvals may remain host-only |
+| Subagents | New scoped coordinator adapter for agreed status/stop/retry/steer behavior, preserving mobile's exclusion of child internals |
+| Files, Git and artifacts | Existing file/Git contracts plus authenticated bounded artifact retrieval; local download/preview is an explicit client action, never remote-path interpretation |
+| Terminal | New session ownership, observation, writer arbitration and security contract as described above |
+| Browser tabs | Existing `WebContentsView` is local native UI. Remote folder browsing is unrelated. Viewing/controlling a remote browser requires a separate capture/input design; do not promise parity or quietly open a local tab as if remote |
+| Bots and schedules | Reuse existing APIs where advertised, preserve separate product areas and host-specific availability; include their runs in authorized observation |
+| Settings | Appearance/shortcuts/connections remain client-local. Execution settings belong to the selected host; full remote Settings administration needs an explicit scope decision |
+| Voice, computer use and native integrations | Capability-gate by actual execution host. Remote screen control and host microphone access are not implied by chat control |
+
+The complete first-release action matrix must be reviewed before UI implementation. An unsupported action needs approved treatment rather than a silent local fallback. Remote browser viewing and full remote Settings administration are unresolved scope, not hidden implementation promises.
+
+## UI signoff inventory
+
+The user supplied three Connections Settings screenshots as visual direction. Reuse their separation between inbound and outbound control, compact device rows, status, Add, toggles and revoke/reconnect actions, adapted to Aiden's settings system. Use platform-neutral wording where appropriate. SSH and keep-awake are pictured but are not automatically included features.
+
+| Decision | Approved proposal direction |
+| --- | --- |
+| Settings organization | Connections with Control this device and Control other devices; decide whether to rename/relocate Remote Access |
+| Sidebar | All authorized hosts in the existing workspace/recent projection with a host filter; exact default/filter placement pending |
+| Remote marker | Small soft-colored globe on remote chat rows; placement, tooltip/accessibility name and duplicate host names need approval |
+| Composer | Turn existing Local label into host selector; show the selected host's workspaces and folder browser |
+| Host changes | Existing chat stays host-bound; decide whether unsent text follows the user or each host restores its own draft |
+| Offline/reconnect | Cached content remains identifiable as stale; mutations unavailable; approve presentation and retry/re-pair states |
+| Process/control scope | Confirm Aiden-managed terminals/subagents versus arbitrary OS processes, and authority over work started elsewhere |
+| Conversation areas | Confirm whether “all chats” includes Bots and Assistant in their existing surfaces; maintain conversation access boundaries |
+| Optional features | SSH, keep-awake, chat migration, remote screen control and headless daemon are separate decisions |
+| Environment scope | Confirm remote browser viewing and full remote Settings administration separately from Aiden run/file/Git control |
+
+Before implementation, provide concrete mockups of Settings, sidebar/filter, composer/folder selection, and offline/capability states for review of any material departures. Follow `docs/design-guide.md`, `docs/settings-design-system.md`, `docs/chatgpt-desktop-ui-inspiration.md` and `docs/chatgpt-ui-element-specimen.html`. Preserve semantic tokens, shared action shapes and focus behavior. The Connections/sidebar/composer proposal was approved on 2026-09-09; material departures require fresh approval.
+
+## Delivery sequence and gates
+
+1. **Contract and surface inventory.** Freeze host/resource identity, operation coverage, ownership, capabilities, recovery and numeric resource limits. Map every action reachable from a remote chat. Record approved UI scope separately. Exit: explicit supported/unsupported surface matrix and old-client compatibility fixtures.
+2. **Desktop connection core.** Implement encrypted registry, pairing, bounded HTTP/SSE client, main-process routing and activation leases. Exit: two test servers with colliding IDs, pin/revocation failures, connection switching and interrupted pairing pass without renderer secrets.
+3. **Local adapter and remote chat vertical slice.** Refactor existing local behavior behind host interfaces, then connect summary/detail/model/workspace reads and atomic create/send/cancel/approval flows. Exit: same ChatPane handles both adapters; no reachable action silently runs on the wrong host.
+4. **Host-wide live work.** Add runtime observation, metadata feed, explicit cross-origin control and authority races. Address stream persistence amplification in this slice. Exit: a locally started run on B is observed and controlled from A with correct grants; legacy clients retain their isolation.
+5. **Environment parity.** Integrate remote files/Git/attachments/artifacts and agreed subagent/terminal contracts. Exit: signed-off process scope works, remote resources never open through unintended local handlers, all unsupported surfaces have approved capability treatment.
+6. **Approved UI and onboarding.** Implement the approved Connections, selector, sidebar and state designs over completed backend contracts. Update onboarding and the data-driven tour with a dedicated optimized transparent 1024×1024 illustration only when the feature ships; approve illustration/UI beforehand.
+7. **Combined platform acceptance.** Integrate with the reconciled Linux branch and test Mac↔Mac, Mac→Linux, Linux→Mac and Linux→Linux, including a client that also serves another peer. Exit: functional, security, recovery, performance and packaged operator evidence pass.
+
+These are implementation milestones, not permission to call the first remote chat demo complete. Host-wide observation/control and agreed Environment support are part of the requested outcome.
+
+## Efficiency requirements
+
+- One shared lightweight host feed per enabled connected host, not one stream per sidebar row. Share main-process connections between windows/surfaces. Fetch detailed transcript/run/terminal content only while needed.
+- Use paginated summary indexes, bounded caches and bounded concurrent host refresh. Never scan transcript files to fill sidebar metadata or recursively crawl folders on host selection.
+- Disabled connections generate zero traffic. Suspend detailed hidden-view subscriptions; foreground reconnection is coalesced with exponential backoff and jitter. Retain only lightweight background notifications required by the approved behavior.
+- Bound cache bytes, detailed subscriptions, queues, active hosts, requests and replay retention explicitly before implementation. Slow consumers cannot grow host memory without limit.
+- Current remote stream storage clones/persists growing snapshots during event append. Fix or amortize this before multi-host load; flush durable control/terminal boundaries and preserve idempotency/recovery. Document bounded RAM-only text replay loss if batching is chosen.
+- Current full chat response has a 1 MiB cap. Add feature-negotiated bounded transcript paging/recent-window reads for large desktop histories; do not simply lift the global response limit. Preserve legacy endpoints.
+- Batch token rendering and metadata invalidations. Do not poll full chat bodies, launch per-chat Git watchers or repeatedly enumerate providers while merely showing remote status.
+- Measure production-equivalent local-only and 1/5/10-host cases: startup, idle CPU/wakeups, memory after eviction, wire bytes, disk bytes during streaming, metadata freshness and slow-client recovery. Set numerical baseline-relative release budgets from those measurements; do not invent hardware performance claims.
+
+## Verification matrix
+
+- Register new tests in `package.json`; run focused remote/protocol/router/stream/pairing/workspace/terminal/sidebar/composer suites and normal required checks during implementation.
+- Update normative API docs/schema/shared fixtures and inspect/test both Swift and Kotlin consumers for shared contract or transcript/activity changes. Old grants and strict decoder behavior must remain valid.
+- Two servers with identical chat/workspace/provider names and IDs; rename host; same host at a verified alternate address; self-pair; A→B→A late responses; forget/revoke then re-pair.
+- Local-owner, remote-owner, Bot/schedule/Telegram origin coverage as authorized; observer-only denial; cross-owner stop; two-controller approval races; host-only approval restrictions; revoked subscriptions and attachment handles.
+- Lost acknowledgement and same-key retry without duplicate turn; no offline mutation queue that silently runs later; host crash; sleep/resume; journal gap; terminal detach, replay/backpressure, lease conflicts and restart truthfulness.
+- Remote root policy changes, symlink replacement, expired handles and revision conflicts; attachments upload to the chosen host; paths/artifacts/browser actions cannot cross host boundaries.
+- Existing local-only behavior remains unchanged when no peers are configured. Confirm Quick View/Environment state stays separate and source-scoped.
+- Packaged real two-machine LAN and Tailscale checks, then combined Linux X11/Wayland and secure credential-store checks. No claim of Linux completion from separate historical CI.
+
+## Work performed for this plan
+
+Source and live branch investigation only. No implementation, deployment, branch checkout, or functional test run. Updated this plan and its index, and logged the missing project-memory directory and agent handoff friction in `.papercuts/troubleshooting.md`.
diff --git a/docs/plans/draft-agent-chats-plan.md b/docs/plans/draft-agent-chats-plan.md
new file mode 100644
index 000000000..f854570b0
--- /dev/null
+++ b/docs/plans/draft-agent-chats-plan.md
@@ -0,0 +1,33 @@
+# Draft agent chats
+
+Status: Implemented; pull-request CI and merge pending.
+
+Ordinary desktop workspace chats stay transient until the first user message is durably saved. Opening New Agent, entering an empty workspace, or opening a fresh worktree must not install an empty chat or sidebar history entry. Leaving an unsent draft discards it. A committed message remains saved even if generation fails.
+
+## Implementation
+
+- Use an explicit renderer draft record with a stable future chat ID. Keep it outside persisted chat lists and query caches. Model, workspace, title, Computer Use, attachments and composer options remain local until Send.
+- Freeze first-send input and settings while saving. Commit a complete nonempty chat through an additive desktop IPC, preserving existing workspace authority, attachment quotas, skill leases, turn admission and durability recovery.
+- Store a private first-message receipt. Matching retries confirm the same message; mismatched identifier reuse fails. Reconciliation prevents a lost or uncertain receipt from duplicating a chat.
+- Promote the draft in place using the same chat/component identity. Publish one sidebar entry and start generation once. Navigation wins over late completion; release a pending turn if its conversation is no longer open.
+- Preserve existing Bot, Assistant, scheduled, Telegram and runtime child-agent lifecycles. Remote HTTP contracts remain unchanged; inspect native consumers and validate applicable shared contracts.
+
+## Authorized legacy migration
+
+The owner authorized deleting existing empty chats in this migration. At startup, after recovery and before clients can write, snapshot readable zero-message chat identities and fingerprints before consulting workspace, schedule, artifact, or private-history eligibility stores. Only eligible ordinary chats in registered workspaces are deleted. Exclude Bot/Assistant/Telegram conversations, scheduled task and run references, unreadable records, and chats with staged artifacts or private execution history. A message object counts as history even if its text is empty. Validated header-only Pi journals created by the old Todo snapshot read, including completed empty v3-to-v4 promotions with matching backup/receipt and migration-only scaffolding, do not count as history; body records and uncertain journal state remain protected.
+
+Persist the exact candidate set and per-chat fingerprints before deletion, recheck each candidate and fingerprint, and remove via the existing cross-store deletion service. Checkpoint progress and mark completion once. Interrupted migration resumes only original candidates; subsequent launches never sweep newer empty chats created through unchanged remote APIs. Unknown/corrupt migration state fails closed. If the initial index enumeration or snapshot save fails, startup stops before admitting writers. Unreadable payloads and uncertain eligibility preserve the affected candidates and allow checkpointed completion; they never cause a later resweep. The final cross-store deletion assertion checks only the frozen chat fingerprint and zero-message state, without reopening already-deleted private stores.
+
+## Verification gates
+
+- Draft abandonment through all creation paths creates no chat payload or sidebar row.
+- First send failure preserves composer payload; successful promotion persists one message and runs once.
+- Duplicate submission, changed-payload retry, navigation during saving, workspace removal, document invalidation and post-install storage failure are covered.
+- Migration deletes empty payload/index entries, preserves real history and special conversations, resumes safely, and runs once across restarts.
+- Focused unit/contract tests, Electron draft/migration acceptance, TypeScript, lint and PR exact-head CI must pass before delivery.
+
+No new setup capability or onboarding asset is introduced; this corrects the existing new-chat lifecycle.
+
+## Local verification
+
+The Electron acceptance tests cover: draft abandonment and in-place promotion, one-time migration across restart, definite first-save failure and retry, a delayed receipt after navigation, and corruption-safe migration completion. Shared Remote tests and a generic iOS build-for-testing also pass. Native iOS devices were offline and the local Android toolchain was unavailable; no physical-device acceptance is claimed. The PR checks are the source of truth for final exact-head CI.
diff --git a/docs/plans/libghostty-terminal-plan.md b/docs/plans/libghostty-terminal-plan.md
new file mode 100644
index 000000000..6df10ab8d
--- /dev/null
+++ b/docs/plans/libghostty-terminal-plan.md
@@ -0,0 +1,17 @@
+# Libghostty workspace terminal
+
+Status: Implemented
+
+Replace the workspace drawer's xterm.js emulator with Ghostty's official
+`libghostty-vt` WebAssembly C ABI, following T3 Code's browser adapter:
+runtime + write-pty trampoline, core snapshots, canvas renderer, and surface
+input (IME, selection, scrollback, mouse reporting).
+
+PTY spawn, `TERM=xterm-256color`, snapshot hydrate, and session limits stay in
+`main/services/terminal.ts`.
+
+## Remaining
+
+- Packaged/physical drawer acceptance on a signed Mac build.
+- Optional later native Metal embed if Ghostty publishes a stable headless
+ surface API.
diff --git a/docs/plans/nontechnical-user-journey-ux-plan.md b/docs/plans/nontechnical-user-journey-ux-plan.md
new file mode 100644
index 000000000..fa123a0e1
--- /dev/null
+++ b/docs/plans/nontechnical-user-journey-ux-plan.md
@@ -0,0 +1,372 @@
+# Make Aiden easier to start, understand, and recover
+
+Date: 2026-09-04
+Status: **Active — approved UX implementation in review; broader journey backlog and physical-device usability validation remain open.**
+Baseline: `d40d00f1d`
+Deliverable: UX audit, journey chart, remote-setup proposal, and implementation handoff.
+
+Visual review: [Now vs proposed — interactive HTML](../ux/now-vs-proposed.html). Ten key journeys, with simulated setup/recovery actions. Open the HTML in a browser; it runs locally without dependencies or external requests. Current screens are simplified source-based reconstructions, not screenshots.
+
+
+## Approved implementation in this PR
+
+The user approved the HTML with two copy requirements: show **ChatGPT, LM Studio, Ollama, Other Custom Provider**, followed by **Other ways**, and keep **Create a bot** throughout.
+
+| Journey | Implemented change | Practical boundary |
+| --- | --- | --- |
+| Connect a phone | Two setup cards; one acknowledgement; main-owned setup enables access, prepares the owned route, verifies pairing prerequisites, and issues a code. Rollback, stale review, owner cancellation, and concurrent setup are guarded. | Two desktop actions after choosing the connection method. Changing the selected method adds one choice. Installation, sign-in, HTTPS authorization, scanning, and OS permissions remain external steps. |
+| Connect AI / first chat | Four primary provider choices, additional services under Other ways, custom provider model validation, actionable composer readiness link. | Existing profile/tour and first-chat surfaces remain; no new automatic account sign-in or benchmark fetch. |
+| Create a bot | Two pages; optional appearance and detailed capability controls; explicit model/access review; fresh desktop drafts start Custom with no file, shell, connection, skill, or extra capability grants. Failed saves retain the draft. | Existing bots preserve their saved access. Native bot editors retain their existing defaults in this desktop editor change; no bot-first phase is advanced. |
+| Telegram | Three groups, acknowledgement before enabling, a single enable/connect action, owner pairing status, persistent connect errors; disconnect turns the service off. | BotFather token creation and Telegram owner pairing are still required. Full unattended authority is disclosed before connecting. |
+| Voice | Audio destination labels and persistent recorder/transcription recovery beside the draft, with a direct Voice settings action. | Local model download and cloud credentials remain explicit; recording never sends the draft as a chat. |
+| Computer Use | Plain explanation and acknowledgement before enable; Mac permission action; provider screenshot/text disclosure up front. | Per-chat opt-in, macOS permission gates, and per-control approval remain. |
+| Scheduled work | What / when / access groups followed by a final review; failed saves retain choices. | Existing Create with Aiden natural-language entry remains primary. Script, Full, and MCP authority restrictions remain. |
+| Plugins | Connection details disclosed progressively; Connect verifies tool availability; saved credentials are not labelled as a verified connection. | External authorization remains explicit. An unavailable endpoint leaves a persistent error. |
+| Recovery | Phone setup rollback, preserved pairing lifecycle, composer voice recovery, and bot/schedule draft retention. | Existing native cache/reconnection contracts remain; no automatic mutation replay or new offline-writing contract. |
+| Find settings / mobile pairing | Aiden On The Go destination, natural-language search aliases, updated Mac instructions, QR-first mobile navigation with manual/advanced fallbacks. | Stable settings route IDs and mobile wire protocol are unchanged. |
+
+The 39-row audit below remains the backlog rather than a claim that every possible branch has been redesigned. Release gates and evidence are tracked in [the implementation review](../ux/implementation-review.md).
+
+## Design direction
+
+Make the user's intended outcome the entry point. Aiden should assemble the required settings, explain the consequences once, and carry the user through to a verified result.
+
+Start with **Aiden On The Go**: two setup cards, **Connect your phone** and **Scan to finish**, followed by a connected-device summary. When Tailscale is already ready, the target is **two desktop clicks from the setup page to a usable QR code**. Scanning and any phone/OS permissions are additional actions. A fresh Tailscale installation cannot honestly be a two-click end-to-end experience; it needs guided installation, sign-in, and possibly administrator authorization.
+
+Then apply the same pattern to first chat, provider connection, permissions, Bots, Telegram, voice, plugins, and scheduled work. Reduce technical decisions and context switches; do not remove meaningful control over data, access, spending, or destructive actions.
+
+## What this audit establishes
+
+This is a source-based review of desktop entry points, all 15 Settings destinations, onboarding, chat/workspace controls, and representative iOS and Android pairing, connection, and task surfaces. It includes first use, repeat use, failure, recovery, and removal. The journey inventory below covers the shipped capability families visible in this checkout; it is not an exhaustive traversal of every conditional screen or every OS/account configuration.
+
+Current labels, control dependencies, and state branches are code observations. Assessments of confusion and proposed improvements are UX hypotheses, not measured user behavior. At audit time, no live application walkthrough, external account connection, physical-device test, or user study was performed. The implementation review now records automated Electron walkthroughs; external-account, physical-device, and user-study gates remain open. Release availability, actual timings, and platform-specific system dialogs still need verification before publishing setup instructions.
+
+Existing strengths to preserve:
+
+- Desktop onboarding already has three stages and explicit provider deferral.
+- Settings already has search; many technical remote controls are already in disclosures.
+- Remote pairing already has expiry, one-use codes, authenticated completion, per-device removal, and safe route ownership checks.
+- Bots already have a guided editor and a review step.
+- Schedules already support ordinary repeat/time controls and natural-language creation through the Assistant.
+- Chat drafts, mobile caches, retry states, accessibility options, and local diagnostics have substantial existing support.
+
+The main shortcoming is how these pieces join together. A disclosure can hide a prerequisite without helping the user complete it. A wizard can still demand five difficult decisions. A successful connection does not necessarily mean the user knows what to do next.
+
+## Journey chart
+
+Priority: **P0** = first useful outcome or accurate understanding of access/data; **P1** = common repeat work or recovery; **P2** = specialist convenience. These are UX priorities, not vulnerability ratings. “Gap” is the source-informed hypothesis to validate. Evidence IDs link to the source register below.
+
+### Start and find your way
+
+| ID | User goal and current path | Gap / likely hurdle | Proposed path and completion signal | Priority / evidence |
+|---|---|---|---|---|
+| J01 | Launch → profile → provider → feature tour → app | A name, detailed search disclosure, provider choice, and large feature inventory precede first value. | Keep three stages; make optional profile detail deferrable, explain the AI connection, then offer a first task. Retain the full tour as optional exploration. Success: a first useful reply. | P0 · [S1](#s1) |
+| J02 | Connect AI during onboarding or Providers | API keys, browser sign-in, local servers, and custom Tailscale models require different expertise. | Show “Sign in,” “Use an API key,” and “Use a local or custom model”; progressively reveal relevant fields. Label the actual account/service and costs where known. Success: connection validated and one visible, usable model selected. | P0 · [S1](#s1), [S3](#s3) |
+| J03 | Skip provider → finish setup → try to chat | Deferral is explicit, but reaching the app can be mistaken for chat readiness. | Preserve browsing; place “Connect AI to send your first message” at the composer with a return-to-draft setup action. No automatic paid test prompt. | P0 · [S1](#s1), [S4](#s4) |
+| J04 | New Agent → workspace/context controls → message | “Agent,” “chat,” “workspace,” and “scratch folder” require a mental model too early. | Start with “New chat”; offer “Just chat” and “Work with a folder.” Explain where generated files are saved, including the existing scratch folder behavior. | P0 · [S4](#s4), [S5](#s5) |
+| J05 | Sidebar → workspaces/chats, Bots, Scheduled, Assistant dock | Multiple conversation entry points can look interchangeable. | Explain in empty states: Chat = a task; Bot = a reusable helper with its own ongoing conversation; Scheduled = repeated work; Assistant = help with Aiden. Keep recent work easy to resume. | P1 · [S5](#s5), [S6](#s6), [S8](#s8) |
+| J06 | Settings → search section titles/keywords → section | Search currently filters destinations, not individual fixes; “Android” and ordinary “connect my phone” wording are not explicit Remote Access keywords. | Add intent aliases and result links to exact actions, including phone, sign-in, microphone, update, and missing folder. Preserve existing routes. | P1 · [S2](#s2) |
+
+### Chat and local work
+
+| ID | User goal and current path | Gap / likely hurdle | Proposed path and completion signal | Priority / evidence |
+|---|---|---|---|---|
+| J07 | Choose provider/model; optional Pad and reasoning controls | A large technical inventory makes the first choice hard. | First show current and pinned models with supported capability labels; offer a clearly identified default from the connected inventory. Keep full search/Pad available. Success: user can explain which service receives the message. | P0 · [S3](#s3), [S4](#s4) |
+| J08 | Pick No access / Ask first / Full access; handle approvals | Users must understand scope, and “Full” can sound like a quality setting. | Retain enforced scopes; describe concrete file/command consequences and name the folder. Explain each approval with action, affected resource, and allow-once/deny choices. Full access remains an explicit consequential choice. | P0 · [S4](#s4), [S10](#s10) |
+| J09 | Attach photo/file → model compatibility → send | Ordinary composer can skip images for unsupported models with a toast. User may think the photo was included. | Keep a persistent attachment-level explanation; offer an explicit compatible-model choice without changing recipients silently. Preserve supported attachments and text. Bots keep their separate companion-vision contract. | P0 · [S4](#s4), [S6](#s6) |
+| J10 | Send → streaming answer, tools, reasoning, subagents/todos | Several kinds of activity compete with the actual outcome. | One plain-language current status; expand details when needed. Approval waiting, stopped, failed, and completed must remain distinct. Preserve current cancellation and durable activity semantics. | P1 · [S10](#s10) |
+| J11 | Provider error, interrupted generation, retry | A generic retry can conceal sign-in, quota, network, or uncertain side effects. | Map known failures to “Sign in again,” “Try again,” or an explicit model change. Preserve draft and originating context; do not automatically resend an action with an unknown result. | P0 · [S4](#s4), [S10](#s10) |
+| J12 | Open Files / Review / Quick View / Environment | Container names and Git-only states can obscure the simple goal of finding a result. | Lead with “Files” and “Changes” actions beside relevant output. A non-Git folder should lead to Files with a useful explanation, not an apparent dead end. | P1 · [S11](#s11) |
+| J13 | Open generated artifact → expand/export | The interactive result and the saved deliverable are different objects. | Make preview, export, destination, and export failure clear. Success means a verified usable file, not merely an open preview. | P1 · [S11](#s11) |
+| J14 | Branch/worktree → review → commit → push | Specialist Git vocabulary; save and publish can be confused. | Keep optional developer tools. Add short explanations: commit saves a version locally; push sends commits to the named remote. Preserve separate confirmations, stale-state checks, and conflict handling. | P2 · [S11](#s11) |
+| J15 | Find/rename/delete chats or remove a worktree | Removing a conversation, a saved location, and actual files have different consequences. | Use object-specific removal copy and show exactly what survives. Offer undo only where backend recovery is real; never imply deleted files can be restored without evidence. | P1 · [S5](#s5) |
+
+### Reuse, connect, and automate
+
+| ID | User goal and current path | Gap / likely hurdle | Proposed path and completion signal | Priority / evidence |
+|---|---|---|---|---|
+| J16 | Create Bot → Identity → Access → Model → Capabilities → Review | Five stages and independent model/capability choices before a conversation. | Two core cards: “What should your bot do?” and “Review model and access.” Start a new Bot with a supported minimal custom scope; advanced customization stays available. Model remains explicitly pinned. | P1 · [S6](#s6) |
+| J17 | Edit Bot, customize avatar, enable vision, bind Telegram | Durable identity, optional decoration, and external access are different tasks. | Allow optional avatar editing after first chat. Explain that model changes affect this Bot's ongoing conversation; connect Telegram or vision only on explicit intent, with recipient/access review. | P1 · [S6](#s6), [S7](#s7) |
+| J18 | Telegram profile → token → enable → connect/poll → owner pairing → workspace/model | Multiple toggles and technical descriptions; independent Bot binding can require a second trip to Settings. | Three cards: “Connect Telegram,” “Choose what it can use,” “Send a message to finish.” Resume after BotFather; combine Aiden-owned enable/connect steps after acknowledgement. Verify the authorized owner before claiming readiness. | P1 · [S7](#s7) |
+| J19 | Plugins catalog → preset → credential/authorization → save/test | “Connect” and “Test” may represent different readiness; generic editor exposes commands/headers. | Known plugin → permission/recipient summary → sign in or paste key → supported non-mutating connection verification. Distinguish “Saved” from “Ready.” Keep custom server setup under Advanced. | P1 · [S9](#s9) |
+| J20 | Create/enable skill → invoke with `$` or model use | Difference between skill instructions, executable tools, and Bots is implicit. | Explain “Reusable instructions”; offer a simple example/template and a visible composer picker. Say when instructions are applied; do not claim enabling a skill guarantees invocation. | P2 · [S9](#s9) |
+| J21 | Scheduled → editor or Ask Aiden → timing, scope, model/tools → confirm | Existing ordinary time controls are helpful, but run context is extensive. | Default to “What” and “When,” then one concrete review showing model, folder, access, time zone, and next run. Preserve advanced scripts/cron. Success: saved task with confirmed next run. | P1 · [S8](#s8) |
+| J22 | Run/pause/resume schedule; inspect failure | A schedule can be mistaken for a cloud service that runs while the Mac is unavailable. | Keep “Runs while Aiden is open on this Mac” beside next run. Explain the actual missed-run policy, attention state, and pause status; never imply catch-up behavior without checking scheduler rules. | P1 · [S8](#s8) |
+| J23 | Web Search on/off → provider catalog → routing/setup | Advanced fallback and recipient policy dominates a basic search preference. | First show On/Off and current recipient(s), with concise data disclosure. Keep custom routing below “Search options.” Changing recipients or unattended use remains explicit. | P1 · [S12](#s12) |
+| J24 | Model Pad → benchmark credential/fetch → arrange models; Providers → catalog update | Optional evaluation data may look necessary for chat or become confused with model availability. | Describe it as optional model comparison. Keep manual source-specific fetch actions, provenance, and incomplete-data labels. Never fetch benchmarks or models.dev during setup or ordinary browsing. | P2 · [S3](#s3), [S12](#s12) |
+
+### Use Aiden on another device
+
+| ID | User goal and current path | Gap / likely hurdle | Proposed path and completion signal | Priority / evidence |
+|---|---|---|---|---|
+| J25 | Remote Access → enable → Connection → method → Tailscale Connect → Add device | Primary action is gated by prerequisites the user must find and order. | Two-card setup described below; explicit acknowledgement enables the selected connection and opens pairing after verification. | P0 · [S13](#s13), [S14](#s14) |
+| J26 | Mobile onboarding → prepare Mac → choose connection → camera/manual entry | iOS repeats network choices already encoded in QR; Android puts Paste JSON beside Scan QR. | “Scan the code on your Mac” is primary. Manual setup remains accessible as fallback; payload import becomes Advanced. No second transport decision for a valid QR. | P0 · [S15](#s15), [S16](#s16) |
+| J27 | Pair successfully → choose Bot/workspace; approve browsing folders on Mac | “Connected” can lead to an empty workspace; folder browsing roots and existing workspaces have different scopes. | Show existing permitted content, then “Add a folder on your Mac” only when relevant. Explain precisely that browsing roots govern discovery/addition; do not suggest all existing workspaces are hidden by default. | P0 · [S13](#s13), [S14](#s14), [S17](#s17) |
+| J28 | Leave Wi-Fi, sleep/quit Mac, lose connection → reconnect | Off, unreachable, Tailscale not ready, and revoked are different states. | “Can't reach your Mac” with known facts, preserved drafts/cache, and one relevant next action. Label cached content with freshness; show “Nearby only” for a LAN pairing. Do not assert the Mac is asleep without evidence. | P0 · [S14](#s14), [S17](#s17) |
+| J29 | Pair another Mac/phone → switch installations | Similar Mac names and cached content can conceal which machine will run work. | Keep active Mac visible on action surfaces and approval cards. Verify every newly paired device independently; preserve installation/device-scoped caches and revocation. | P1 · [S13](#s13), [S17](#s17) |
+| J30 | Revoke on Mac or remove saved Mac on phone | Stopping service, removing one credential, and deleting local cached data are different. | Use “Pause phone access,” “Remove device access,” and “Remove this Mac from this phone” with exact consequences. Local removal must not claim server-side revocation unless performed and verified. | P0 · [S13](#s13), [S16](#s16), [S17](#s17) |
+
+### Voice, permissions, maintenance, and help
+
+| ID | User goal and current path | Gap / likely hurdle | Proposed path and completion signal | Priority / evidence |
+|---|---|---|---|---|
+| J31 | Voice settings → provider/model/download → microphone or dictation shortcut | On-device engine setup and cloud credentials precede an apparently simple microphone action. | First microphone use opens relevant setup: show audio destination, download size if needed, and one setup action. Capture only after explicit record intent. Success: editable transcript, not automatic message sending. | P1 · [S18](#s18) |
+| J32 | Mobile speech → native or paired Mac → optional Parakeet setup | Where speech is processed and why the Mac must be online can be unclear. | Label “On this device” / “On your Mac” according to actual supported processing; disclose native service behavior accurately. Show Mac model download progress and retain typed fallback. | P1 · [S14](#s14), [S18](#s18) |
+| J33 | Enable Computer Use → OS Accessibility/Screen Recording → per-chat opt-in → Allow once | Global readiness, OS permissions, and chat authority are separate gates; copy names the driver. | “Let Aiden help in Mac apps” → plain privacy review → request missing OS permissions in order → return to originating chat. Preserve per-chat opt-in and approval before control actions. | P0 · [S19](#s19) |
+| J34 | Memory settings → automatic compaction engine + global/workspace memory | Conversation shortening and durable remembered facts are presented together. | Explain “Keep long chats working” separately from “Remember useful information.” Put experimental engine selection under Advanced. Any future fact viewer/delete action needs actual storage support. | P1 · [S20](#s20) |
+| J35 | Appearance / shortcuts → customization and conflict handling | Useful existing controls need to remain discoverable through a simpler information architecture. | Keep system defaults, text size, contrast, reduced motion, and shortcut conflict repair accessible; no prerequisite customization tour. Test keyboard-only and screen readers across setup. | P1 · [S21](#s21) |
+| J36 | Profile → usage/date range → share snapshot | Tokens, estimates, and actual provider bills can be confused; profile sharing includes a name. | Explain request/usage totals, cost coverage and missing prices; do not present estimates as invoices. Keep preview and explicit sharing with the included personal data visible. | P1 · [S22](#s22) |
+| J37 | About/sidebar → update → download/retry/restart | App restart can interrupt an ongoing task; failures need a durable next action. | Clear progress and “Restart to update” when safe; retain existing active-work guards and retry. Distinguish installed version from downloaded update. | P1 · [S5](#s5), [S23](#s23) |
+| J38 | About → reopen onboarding vs reset onboarding; diagnostics → export/delete | “Reset onboarding” sounds like replaying a tutorial but its description clears profile setup/preferences. | Rename by actual consequence; separate “Show setup again,” scoped repairs, and destructive reset. Support export explains local contents; sensitive dumps remain a separate explicit choice. | P0 · [S23](#s23) |
+| J39 | Ask Assistant for help setting up the app | Assistant settings explicitly say it cannot inspect live settings/projects or use connected tools. | Initially provide accurate guidance and links. A future “Help me set this up” capability must use a bounded reviewed setup operation and confirmation; do not advertise it as shipped. | P1 · [S8](#s8) |
+
+## The Aiden On The Go proposal
+
+### Two setup cards, then a useful connected state
+
+Use **Aiden On The Go** as the user-facing destination, with “Remote Access” retained as a searchable alias. Settings, onboarding's optional feature tile, and the existing connection popover should open the same setup state.
+
+| Card | What the user sees | Primary action | What Aiden handles |
+|---|---|---|---|
+| **1. Connect your phone** | “Use your Bots and workspaces from your phone or tablet while Aiden is running on this Mac.” Connection choice: **Away from home — uses Tailscale on both devices** or **On the same Wi-Fi — no Tailscale needed**. Show the available recommended route, never hide its requirement. | **Connect a device** opens the acknowledgement below. | Read current settings and local readiness. Prepare a summary of the exact proposed changes. No service or route mutation merely from opening the page. |
+| **2. Scan to finish** | After confirmation: compact preparation progress, then QR; “Open Aiden On The Go on your phone and scan this code.” Mac name visible. Manual-code fallback available. | Phone: **Scan code**. Desktop: **Create new code** only when required. | Enable the chosen service/mode, configure the Aiden-owned private connection when permitted, verify it, then open the existing one-use pairing window. Track authenticated completion. |
+| **Connected summary** | “[Device name] is connected to [Mac name].” Show “Nearby only” or “Uses Tailscale,” available content, and “Keep Aiden running on your Mac.” | Phone: **Open a Bot** or **Open a workspace**, according to available content. | Show current reachability separately from saved pairing. Keep device management and advanced connection diagnostics below. |
+
+There are only two setup cards. If a dependency is missing, replace the preparation area inside card 2 with a single repair instruction. Do not add an expanding wall of independent switches. Optional folder access is a follow-up in the connected summary; it does not block pairing or Bot use.
+
+### One acknowledgement modal
+
+For the Tailscale path:
+
+> **Connect your phone to this Mac?**
+>
+> Aiden will turn on phone access, set up its private connection through Tailscale, and show a one-time code for your phone.
+>
+> Paired devices can use the workspaces and capabilities this Mac allows. Your AI keys stay on this Mac; requests still go to the AI service you choose. Keep Aiden running to use it from your phone.
+>
+> You can remove a device's access here at any time.
+>
+> **Enable and show code** · **Cancel**
+
+For nearby access, replace the first paragraph with: “Aiden will turn on phone access over your local network and show a one-time code. Your phone and Mac need to be on the same network.”
+
+The scope sentence must be built from the actual current permissions and allowed workspaces. Put a human-readable access summary behind **Review access**, with no new grants selected automatically. Enabling the network connection is not permission to grant the home folder, Full access, unattended tools, or every Bot capability.
+
+The primary button is the acknowledgement. Do not add an “I understand” checkbox or a second generic confirmation. Use a separate review only if the proposed action materially changes, such as replacing a previous Aiden connection or changing an existing device's route.
+
+### Honest click budget
+
+Count desktop clicks starting on the setup page; network waits, QR scanning, text entry, OS permissions, and external sign-in are recorded separately. Current counts are inferred from controls and vary with saved settings; establish the actual baseline in the live test.
+
+| Starting state | Target Aiden interaction | Extra work that must remain visible |
+|---|---|---|
+| Fresh Aiden remote setup, Tailscale already installed/signed in/HTTPS authorized, default route suitable | **Connect a device → Enable and show code** | Phone scan and any camera permission; both devices need authorized Tailscale connectivity. |
+| Same Wi-Fi chosen instead of the suggested away route | Select **On the same Wi-Fi**, then the two actions above | Phone camera/local-network permissions and scan. This is three desktop clicks when a route choice is changed. |
+| Existing ready connection; add another device with unchanged scope | **Add device** opens code directly; existing access summary remains visible | Phone scan. No repeated acknowledgement of unchanged settings. |
+| Tailscale missing or signed out | Same two Aiden setup actions, then a guided prerequisite | Installation, sign-in on both devices, and any required HTTPS/admin approval. Resume rather than restart. No two-click completion claim. |
+| Conflict or unknown previous route result | Explain and offer the applicable review/verification | Owner review or external repair may be necessary; do not overwrite a connection to satisfy a click target. |
+
+### State and recovery contract
+
+```mermaid
+flowchart TD
+ A[Connect a device] --> B[Review and confirm access setup]
+ B --> C[Check selected connection prerequisites]
+ C -->|Missing| D[Show one specific setup action]
+ D -->|Return and recheck| C
+ C -->|Ready| E[Prepare and verify connection]
+ E -->|Verified| F[Show one-time QR code]
+ E -->|Conflict or uncertain result| G[Explain and review or verify]
+ G -->|Resolved| C
+ F -->|Authenticated phone completion| H[Connected: choose a first task]
+ F -->|Expired| I[Create a new code]
+ I --> F
+```
+
+| State | Plain-language presentation | Required behavior |
+|---|---|---|
+| Tailscale missing | “To connect away from home, install Tailscale on your Mac and phone.” **Get Tailscale**; **Use same Wi-Fi instead**. | Use reviewed official destinations; do not install or authorize it silently. Changing transport requires the updated scope to be visible. |
+| Tailscale signed out | “Open Tailscale and sign in on both devices to the same private network.” **Open Tailscale**. | Recheck on return; preserve setup progress. Mac readiness alone cannot prove phone membership. |
+| HTTPS approval missing | “Your Tailscale network needs permission to create a secure connection. You may need its administrator.” **View setup instructions**. | Keep HTTPS authorization explicit; do not auto-change account/network policy. |
+| Preparing | “Turning on phone access…” → “Preparing your private connection…” → “Checking the connection…” | Ordered, bounded operations; one active attempt. No QR until the selected transport is verified. |
+| Different Aiden profile uses route | “Another Aiden profile is using this Mac's phone connection.” | Keep the current route. Active owner blocks; a stale owner gets a specific review. Never overwrite unrelated routes or enable Funnel. |
+| Unknown route result | “We couldn't confirm whether setup finished.” **Check connection**. | Reconcile observed ownership/health before retrying; never claim nothing changed without evidence. |
+| QR ready / consumed / expired | “Scan this code”; “Finishing connection”; “This code expired.” | Preserve existing five-minute one-use lifecycle and identity checks. Do not weaken/manual-shorten the setup secret. Do not interrupt a completing phone handshake to rotate the code. |
+| Camera denied / unavailable | “Camera access is off. You can enter a setup code instead.” | Provide accessible manual pairing and OS-settings recovery. Keep address required where discovery cannot supply it. |
+| Paired but no usable content | “Connected. Open a Bot, or choose a workspace on your Mac.” | Tailor to actual inventory and granted scope; never silently approve a folder or select a different AI recipient. |
+| Unreachable later | “Can't reach [Mac name]. Keep Aiden running and check the connection.” | Preserve drafts/cache with explicit freshness. Retry only safe reads; revoked credentials go to re-pairing and cache cleanup. |
+
+### Orchestration requirements for implementation
+
+Reuse existing service, route, pairing, and revocation logic. Add a main-process-owned setup coordinator rather than a fragile sequence of renderer toggle clicks. The new operation must:
+
+1. Capture the exact profile, prior enabled/mode state, route ownership, and reviewed change scope. Recheck before each mutation; reject a stale review if consequences changed.
+2. Perform prerequisite checks before avoidable mutations. Then enable the selected service, configure only the owned connection, verify health, and begin pairing in the order required by the existing service contract.
+3. Serialize attempts and handle double clicks, navigation, app restart, cancellation, and late responses. Reuse the existing authenticated pairing-completion lifecycle.
+4. Preserve pre-existing enabled access, devices, roots, endpoints, and unrelated Tailscale handlers. Do not silently select “both” to make discovery easier or change an established mobile endpoint.
+5. On failure/cancel, close the exact unused pairing session. Roll back only changes proven to belong to this attempt when no completed pairing or concurrent change depends on them. If cleanup is uncertain, report what is known and offer verification; never blanket-reset Tailscale.
+6. Distinguish preparation, code-ready, paired, reachable, and useful-content states. A local listener, created QR, or consumed code alone is not completion.
+7. Keep secrets, codes, endpoints, raw Tailscale output, and identifiers out of diagnostics. Optional UX measurements must be coarse local counters, not new upload telemetry.
+
+This is more than rearranging controls. Safe orchestration and recovery are the substantial engineering work; the two-card surface is its presentation.
+
+### Mobile parity and accurate copy
+
+- iOS and Android should use the same user concepts and state meanings while retaining native interaction patterns. Both default to scanning, support accessible manual entry, and put payload import under Advanced.
+- Update desktop device labels, empty states, and onboarding copy to include Android where the shipped build supports it. `SettingsDeviceRow` currently renders every non-iPad device as “iPhone”; this needs contract review before choosing a corrected type mapping.
+- Verified during implementation: the manual setup code decrypts the bootstrap on the phone and is never sent to the Mac. Preserve that accurate disclosure and the existing cryptography. This does not mean prompts or all chat data stay on the phone.
+- Remove transport terminology from the primary phone path because a valid QR already specifies its endpoint. Keep endpoint/pin information available for manual setup and identity problems.
+- Never bypass an identity mismatch, credential revocation, system permission, or unavailable feature on an older client. Provide a named recovery action or compatible fallback.
+
+## A consistent pattern for every setup
+
+Use **Choose outcome → review meaningful consequences → prepare automatically → verify → first useful action**. Keep the interface to two or three cards where that actually simplifies decisions. Do not force ordinary repeat actions into a wizard.
+
+| Setup | First card | Second card | Optional third / completion |
+|---|---|---|---|
+| AI connection | Choose how to connect | Sign in or provide required key; verify | Selected model and **Start a chat** |
+| Bot | Describe its job | Review explicit model and minimal supported access | **Create and chat**; appearance/custom scope optional |
+| Telegram | Connect your Telegram bot | Review owner and allowed work | Send pairing message; confirm connection |
+| Voice | Choose where audio is processed | Complete required download/permission | Return to editable composer and record on intent |
+| Computer Use | Explain screenshots and actions | Complete missing OS permissions | Enable for originating chat with existing action approvals |
+| Plugin | Choose service and review access | Sign in/key and verify | Show available tools and return to task |
+| Schedule | Describe work and when | Review exact time, model, scope and cost implications | Show next run and how to pause |
+
+Use one acknowledgement when an action enables remote access, changes recipients, grants capabilities, schedules unattended work, or downloads a substantial optional model. Use direct actions with clear feedback for ordinary navigation, unchanged repeat pairing, and reversible preferences. Preserve separate destructive confirmation where warranted.
+
+For new users, offer defaults derived from actual supported inventory. Do not silently replace a user's model, inherit Full access into a new Bot, enable unattended web/plugin access, or change a saved privacy preference. A “recommended” label needs a transparent reason, such as “already connected,” not an invented quality ranking.
+
+## Language and settings organization
+
+| Current wording | Proposed primary wording | Keep in detail when useful |
+|---|---|---|
+| Remote Access | Aiden On The Go / Connect your phone | Remote Access as search alias |
+| Tailscale / Local Network | Away from home / On the same Wi-Fi | Tailscale requirement and actual route |
+| Tailscale Serve | Private phone connection | Exact route/command and diagnostics |
+| Approved roots | Folders your phone can browse | Root restrictions and existing-workspace distinction |
+| Revoke | Remove device access | Immediate credential invalidation |
+| Per-device credential / Pinned HTTPS identity | Only paired devices can connect | Identity verification details |
+| Pi-powered teammate | Bot | Runtime names in developer information |
+| Polling / polling lease | Connected / Checking for messages | Troubleshooting diagnostics |
+| MCP server | App connection, or named plugin | MCP in Advanced and search aliases |
+| Compaction | Keep long chats working | Summarization engine and experimental controls |
+| Reset onboarding | Reset profile setup and preferences | Exact affected/preserved data from backend |
+
+Keep sentences accurate before making them shorter. For example, “Stored on this Mac” does not imply information is never included in a model request. “Same Wi-Fi” needs a fallback explanation for wired Macs and networks that isolate devices. “Away from home” still requires the Mac to be reachable and the phone to have the intended private-network access.
+
+Proposed Settings grouping, retaining deep links and expert access:
+
+| Group | Destinations / actions |
+|---|---|
+| AI and chat | AI connections, optional Model Pad, memory |
+| Apps and tools | Plugins, Skills, Web Search, Computer Use |
+| Phone and automation | Aiden On The Go, Telegram, Scheduled tasks |
+| Personal preferences | Appearance, Voice, Keyboard shortcuts, Assistant |
+| Help and app | Updates/About, replay setup, diagnostics, carefully separated reset |
+
+Prototype and test this grouping before moving navigation. The first implementation should repair high-friction journeys and copy without requiring a whole-app navigation migration.
+
+Every disabled primary control needs a nearby reason and a relevant action. Every empty state needs a next step. Every failure should say what happened, what is preserved, and what the user can do; do not promise preservation if outcome is unknown. Keep raw diagnostic detail expandable and copyable without displaying credentials.
+
+## Visual and accessibility requirements
+
+Use Aiden's existing semantic tokens and UI primitives, informed by [the desktop reference](../chatgpt-desktop-ui-inspiration.md) and [the interactive specimen](../chatgpt-ui-element-specimen.html). This proposal adds no new application UI or assets.
+
+- Cards use existing backgrounds and spacing. No decorative borders/outlines around radio choice cards; selection uses the radio and background state.
+- Status uses soft semantic fills, text, and icons, never color alone or decorative colored outlines.
+- Non-text keyboard controls retain visible neutral focus rings. Text-entry borders stay unchanged on focus; use existing input-background/caret states.
+- Dialogs announce their title, contain focus appropriately, support cancel, and return focus to the initiating control. Step changes have concise screen-reader announcements.
+- Progress is readable without animation. Respect reduced motion, text scaling, light/dark/high-contrast settings, and narrow desktop/mobile layouts.
+- QR pairing cannot be the sole accessible route. Do not announce a countdown every second; announce meaningful state changes and keep time remaining available.
+- Onboarding must stay concise and data-driven. Reuse the existing Aiden On The Go illustration when updating that tile. Any new advertised durable feature requires its own optimized 1024 × 1024 transparent PNG and the existing asset-contract test.
+
+## Delivery order and acceptance gates
+
+| Phase | Concrete deliverable | Dependencies and acceptance |
+|---|---|---|
+| 0 — Establish baseline | Walk through J01–J39 and mark observed/pass/fail/not applicable on actual builds; prototype remote cards. | No user-account/permission mutations during inspection without the corresponding user action. Record actions, navigation changes, completion, and confusing words. |
+| 1 — Remote setup | Main-owned setup operation, two-card desktop flow, acknowledgement, recovery, native pairing copy/navigation, optional onboarding entry, updated remote guide. | Cover already-ready LAN/Tailscale, missing prerequisites, conflicts, cancellation, expiry, multiple profiles/devices, stale clients, and revocation. Two desktop clicks on the defined ready/default path. |
+| 2 — First useful chat | Provider return-to-draft setup, deliberate model default, workspace wording, attachment compatibility recovery, actionable blocked composer. | Reuse onboarding validation; preserve provider choice and privacy defaults. Verify key-invalid, cancelled sign-in, no models, all-hidden models, offline provider, and failed send. |
+| 3 — Other setup journeys | Bot, Telegram, voice, Computer Use, plugins, schedules using the shared UX pattern. | Ship in independently testable slices; keep backend access distinctions and explicit external authorization. No new unsupported “safe” Bot mode label. |
+| 4 — Recovery and navigation | Settings intent search, memory/help/reset clarity, persistent repair actions, optional grouping changes. | Preserve deep links, shortcuts, accessibility, expert controls, and safe migration of existing preferences. |
+
+**Phase 1 definition of done:** a user can start at the setup page, understand what will be enabled, get a working code on a ready connection in two desktop clicks, finish pairing on iOS or Android, identify the connected Mac, open permitted content, recover from a blocked setup, and remove access. All existing identity/ownership safeguards must still pass.
+
+**Engineering checks for future implementation:**
+
+- Extend relevant existing desktop tests; register any added test file in `package.json`. Phase 1 includes `npm run test:aiden-remote`, `npm run test:onboarding`, and focused settings/command/connection-popover coverage where changed, plus type checking and build.
+- For shared remote contracts or transcript/activity changes, inspect and update **both** native consumers and focused tests. Run applicable iOS tests under its documented Xcode workflow and Android Gradle suites; do not claim mobile validation from desktop tests alone.
+- Other slices use the existing provider, Bots, scheduled, voice, web-search, Computer Use, memory, and command suites as relevant. Check `package.json` for the exact current scripts when implementing.
+- Test outcome and state behavior, not only copy snapshots: one attempt per gesture, no premature success, no stale-result publication, preserved drafts, accurate cleanup, no unauthorized scope change, and safe re-entry.
+- Add live keyboard/screen-reader, mobile camera/manual-entry, background/foreground, and Mac unavailable checks. Keep physical-device gates open until performed.
+
+**Validation for this document:** source references and local links checked, journey IDs checked for uniqueness, and `git diff --check`. Application tests are not required for this documentation-only proposal; none of the proposed behaviors have been implemented or runtime-validated here.
+
+## Usability study and success targets
+
+Use five to eight participants unfamiliar with developer tools. Include both mobile platforms, a keyboard-only/screen-reader session, someone without an AI connection, and someone without Tailscale. Use consented test accounts/devices; count external setup separately.
+
+| Task | What to observe | Proposed acceptance target, not a measured result |
+|---|---|---|
+| Connect AI and ask a first question | Abandonment, terms needing explanation, lost drafts | At least 80% complete without moderator intervention after account prerequisites are met. |
+| Pair phone on prepared Tailscale | Desktop actions, transport confusion, accurate readiness | Two desktop clicks to QR on the defined default path; at least 80% finish pairing unassisted. |
+| Pair phone with no Tailscale | External handoff, return/resume, understanding nearby alternative | Participants can identify the next required action and resume without repeating completed setup. |
+| Recover from denied camera or unreachable Mac | Recovery discoverability, draft preservation | At least 80% find manual entry or the relevant recovery action without help. |
+| Explain and remove access | Understanding of running Mac, provider requests, allowed work, removal | Every participant can locate removal; any misunderstanding of access/data consequences triggers copy redesign. |
+| Create Bot and schedule a task | Required decisions and scope comprehension | At least 80% complete unassisted and can explain the selected model, access, next run, and Mac availability requirement. |
+
+Measure completion time, decision count, navigation changes, backtracking, assistance requests, and one post-task ease rating. Establish actual baseline values before setting time-reduction claims. Store research observations with consent; any product counters remain local and categorical unless separately approved. A small study identifies friction; it does not prove accessibility or population-wide success.
+
+## Implementation handoff prompt
+
+> Implement Phase 1 of `docs/plans/nontechnical-user-journey-ux-plan.md`. Read project instructions, current memory, remote hardening/manual-pairing plans, and both UI design references first. Replace dependency hunting in Aiden On The Go setup with the two-card, explicitly acknowledged flow and a main-process-owned coordinator. Preserve route ownership, endpoint stability, one-use codes, identity validation, permissions, per-device revocation, and all existing-device state. Keep Tailscale installation/sign-in/HTTPS authorization as guided external prerequisites. Include iOS and Android pairing/copy parity, relevant onboarding updates, recovery states, focused tests, remote setup documentation, and plan/memory updates. Treat the two-click budget as applying only to the specified prepared default route. Validate the work and report any remaining physical-device gates. Leave later phases proposed until separately scoped.
+
+## Source register
+
+Paths below are the authoritative audit evidence. Component code takes precedence where older narrative documentation uses superseded labels. Sources support the current-state observations; proposed copy and flows are recommendations.
+
+**S1 — First run:** [onboarding flow](../../renderer/components/onboarding-flow.tsx), [onboarding tests](../../renderer/components/onboarding-flow.test.tsx), [auth/validation plan](onboarding-auth-and-provider-validation-plan.md).
+
+**S2 — Settings:** [destinations and search keywords](../../renderer/shared/settings-section.ts), [settings view](../../renderer/main/settings-view.tsx).
+
+**S3 — Providers/models:** [providers](../../renderer/components/settings/providers-settings.tsx), [custom provider editor](../../renderer/components/settings/provider-editor.tsx), [model picker](../../renderer/components/model-picker.tsx), [model visibility](../../renderer/components/settings/provider-model-visibility.tsx).
+
+**S4 — Compose:** [composer](../../renderer/components/composer.tsx), [workspace picker](../../renderer/components/workspace-picker.tsx), [chat pane](../../renderer/main/chat-pane.tsx).
+
+**S5 — Navigation and history:** [sidebar](../../renderer/components/chat-sidebar.tsx), [chat layout](../../renderer/main/chat-layout.tsx).
+
+**S6 — Bots:** [desktop Bots/editor](../../renderer/main/bots-view.tsx), [iOS editor](../../ios/AidenOnTheGo/Features/Bots/AidenBotEditorView.swift), [Android editor](../../android/app/src/main/java/sbtbiswas/AidenOnTheGo/features/bots/AidenBotEditorScreen.kt), [Bot-first plan](bot-first-aiden-on-the-go-plan.md).
+
+**S7 — Telegram:** [settings](../../renderer/components/settings/telegram-settings.tsx), [parity plan](telegram-first-class-agent-parity-plan.md).
+
+**S8 — Schedules/Assistant:** [task editor](../../renderer/components/scheduled-task-editor.tsx), [tasks view](../../renderer/components/scheduled-tasks-view.tsx), [Assistant capability disclosure](../../renderer/components/settings/assistant-settings.tsx), [Assistant automation approval](../../renderer/components/assistant/assistant-automation-approval.tsx).
+
+**S9 — Plugins/skills:** [plugin settings](../../renderer/components/settings/mcp-settings.tsx), [preset setup](../../renderer/components/settings/mcp-preset-setup.tsx), [skills](../../renderer/components/settings/skills-settings.tsx).
+
+**S10 — Progress/approval/recovery:** [activity feed](../../renderer/components/activity-feed.tsx), [subagent shell approval](../../renderer/components/subagent-shell-approval.tsx), [provider failure mapping](../../main/services/provider-failure.ts), [composer](../../renderer/components/composer.tsx).
+
+**S11 — Work surfaces/results:** [Files](../../renderer/components/files-panel.tsx), [Review](../../renderer/components/review-panel.tsx), [Environment](../../renderer/components/environment-panel.tsx), [artifact preview/export](../../renderer/components/html-artifact-frame.tsx), [commit](../../renderer/components/git-commit-dialog.tsx), [push](../../renderer/components/git-push-dialog.tsx).
+
+**S12 — Search and optional model information:** [Web Search](../../renderer/components/settings/web-search-settings.tsx), [Model Pad](../../renderer/components/settings/model-pad-settings.tsx), [model data](../../renderer/components/settings/model-data-settings.tsx), [manual catalog policy](../../AGENTS.md).
+
+**S13 — Desktop remote UX:** [settings and pairing dialog](../../renderer/components/settings/remote-access-settings.tsx), [remote settings tests](../../renderer/components/settings/remote-access-settings.test.tsx), [connection popover](../../renderer/components/remote-connection-popover.tsx), [pairing lifecycle](../../renderer/lib/remote-pairing-lifecycle.ts).
+
+**S14 — Remote boundaries:** [remote guide](../aiden-on-the-go-remote-access.md), [manual pairing plan](aiden-manual-pairing-plan.md), [multi-instance hardening](completed/aiden-remote-multi-instance-hardening-plan.md), [remote API](../aiden-remote-api-v1.md).
+
+**S15 — iOS pairing:** [onboarding and pairing view](../../ios/AidenOnTheGo/Features/Remote/AidenPairingView.swift), [remote client](../../ios/AidenOnTheGo/Networking/AidenRemoteClient.swift).
+
+**S16 — Android pairing:** [pairing and removal screen](../../android/app/src/main/java/sbtbiswas/AidenOnTheGo/features/remote/AidenPairingScreen.kt), [remote client](../../android/app/src/main/java/sbtbiswas/AidenOnTheGo/networking/AidenRemoteClient.kt).
+
+**S17 — Native continuation:** [iOS coordinator](../../ios/AidenOnTheGo/Features/Remote/AidenRemoteCoordinator.swift), [iOS workspace shell](../../ios/AidenOnTheGo/Features/Remote/AidenWorkspaceShellView.swift), [Android product shell](../../android/app/src/main/java/sbtbiswas/AidenOnTheGo/features/remote/AidenProductShellScreen.kt), [Android workspace shell](../../android/app/src/main/java/sbtbiswas/AidenOnTheGo/features/workspaces/AidenWorkspaceShellScreen.kt).
+
+**S18 — Voice:** [voice settings](../../renderer/components/settings/voice-settings.tsx), [local voice setup](../../renderer/components/settings/local-voice-settings.tsx), [paired-Mac speech](../aiden-on-the-go-remote-access.md#paired-mac-voice-input).
+
+**S19 — Computer Use:** [settings and disclosures](../../renderer/components/settings/computer-use-settings.tsx), [hardening plan](update-microphone-computer-use-hardening-plan.md).
+
+**S20 — Memory:** [memory settings](../../renderer/components/settings/memory-settings.tsx), [compaction plan](compaction-plan.md).
+
+**S21 — Personal preferences:** [appearance](../../renderer/components/settings/appearance-settings.tsx), [shortcuts](../../renderer/components/settings/shortcut-settings.tsx), [semantic appearance definitions](../../renderer/shared/appearance.ts), [style tokens](../../renderer/styles.css).
+
+**S22 — Usage/sharing:** [profile](../../renderer/main/profile-view.tsx), [share card](../../renderer/components/usage/profile-share-card.tsx).
+
+**S23 — Maintenance:** [About/update/reset](../../renderer/components/settings/about-settings.tsx), [diagnostics](../../renderer/components/settings/diagnostics-settings.tsx), [test scripts](../../package.json).
diff --git a/docs/plans/performance-stability-efficiency-plan.md b/docs/plans/performance-stability-efficiency-plan.md
index f5467aaf8..1ab6358be 100644
--- a/docs/plans/performance-stability-efficiency-plan.md
+++ b/docs/plans/performance-stability-efficiency-plan.md
@@ -56,7 +56,7 @@ The first implementation milestone should therefore be **data safety and bounded
| P1 | Scheduled catch-up has per-task overlap protection but no global budget or battery/lock policy | `main/services/schedule-service-core.ts` | Multiple missed tasks can stampede after startup/resume |
| P2 | The closed model picker queries every provider and rebuilds/sorts catalog structures during parent renders | `renderer/components/model-picker.tsx`, `renderer/lib/queries.ts` | Stream-frame work scales with provider/model count |
| P2 | Startup waits for provider enumeration/auth state before the first React render | `renderer/main/index.tsx`, `main/services/provider-registry.ts` | A slow keychain/provider probe delays visible app chrome |
-| P2 | Routes, settings, xterm, KaTeX, and full Highlight.js are in an eager startup graph | `renderer/main/router.tsx`, `renderer/main/settings-view.tsx`, `renderer/components/code-block.tsx` | Larger parse/compile/startup and update payload |
+| P2 | Routes, settings, terminal, KaTeX, and full Highlight.js are in an eager startup graph | `renderer/main/router.tsx`, `renderer/main/settings-view.tsx`, `renderer/components/code-block.tsx` | Larger parse/compile/startup and update payload |
| P2 | Terminal output and LLM deltas cross IPC at source cadence; terminal buffers repeatedly copy large strings | `main/services/terminal.ts`, `main/services/llm-client.ts` | Excess wakeups, IPC allocations, and resize churn |
| P2 | Several realistic lists are unwindowed | files, review, chat/model palettes, transcript | Large workspaces and histories degrade nonlinearly |
@@ -239,7 +239,7 @@ Exit gate:
#### 4B. Render sooner and load optional code later
- Render the lightweight shell before provider enumeration. Show a truthful provider-hydration state and enable composer selection only after alias/identity migration is authoritative.
-- Dynamically import Settings/Profile/Scheduled routes, individual heavy Settings sections, terminal/xterm on first open, and other secondary panels.
+- Dynamically import Settings/Profile/Scheduled routes, individual heavy Settings sections, terminal/libghostty on first open, and other secondary panels.
- Keep ChatLayout, transcript shell, composer, selected-model trigger, and generation bridge in the initial graph. Optionally idle-preload the next likely surface after first input readiness.
- Use package-content allowlists. Bundle pure-JS main dependencies when safe; externalize/unpack only native/runtime-required modules.
- Disable packaged source maps or publish hidden maps outside the app artifact. Add a test that no `.map` is shipped.
diff --git a/docs/plans/pi-compaction-memory-upgrade-implementation-notes.md b/docs/plans/pi-compaction-memory-upgrade-implementation-notes.md
index 045a85f9b..2f7de22e6 100644
--- a/docs/plans/pi-compaction-memory-upgrade-implementation-notes.md
+++ b/docs/plans/pi-compaction-memory-upgrade-implementation-notes.md
@@ -399,7 +399,12 @@ claimed or selected without its device-local receipts.
then `v4_only`. The same authoritative chat eligibility controls new v4
journal creation, legacy migration, automatic and manual Pi checkpoints, and
memory. In particular, a pre-existing chat without a journal is not silently
- classified as new. `AIDEN_PI_UPGRADE_BEHAVIOR_ENABLED=0` is read once at
+ classified as new. Rollout-ineligible chats therefore generate journalless
+ over an in-memory session (`openChatIfEligible` reports a structured reason
+ instead of throwing; recall is omitted, effect recovery is never marked
+ durable, and the durable store is never quarantined), so no stage blocks
+ generation — see the "Journalless generation" section of the Phase 7
+ rollout runbook. `AIDEN_PI_UPGRADE_BEHAVIOR_ENABLED=0` is read once at
startup and disables journal creation/migration, automatic/manual checkpoint
generation, and memory while retaining byte-stable read access to existing
v4 journals.
diff --git a/docs/plans/scheduled-provider-and-pi-rollout-recovery-plan.md b/docs/plans/scheduled-provider-and-pi-rollout-recovery-plan.md
new file mode 100644
index 000000000..550ad4931
--- /dev/null
+++ b/docs/plans/scheduled-provider-and-pi-rollout-recovery-plan.md
@@ -0,0 +1,94 @@
+# Scheduled-Task Provider Recovery and Pi Rollout Generation Fix
+
+Status: Implemented (2026-09-09) — Phases A, B2, and C are coded and green in
+worktree `.worktrees/prod-error-recovery` (branch `fix/scheduled-provider-and-pi-rollout`);
+B1 (operator stage advance) and machine remediation remain release-owner steps.
+Originated from installed production diagnostics on 2026-09-09
+(app v0.39.0, `~/Library/Application Support/Aiden Agent`).
+
+## Problem
+
+Two production failures surfaced from the installed app's logs and data:
+
+1. **Scheduled LLM tasks fail forever with "Choose a provider before running
+ this scheduled task."**
+ - Thrown at `main/services/schedule-execution.ts:233` when both
+ `task.providerId` and `settings.lastProviderId` are empty.
+ - UI-created tasks never store a provider (`renderer/components/scheduled-tasks-view.tsx`
+ `newTask()`; the editor has no provider picker), and the fallback key
+ `settings.lastProviderId` is only ever written by the Telegram flow while
+ the app's real selection lives in renderer localStorage
+ (`renderer/lib/use-model-selection.ts`), invisible to the main-process
+ scheduler.
+2. **"Generation failed: Pi v4 journal creation is outside the active device
+ rollout stage."**
+ - Thrown at `main/services/pi-compaction-session-store.ts:675` when a chat
+ has no v4 journal and the device-local rollout policy (stage
+ `new_chats`, `activatedAt` = first launch of the Pi-upgrade build) marks
+ the chat as pre-activation.
+ - `main/services/llm-client.ts` opens the journal unconditionally and
+ hard-fails generation without one, so every chat created before
+ activation is blocked from generating until the operator advances the
+ rollout stage.
+3. **Remote 4xx bursts** in rotated diagnostics
+ (`remote-request-failed`, route categories workspaces/chats/schedules/usage)
+ — cause unknown; needs route/version evidence before a fix.
+
+## Fix design
+
+### Phase A — scheduled-task provider resolution
+
+- **A1 (main):** attended renderer chat starts persist
+ `lastProviderId`/`lastModel` into app settings so the documented scheduler
+ fallback resolves the selection the app actually uses. Attended
+ renderer-owned starts only; scheduled/subagent/bot streams must not
+ overwrite the user default.
+- **A2 (renderer + tool):** pin providers explicitly —
+ `newTask()`/templates prefill from the current model selection; the task
+ editor gains a provider/model picker (default "App default"); chat-driven
+ `schedule_task` creation stops displaying "Scheduler default" when nothing
+ resolves and rejects creation instead of saving a task that can only fail.
+- **A3:** editor + parse guardrail warns when an LLM task has no provider and
+ no app default exists yet.
+- Contract unchanged: `providerId` stays optional; remote/mobile-created
+ tasks already pin concrete providers.
+
+### Phase B — Pi rollout generation block
+
+- **B1 (operational, release owner):** advance the device per
+ `docs/testing/pi-compaction-phase7-rollout-gates.md` (evaluation receipt →
+ installed receipt → `npm run pi-upgrade:advance -- migrated_low_risk_chats`).
+ Note `AIDEN_PI_UPGRADE_BEHAVIOR_ENABLED=0` does not restore generation for
+ journal-less chats.
+- **B2 (code):** generation must never be hard-blocked by the rollout gate,
+ while preserving the fail-closed contract that a pre-existing chat is never
+ silently given a v4 journal or migrated:
+ - `pi-compaction-session-store.ts` gains `openChatIfEligible()` returning
+ either a session or a structured rollout-ineligible/legacy-deferred
+ reason; `openChat()` keeps its throws for background callers.
+ - `llm-client.ts` uses the probe and, when ineligible, runs the turn
+ journalless over an in-memory session (child-agent precedent): no v4
+ journal is created, effect recovery is never marked durable, and store
+ quarantine can never fire for an in-memory failure. VCC recall is
+ omitted; todo replay runs against the empty in-memory journal.
+ - `chats:todoSnapshot` and the context-lifecycle compaction caller skip
+ instead of throwing for ineligible chats.
+
+### Phase C — remote 4xx evidence
+
+Add route/method/client-version fields to `remote-request-failed` journal
+events, correlate with the paired mobile build, then fix the wrong side
+(route alias or client refresh backoff) with a router regression test.
+
+## Machine remediation (after ship)
+
+- Salman Guardian task heals via the A1 fallback after one attended send, or
+ by pinning a provider in the new editor.
+- Pre-activation chats heal immediately via B1; B2 protects every device.
+
+## Verification
+
+`npm run type-check`, `npm run lint`, focused suites (`test:scheduled`,
+`test:assistant-automations`, `test:compaction`, `test:google-provider`,
+`test:command-system`, `test:aiden-remote`), then the full `npm run test`
+chain. New test files must be registered in `package.json`.
diff --git a/docs/security/aiden-remote-threat-model.md b/docs/security/aiden-remote-threat-model.md
index 0c4db1338..819ddcd3a 100644
--- a/docs/security/aiden-remote-threat-model.md
+++ b/docs/security/aiden-remote-threat-model.md
@@ -133,7 +133,7 @@ Speech setup and use deliberately map to the existing `server:read`/`chat:write`
## 7. Privacy and logging
-Remote-access diagnostics are metadata-minimal. Permitted fields: closed route category, outcome or status class, bounded duration, and stable Aiden-owned error code; successful production traffic is aggregated by day. Forbidden fields: request IDs, instance/device suffixes, Authorization, pairing/idempotency secrets, opaque handles, QR contents, URLs, request/response bodies, managed or external paths, prompts/messages/reasoning, authoritative bot instructions, editable bot guidance, policy fingerprints, skill contents, attachments/avatar bytes or metadata, Image Playground prompts/rejected candidates/temporary URLs, tool details, provider/MCP failures, Git/shell/schedule output, Keychain/App Group data.
+Remote-access diagnostics are metadata-minimal. Permitted fields: closed route category, bounded HTTP request method, Aiden-owned route templates (content-free server constants such as `/chats/:id/turns` that never reflect a request URL, query string, credential, identifier, or caller-supplied path), outcome or status class, bounded duration, and stable Aiden-owned error code; successful production traffic is aggregated by day. Forbidden fields: request IDs, instance/device suffixes, Authorization, pairing/idempotency secrets, opaque handles, QR contents, URLs, request/response bodies, managed or external paths, prompts/messages/reasoning, authoritative bot instructions, editable bot guidance, policy fingerprints, skill contents, attachments/avatar bytes or metadata, Image Playground prompts/rejected candidates/temporary URLs, tool details, provider/MCP failures, Git/shell/schedule output, Keychain/App Group data.
Offline caches are scoped by Aiden instance ID and use platform data protection. They may retain safe Bot identity/inbox/access summaries and canonical-avatar cache entries, never managed paths, credentials, internal bindings, or Image Playground temporary results. Shared unsent composer drafts are additionally keyed by chat ID, remain in the app-private container (not App Group, widget, intents, or logs), clear after an accepted send, and purge on removal, revocation, or replacement pairing. Pending attachment references are not copied into draft persistence. Revocation makes other cached data read-only until the user explicitly removes the installation/cache. Lock Screen response excerpts are off by default.
diff --git a/docs/settings-design-system.md b/docs/settings-design-system.md
index ad2d11614..78af6074a 100644
--- a/docs/settings-design-system.md
+++ b/docs/settings-design-system.md
@@ -15,7 +15,7 @@ The `.settings-responsive` container defines `--settings-card-radius`, `--settin
Rows respond to their allocated content width, not the whole window. Below 540px complex controls stack under descriptions, while switches remain on the right. Grid groups must use `minmax(0, 1fr)` / `grid-cols-1` so long provider names or endpoints cannot force horizontal overflow. Controls and text must stay reachable without horizontal page scrolling.
-Model Pad measures the actual scrollport, wrapped toolbar, labels, and legend. Its square is constrained by both remaining height and column width. On very short or highly zoomed windows, it retains a usable 160px square and the Settings page scrolls; the Pad and its labels remain reachable. Ordinary window allocations show the full canvas and legend together. Opening model or benchmark panels uses the same measurement.
+Model Pad measures the actual scrollport and remaining column. Axis captions and the legend use a reserved height so the square outline stays put while surrounding copy, marker labels, and catalog text change. The square is constrained by remaining height, column width, and the visible scrollport. On very short or highly zoomed windows, it keeps a usable canvas (160px when the scrollport allows) and the Settings page scrolls; the Pad and its labels remain reachable. Ordinary window allocations show the full canvas and legend together. Opening model or benchmark panels uses the same measurement.
## Workspace labels
diff --git a/docs/testing/pi-compaction-phase7-rollout-gates.md b/docs/testing/pi-compaction-phase7-rollout-gates.md
index 2aedfe967..b7c9921ae 100644
--- a/docs/testing/pi-compaction-phase7-rollout-gates.md
+++ b/docs/testing/pi-compaction-phase7-rollout-gates.md
@@ -3,6 +3,10 @@
Status: automated evaluation and signed development-package acceptance pass;
installed production and credentialed-provider evidence remains **Pending** until
the release owner runs the steps below against the installed candidate.
+Generation is never blocked by the rollout gates at any stage:
+rollout-ineligible chats generate **journalless** over an in-memory session
+instead of failing (see "Journalless generation" below), so advancing the
+stage is a durability decision, not an availability one.
## Device-local evaluation receipt
@@ -46,7 +50,42 @@ Repeat only after observing the current stage and completing the next cohort's a
## Rollback
-Set `AIDEN_PI_UPGRADE_BEHAVIOR_ENABLED=0` before app startup and restart Aiden. This disables new v4 journal creation, legacy migration, automatic/manual Pi checkpoint generation, and durable-memory retrieval or writes. Existing v4 journals remain readable and are not downgraded or rewritten. Remove the override and restart to resume the persisted rollout stage.
+Set `AIDEN_PI_UPGRADE_BEHAVIOR_ENABLED=0` before app startup and restart Aiden. This disables new v4 journal creation, legacy migration, automatic/manual Pi checkpoint generation, and durable-memory retrieval or writes. Existing v4 journals remain readable and are not downgraded or rewritten. With the journalless safety net, chats that have no existing v4 journal continue to generate in the rollback environment — journalless over an in-memory session — rather than failing; durable compaction, memory, and history recall stay disabled for them until the override is removed and the persisted rollout stage resumes. Remove the override and restart to resume the persisted rollout stage.
+
+## Journalless generation (safety net)
+
+`PiCompactionSessionStore.openChatIfEligible()` probes eligibility and reports a
+structured reason instead of throwing; `openChat()` keeps its fail-closed
+contract for background callers. When the probe reports a reason, the
+generation runs over an in-memory session and **no durable journal is created
+and no legacy migration runs** — the fail-closed rollout contract is preserved
+verbatim.
+
+It engages exactly when a chat cannot yet hold a durable journal:
+
+- Stage `new_chats` (production default): chats created before the policy's
+ `activatedAt` (the first launch of the Pi-upgrade build on that device).
+- Any stage: chats whose legacy v3 journal is still deferred (its cohort has
+ not reached `migrated_low_risk_chats`, or it exceeds that stage's 500-entry
+ limit). The v3 bytes are never touched.
+- The rollback environment (`AIDEN_PI_UPGRADE_BEHAVIOR_ENABLED=0`): chats
+ without an existing v4 journal.
+
+Semantics of a journalless run: the request path is identical, visible turns
+persist through the chat store exactly as with journaled runs, but VCC history
+recall is omitted (nothing durable to recall), todo replay reads the empty
+in-memory journal (the todo panel reports the snapshot unavailable),
+automatic and manual Pi checkpoints stay cohort-disabled, effect-recovery
+boundaries are written only in-process and never acknowledged as durable, and
+the durable store can never be quarantined by an in-memory failure.
+
+Verify on a device (any pre-activation chat): send a message — generation
+succeeds; no new journal appears for that chat under the app's
+`pi-compaction-sessions` storage; its todo snapshot reports unavailable;
+requesting compaction resolves as already compact enough. Advancing the stage
+(below) restores durable journals — creation becomes unconditional at
+`migrated_low_risk_chats`, legacy v3 migration unlocks for journals of up to
+500 entries, and later stages follow the cohort ladder to `v4_only`.
## Provider-native re-audit
diff --git a/docs/ux/implementation-review.md b/docs/ux/implementation-review.md
new file mode 100644
index 000000000..660f9df9e
--- /dev/null
+++ b/docs/ux/implementation-review.md
@@ -0,0 +1,39 @@
+# Guided setup UX — implementation review
+
+Approved from [Now vs proposed](now-vs-proposed.html). The [journey chart](../plans/nontechnical-user-journey-ux-plan.md) records the broader backlog and the exact scope implemented here.
+
+## Quick review
+
+| Try this | Look for |
+| --- | --- |
+| First-run AI setup | ChatGPT, LM Studio, Ollama, Other Custom Provider; Other ways below. Custom setup cannot complete without an available default model. |
+| Settings → Aiden On The Go | Connect your phone / Scan to finish. Choose a method, acknowledge once, scan the code. |
+| Cancel the phone acknowledgement | Access stays off. No route changes. |
+| Interrupt or fail phone preparation | New access is rolled back when the result is known. Existing access and unrelated routes are preserved. Uncertain changes require explicit verification. |
+| Create a bot | Name and instructions → model and access. Optional appearance and detailed capabilities. Fresh desktop drafts start with no custom tool grants. |
+| Telegram | Token → model/access → connect and pair. Enable and connect happen together after an unattended-access acknowledgement. |
+| Voice | Choose where audio goes. Errors stay beside the draft with Open voice settings. |
+| Computer Use | Read the screenshot/provider explanation before enable; then handle Mac permissions. |
+| Scheduled task | Review the task and its access before creation. Failed saves keep the draft. |
+| Connect a plugin | Connect checks the endpoint’s tool availability. Errors stay in the dialog. |
+| Search Settings | Try “connect my phone”, “use my voice”, “connect my ai”, or “see my screen”. |
+| Native pairing | Updated Mac instructions, scanning first, manual entry available, raw payload import under Advanced. |
+
+Two desktop actions means **Connect a device → Enable and show code after choosing the method**. External Tailscale installation/sign-in/HTTPS authorization, scanning, and OS permission prompts are additional steps.
+
+## Evidence
+
+- Desktop TypeScript and E2E TypeScript checks pass.
+- Focused remote, onboarding, bot, Telegram, voice, scheduling, composer, plugin, and permission checks pass. Remote tests cover successful LAN/Tailscale setup, stale reviews, owner cancellation, concurrent attempts, rollback, preservation of enabled access, saved-route protection, and pending-outcome reconciliation.
+- Electron walkthroughs cover the four provider choices, custom-provider validation, LM Studio discovery and relaunch, computer-control acknowledgement cancellation, guided LAN pairing cancellation/success, listener survival after closing the window, and all Settings destinations.
+- The Bot editor Electron test uses a test-owned IPC catalog and captures its submitted Custom access. It deliberately fails saving to verify draft retention. It does not prove native Bot Keychain storage; the isolated profile cannot establish that authority. The separate Bot storage/permission suites pass.
+- Android `:app:testDebugUnitTest` passes, including compiling the updated pairing UI. It uses the installed Android Studio JBR and local Android SDK.
+- React Doctor reports no errors; its warnings concern existing large component/state patterns and draft resets when opening dialogs. ESLint passes for changed TypeScript files.
+- Vite and Electron bundles build. The unchanged desktop C helpers compile with the installed Command Line Tools and the existing build flags. The normal `npm run build` wrapper is blocked because its sanitized child environment selects an Xcode installation with an unaccepted license.
+
+## Before release
+
+- Resolve the Xcode license and run the focused iOS native integration/pairing tests on the allowed physical device. No simulator was used.
+- Complete a physical phone scan, actual Tailscale route setup/recovery, and device revocation walkthrough. Tests use local fixtures, not external accounts or a live tailnet.
+- Verify native Bot Keychain storage in a suitable signed/test environment. No authority fallback was added to production.
+- Conduct the nontechnical-user usability checks from the plan. The action reductions are implemented interaction counts, not measured user outcomes. Broader first-task suggestions and exhaustive 39-journey redesign remain tracked in the audit.
diff --git a/docs/ux/now-vs-proposed.html b/docs/ux/now-vs-proposed.html
new file mode 100644
index 000000000..52a9b94ba
--- /dev/null
+++ b/docs/ux/now-vs-proposed.html
@@ -0,0 +1,223 @@
+
+
+
+
+
+Aiden · Now & proposed
+
+
+
+
+