happy-stacks 0.6.12 → 0.6.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/docs/commit-audits/happy/_tools/generate-plans.mjs +453 -0
  2. package/docs/commit-audits/happy/_tools/generate-pr-assignment.mjs +430 -0
  3. package/docs/commit-audits/happy/_tools/init-pr-assignment-working.mjs +107 -0
  4. package/docs/commit-audits/happy/leeroy-wip.commit-analysis.md +1849 -0
  5. package/docs/commit-audits/happy/leeroy-wip.commit-export.fuller-stat.md +747 -1
  6. package/docs/commit-audits/happy/leeroy-wip.commit-index.json +11740 -0
  7. package/docs/commit-audits/happy/leeroy-wip.commit-index.tsv +252 -0
  8. package/docs/commit-audits/happy/leeroy-wip.commit-inventory.md +18 -11
  9. package/docs/commit-audits/happy/leeroy-wip.commit-manual-review.md +1236 -92
  10. package/docs/commit-audits/happy/leeroy-wip.maintainers-overview.draft.md +448 -0
  11. package/docs/commit-audits/happy/leeroy-wip.pr-assignment.draft.tsv +252 -0
  12. package/docs/commit-audits/happy/leeroy-wip.pr-assignment.working.tsv +288 -0
  13. package/docs/commit-audits/happy/leeroy-wip.pr-catalog.draft.md +245 -0
  14. package/docs/commit-audits/happy/leeroy-wip.pr-stack-plan.draft.md +350 -0
  15. package/docs/commit-audits/happy/leeroy-wip.rewrite-deferred-fragments.tsv +65 -0
  16. package/docs/commit-audits/happy/leeroy-wip.rewrite-ledger.tsv +56 -0
  17. package/docs/commit-audits/happy/leeroy-wip.rewrite-process.md +240 -0
  18. package/docs/commit-audits/happy/leeroy-wip.rewrite-status.tsv +39 -0
  19. package/docs/commit-audits/happy/leeroy-wip.split-plan.draft.md +93 -0
  20. package/docs/commit-audits/happy/leeroy-wip.topic-buckets.md +76 -0
  21. package/docs/commit-audits/happy/pr-desc.extraction-ledger.tsv +279 -0
  22. package/docs/commit-audits/happy/pr-desc.original.md +0 -0
  23. package/docs/commit-audits/happy/pr-desc.post-audit-extraction-ledger.tsv +54 -0
  24. package/docs/commit-audits/happy/pr-desc.working-document.md +536 -0
  25. package/docs/happy-development.md +18 -1
  26. package/docs/isolated-linux-vm.md +23 -1
  27. package/docs/stacks.md +21 -1
  28. package/package.json +1 -1
  29. package/scripts/auth.mjs +46 -8
  30. package/scripts/daemon.mjs +44 -21
  31. package/scripts/doctor.mjs +2 -2
  32. package/scripts/doctor_cmd.test.mjs +67 -0
  33. package/scripts/happy.mjs +18 -5
  34. package/scripts/provision/linux-ubuntu-review-pr.sh +5 -1
  35. package/scripts/provision/macos-lima-happy-vm.sh +34 -2
  36. package/scripts/review.mjs +347 -124
  37. package/scripts/review_pr.mjs +78 -2
  38. package/scripts/run.mjs +2 -1
  39. package/scripts/stack.mjs +265 -19
  40. package/scripts/stack_daemon_cmd.test.mjs +196 -0
  41. package/scripts/stack_happy_cmd.test.mjs +103 -0
  42. package/scripts/utils/cli/prereqs.mjs +12 -1
  43. package/scripts/utils/dev/daemon.mjs +3 -1
  44. package/scripts/utils/proc/pm.mjs +1 -1
  45. package/scripts/utils/review/detached_worktree.mjs +61 -0
  46. package/scripts/utils/review/detached_worktree.test.mjs +62 -0
  47. package/scripts/utils/review/findings.mjs +133 -20
  48. package/scripts/utils/review/findings.test.mjs +88 -1
  49. package/scripts/utils/review/runners/augment.mjs +71 -0
  50. package/scripts/utils/review/runners/augment.test.mjs +42 -0
  51. package/scripts/utils/review/runners/coderabbit.mjs +54 -10
  52. package/scripts/utils/review/runners/coderabbit.test.mjs +15 -48
  53. package/scripts/utils/review/sliced_runner.mjs +39 -0
  54. package/scripts/utils/review/sliced_runner.test.mjs +47 -0
  55. package/scripts/utils/review/tool_home_seed.mjs +99 -0
  56. package/scripts/utils/review/tool_home_seed.test.mjs +113 -0
  57. package/scripts/utils/stack/cli_identities.mjs +29 -0
  58. package/scripts/utils/stack/startup.mjs +45 -7
  59. package/scripts/worktrees.mjs +8 -5
@@ -0,0 +1,536 @@
1
+
2
+ # Not Dead Yet Release
3
+
4
+ ## 🚀 Executive Summary
5
+
6
+ This release represents a fundamental architectural shift to support and improve **Local-First** deployments and **Robust Agentic Workflows**. We have introduced a SQLite-backed "Server Light" flavor (no Docker needed anymore to run Happy Server), a persistent Pending Message Queue, and a standardized Capabilities Protocol.
7
+
8
+ For Agents, we have unified the **ACP (Agent Control Protocol)** backend, adding runtimes for **Codex ACP**, **OpenCode ACP**, and **Auggie ACP** (experimental, experiment-gated), while hardening the **Claude** local/remote bridge. Security is significantly upgraded with a **Secrets Vault**, **PID-safe Daemon**, and **Permission Mode restoration** that follows session history across devices.
9
+
10
+ ## 🙏 Special Thanks
11
+
12
+ This PR additionally includes and ports work from:
13
+
14
+ * **@54m** — Session Sharing (UI + server): [slopus/happy#356](https://github.com/slopus/happy/pull/356), [slopus/happy-server#25](https://github.com/slopus/happy-server/pull/25)
15
+ * **@OrdinarySF** — Codex approvals + MCP tooling: [slopus/happy#299](https://github.com/slopus/happy/pull/299), [slopus/happy-cli#102](https://github.com/slopus/happy-cli/pull/102), [slopus/happy-cli#101](https://github.com/slopus/happy-cli/pull/101)
16
+ * **@fberlakovich** — Claude signal forwarding: [slopus/happy-cli#127](https://github.com/slopus/happy-cli/pull/127)
17
+ * **@jiogallardy** and **@cruzanstx** — Claude runner reliability: [slopus/happy-cli#139](https://github.com/slopus/happy-cli/pull/139), [slopus/happy-cli#120](https://github.com/slopus/happy-cli/pull/120)
18
+ * **@zkytech** — Codex `/clear` handling: [slopus/happy-cli#72](https://github.com/slopus/happy-cli/pull/72)
19
+
20
+ ## How to try it
21
+
22
+ ```
23
+ npx --yes happy-stacks@latest review-pr \
24
+ --happy=https://github.com/slopus/happy/pull/487 \
25
+ --no-mobile \
26
+ --keep-sandbox \
27
+ --verbose \
28
+ -- --bind=loopback
29
+ ```
30
+
31
+ ## WIP / not fully tested yet / not fully finished yet
32
+
33
+ This branch/PR is not finalized yet, but can still be used/reviewed/tested already. Other changes will be pushed as they are finalized.
34
+
35
+ - **ACP resume:** ACP providers resume features and capability detection have not been fully tested yet
36
+ - **Tool rendering:** full normalization and rendering improvements are still WIP
37
+ - **Message queue UI polishing:** some improvements and UI/UX are WIP
38
+ - **Installable deps UI display + checking:** experimental installable dependencies (codex-mcp fork & codex-acp) display & detection will be improved a bit in the new session screens
39
+ - **Sessions sharing UI:** some improvements and UI/UX are WIP
40
+ - **Multi-provider permissions session allowlist:** the Claude sessions' permissions allowlists have been improved and extended to all other providers, but not fully tested yet
41
+ - **Friends sharing:** not tested yet
42
+ - **Deep review:** in progress
43
+
44
+ ---
45
+
46
+ ## 🏗 Core Architecture
47
+
48
+ ### 1. Server Light (SQLite & Local Files)
49
+ We have introduced a "Light" server flavor designed for local-only use, removing the dependency on Docker (Postgres/Minio) for personal usage.
50
+ * **Dual Flavor Entrypoints:** The server now boots in either `'full'` (Postgres/S3) or `'light'` (SQLite/Local FS) mode.
51
+ * **SQLite Infrastructure:** Added dynamic Prisma client generation for SQLite (`schema:sync`), atomic write-ahead DB handling, and baseline migrations.
52
+ * **SQLite env correctness:** sqlite DB URLs are formed via proper `file:///...` URLs (URL-escaped), and light flavor validates `PORT` fallbacks and normalizes public paths across platforms.
53
+ * **Migration reliability:** light migration scripts validate `HAPPY_SERVER_LIGHT_DATA_DIR` (trim/require) and centralize the deploy plan args; light entrypoint does not exit after start.
54
+ * **Master secret race hardening:** light flavor master secret file creation is atomic (exclusive create + EEXIST read-back), preventing corruption when multiple processes start concurrently.
55
+ * **Local Files Backend:** In "Light" mode, public files (avatars, attachments) are served directly from `~/.happy/server-light/files` via a secured `/files/*` route.
56
+ * **Public file URL hardening:** strict path normalization rejects traversal/absolute/drive-letter/null bytes; URL generation encodes each path segment (`encodeURIComponent`) so `#`/`?` cannot be interpreted as fragment/query.
57
+ * **Schema sync + Prisma centralization:** a unified `schema:sync` generator produces the SQLite schema and enum exports (with `--check` drift tests), and server code centralizes Prisma init/types with a fail-fast `db` proxy.
58
+ * **Integrated UI Serving:** The server can optionally serve the frontend static bundle (handling SPA routing fallbacks), enabling single-process deployments.
59
+
60
+ ### 2. Pending MessageQueue V1 (Metadata-Backed)
61
+ We replaced the ephemeral socket-based pending queue with a persistent, encrypted queue stored in session metadata.
62
+ * **Source of Truth:** The pending queue is stored in `session.metadata.messageQueueV1`. This ensures queue state survives server restarts and synchronizes perfectly across devices.
63
+ * **CAS Updates:** Enqueue/dequeue operations use `update-metadata` with version checking (Compare-And-Swap) to prevent race conditions.
64
+ * **Submit Modes:** message sending is driven by `settings.sessionMessageSendMode` (`agent_queue|interrupt|server_pending`). The default `agent_queue` mode chooses `server_pending` automatically when queue support exists and the agent is busy/offline/not-ready or controlled by the terminal (so we never “lose” input that cannot be injected safely).
65
+ * **Transcript Recovery:** The CLI observes the server-echoed message (by stable `localId`) before clearing `messageQueueV1.inFlight`, preventing loss if the CLI crashes between emit and server persistence.
66
+ * **Discard tracking:** queued items can be discarded into `messageQueueV1Discarded`, and committed transcript messages can be marked discarded via `discardedCommittedMessageLocalIds` (UI dims and labels discarded bubbles).
67
+ * **Fail-closed parsing:** invalid persisted queue shapes (e.g. malformed `inFlight`) are rejected so corrupted state doesn’t partially apply.
68
+ * **Optimistic “thinking” UX:** the app sets a short-lived `optimisticThinkingAt` marker when sending/enqueueing so sessions reflect activity immediately, then clears it once the server reports `thinking: true`.
69
+ * **Pending UI:** the “Pending messages” indicator/modal is a derived view of `messageQueueV1` (queue + inFlight + discarded). Actions like “send now”, discard, and delete are performed via metadata updates, with fail-closed ordering so send failures never delete items.
70
+
71
+ ### 3. Capabilities Protocol
72
+ Machine introspection has been standardized into a flexible **Capabilities Protocol**, replacing ad-hoc RPCs. This allows to easily detect what is currently installed on the user's computer and surface clear options
73
+ * **Checklist-based Discovery:** The UI requests capabilities via `capabilities.detect` (e.g., checking for "new-session" requirements or "resume" support).
74
+ * **Protocol surface:** `capabilities.describe` / `capabilities.detect` / `capabilities.invoke` support checklist-driven discovery (e.g. `new-session`, `machine-details`, `resume.codex`) and user-initiated install/upgrade operations.
75
+ * **Unified Snapshot:** The daemon returns a comprehensive snapshot of installed tools (Claude, Codex, Gemini, Tmux, OpenCode) and their versions/status.
76
+ * **ACP probing:** capabilities detection covers ACP backends (including Codex ACP dependency checks) so the UI can gate “new session” and “resume” flows on actual machine support.
77
+ * **Dependency Management:** The protocol supports checking and installing helper binaries (like the `codex-mcp-resume` bridge) into a managed prefix (e.g. `~/.happy/tools/codex-mcp-resume`).
78
+ * The app maintains an installable-deps registry used by Machine/New Session screens (e.g. Codex MCP resume + Codex ACP).
79
+ * **Machine-level UX:** machine screens/pickers can surface detected CLI status (with caching + stale-while-revalidate refresh and safe timeouts) so users can quickly diagnose “tool missing / not logged in / daemon too old” states.
80
+ * **Hook timestamp stability:** `useCLIDetection` now produces a stable timestamp even when loaded snapshots lack `checkedAt`, avoiding UI flapping; covered by fake-timer tests.
81
+ * **Cache reliability:** capabilities caches transition to `error` on detection throws (avoids “stuck loading” states while preserving any previous snapshot).
82
+ * **Cache race hardening:** capabilities cache updates are guarded by in-flight tokens so late/stale requests cannot overwrite newer loaded results; covered by a dedicated race regression test.
83
+ * **Probe robustness + UX polish:** ACP probes fail closed with normalized error shapes and hardened termination semantics; installable deps UI strings/dropdowns are localized and update badges use semver comparison; Gemini config loading is ESM-safe.
84
+ * **Diagnostics details:** `detect-cli` is daemon-side (PATH scan, no login shell) and can include best-effort `version` and optional `isLoggedIn` probes (plus `tmux`), guarded by timeouts so it never blocks core flows.
85
+ * Version parsing is tolerant (scans combined stdout+stderr, not just the first line) to reduce false “unknown version” states.
86
+ * **Probe tuning:** tuned `tmux` version probe timeouts (e.g. 1.5s) to reduce false negatives on slow hosts.
87
+ * **Shared protocol contracts:** `@happy/protocol` defines shared daemon↔app contracts (RPC result shapes/error codes, checklist helpers, socket RPC event typing) so the CLI/daemon and Expo app stay in sync without copy/paste drift.
88
+
89
+ ---
90
+
91
+ ## 🤖 Agents & Runtimes
92
+
93
+ ### ACP providers (OpenCode + Auggie)
94
+ * **OpenCode ACP:** a first-class ACP-backed agent runtime with consistent tool rendering/lifecycle semantics (see ACP runtime notes below). Vendor resume support is not available yet (see Known Issues).
95
+ * **Auggie ACP (experimental):** an ACP-backed agent runtime that is experiment-gated in the app, with per-session spawn options (e.g. an indexing toggle) surfaced through the UI and persisted in session state.
96
+
97
+ ### Agent catalog (Expo + CLI)
98
+ * **Shared agent ids + manifest:** `@happy/agents` provides canonical `AgentId` and shared agent metadata used across the Expo app and CLI (resume gating, connect targets, and stable identifier mapping).
99
+ * **Expo catalog facade:** the app uses a single catalog entrypoint (`expo-app/sources/agents/catalog.ts`) backed by per-agent providers (`expo-app/sources/agents/providers/*`) so agent UI behavior/copy/capability wiring is centralized and testable.
100
+ * **CLI backend catalog:** agent-specific logic lives under `cli/src/backends/<agentId>/**` and is composed via `cli/src/backends/catalog.ts` to drive CLI subcommands, detection snapshots, capability/checklist contributions, daemon spawn hooks, and ACP backend factories.
101
+ * **Extensibility:** adding a new agent is primarily “add catalog/provider/backend entries”, rather than editing many unrelated screens/commands/rpc handlers; this reduces wiring churn and makes integrations easier to review.
102
+
103
+ ### ACP runtimes (Codex + OpenCode + Auggie)
104
+ ACP runtimes support multiple ACP-backed agents with consistent UI semantics.
105
+ * **New runtimes:** full runtime support for **Codex ACP**, **OpenCode ACP**, and **Auggie ACP**, including transport wiring and session id management.
106
+ * **Tool Normalization:** Implemented a normalization layer that standardizes tool events (calls/results) across different backends, ensuring consistent rendering in the UI.
107
+ * **Replay Support:** Added infrastructure to capture and import ACP session history for debugging and regression testing.
108
+ * Includes replay capture/import helpers and `loadSession` support on the CLI side, plus slash-command publishing for ACP backends.
109
+ * **Slash commands:** when ACP backends report available commands, they are published into session metadata so the UI can surface slash-command affordances consistently across agents.
110
+ * **Task lifecycle edges:** CLI runtimes emit durable ACP lifecycle events (`task_started`, `task_complete`, `turn_aborted`) with stable task ids so the UI can render agent “thinking/task” boundaries consistently across backends.
111
+ * CLI agent entrypoint aligns subcommands/startup flags across backends (OpenCode wiring, Codex/Gemini argument alignment, and `--permission-mode-updated-at` parsing), and supports `--existing-session` and vendor `--resume` where applicable.
112
+ * ACP stdio is hardened: stdin write failures propagate (not silently swallowed) and stdin drain is guarded to avoid hangs (including “synchronous drain” edge cases in Node stream adapters).
113
+
114
+ ### Claude Reliability & Switching
115
+ Significant hardening of the Claude local/remote runner.
116
+ * **Hook-Mode Continuity:** The runner now preserves the `transcript_path` reported by hook scripts. This allows switching between Remote and Local modes without losing session context.
117
+ * Tests cover the `transcriptPath` surface to prevent regressions.
118
+ * **Switch preflight:** switching waits briefly for hook session/transcript info (with a visible status message) to avoid switching with missing sessionId/transcriptPath.
119
+ * **Fork safety on resume:** when starting local from an existing session, the runner clears stale session info until the new hook data arrives; if spawn fails before the forked session is reported, it restores the previous sessionId/transcriptPath so remote mode can still resume it.
120
+ * **Transcript availability UX:** when attaching to a fresh local session before its transcript file exists, the CLI emits a clear session status message and the scanner begins streaming automatically once the transcript appears (avoids “blank” remote sessions).
121
+ * **Resume validation robustness:** remote resume attempts continue even if transcript validation has not passed yet, avoiding false-negative context loss during fast switching/initialization.
122
+ * **Signal Forwarding:** The CLI now correctly forwards OS signals (`SIGINT`, `SIGTERM`, `SIGHUP`) to the underlying Claude binary, preventing orphaned processes.
123
+ * Forwarding is hardened to avoid orphan lifecycle events and to re-raise forwarded signals where appropriate (reduces “stuck running” and exit-code confusion).
124
+ * _Credit:_ Thanks to @fberlakovich — commits ported into the monorepo from [slopus/happy-cli#127](https://github.com/slopus/happy-cli/pull/127).
125
+ * **Switching Idempotency:** The `switch` RPC is idempotent and does not thrash mode state under repeated calls.
126
+ * **Remote→local switch safety:** when switching to local mode while messages are queued/pending, the terminal prompts with a preview and requires explicit confirmation.
127
+ * If confirmed, queued/pending items are discarded in session metadata (so they can be recovered/reviewed later from the app’s discarded/pending UI) and the switch proceeds.
128
+ * If declined, the switch is canceled and remote mode continues (no surprising “silent” state changes).
129
+ * **Remote↔local switching reliability (non-tmux):** hardened the Claude remote-mode Ink UI and teardown to prevent terminal corruption/buffered-input leaks (deterministic key handling incl. `Ctrl+T`, raw-mode reset + brief stdin drain after Ink unmount, and non-async input handlers with cancellable timeouts).
130
+ * **Scanner + CLI flag correctness:** session scanning tolerates consumer callback exceptions; Claude local-runner treats `-c` as `--continue` for session control detection; and remote runner handles `--resume/-r` with or without an id (without id resumes the most recent valid UUID session for the project).
131
+ * **Config dir robustness:** `CLAUDE_CONFIG_DIR` overrides are trimmed so accidental whitespace doesn’t create wrong paths.
132
+ * **Local runner robustness:** orders `claudeArgs` last for slash-command correctness, forwards OS signals to spawned local children, and treats abort errors as expected (reduces spurious “process error” noise).
133
+ * _Credit:_ Thanks to @jiogallardy and @cruzanstx — commits ported into the monorepo from [slopus/happy-cli#139](https://github.com/slopus/happy-cli/pull/139) and [slopus/happy-cli#120](https://github.com/slopus/happy-cli/pull/120).
134
+ * **AskUserQuestion / ExitPlanMode tools:** the app completes these Claude tool interactions via the existing session `permission` RPC.
135
+ * AskUserQuestion attaches structured `answers` keyed by the question text when supported; otherwise it falls back to denying the tool call and sending a normal user message with the same content so older agents can proceed.
136
+ * ExitPlanMode uses allow/deny without injecting extra chat messages, and denial can include a free-text “request changes” reason that Claude can use to revise the plan in-place. Tool UIs require a `permission.id`, fail-closed when missing, and show localized errors on submit failures.
137
+
138
+ ### Codex Approvals & MCP Interaction
139
+ * **ExecPolicy Amendments:** Added native UI support for Codex's "Always allow this command" flow. The approval decision is passed via the permission system with the specific command amendment payload.
140
+ * _Credit:_ Thanks to @OrdinarySF — commits ported into the monorepo from [slopus/happy#299](https://github.com/slopus/happy/pull/299) and [slopus/happy-cli#102](https://github.com/slopus/happy-cli/pull/102).
141
+ * **Tool ID Alignment:** Permission requests and cached amendments are now strictly keyed by the **MCP Tool Call ID** to prevent mismatches.
142
+ * **MCP result correctness:** Codex MCP tool results preserve falsy `{ Ok: ... }` / `{ Err: ... }` outputs (no lossy `||` fallthrough), with unit tests.
143
+ * Tool correlation prefers stable `call_id` where available, reducing “wrong tool result attached” edge cases.
144
+ * **MCP tool calls surfaced:** Codex `mcp_tool_call_begin` / `mcp_tool_call_end` events are surfaced into the transcript as tool calls/results (prefixed `mcp__...`) for consistent UI rendering.
145
+ * **MCP bridge reliability:** the Happy MCP bridge is launched via `process.execPath` (node/bun) to avoid relying on `.mjs` executable bits across runtimes.
146
+ * _Credit:_ Thanks to @OrdinarySF — commits ported into the monorepo from [slopus/happy-cli#101](https://github.com/slopus/happy-cli/pull/101).
147
+ * **MCP transport safety:** Codex MCP server detection is more tolerant of version output (`codex` vs `codex-cli`, optional `v` prefix) and avoids printing full elicitation payloads to stdout (debug-only, redacted logging instead).
148
+ * **Tool tracing (debugging):** CLI can emit JSONL tool traces and includes a fixture extractor script for building stable tool/permission fixtures from traces.
149
+ * Tracing includes permission request/response events and is broadened for more tool surfaces (while keeping metadata wakeup safety).
150
+
151
+ ---
152
+
153
+ ## 🛡️ Permissions & Safety
154
+
155
+ ### Persistent Permission State
156
+ * **Message-Derived Restoration:** Permission modes (e.g., "Read-Only", "Safe-Yolo") are now inferred from the **last user message** in the transcript. This ensures that permission state follows the session history accurately across devices, even if local state is lost.
157
+ * **Arbitration:** Permission changes are arbitrated using server-aligned timestamps to prevent race conditions when multiple devices update the mode simultaneously.
158
+ * **Default Permissions:** Users can now define default permission modes per Agent Type (e.g., default to "Read-Only" for Codex but "Plan" for Claude) in their profile settings.
159
+ * **Cross-agent normalization:** permission modes are normalized/clamped per agent and mapped across flavors (Claude ↔ Codex/Gemini) so switching agent types preserves intent instead of silently falling back to incompatible modes.
160
+ * **Carry mode across remote↔local:** sessions track `lastPermissionMode`, and local spawns/threading update CLI args so switching local/remote does not drop the active policy.
161
+ * **Permission mode options helper:** centralized per-agent mode lists/labels/icons and normalization to prevent UI drift between agents (descriptions are still hardcoded English where used).
162
+ * **Mode cycling correctness:** keyboard/UI cycling is clamped to the active agent’s valid modes so users can’t get “stuck” on an invalid mode.
163
+ * **Per-session allowlists (Codex/Gemini):** CLI persists “always allow” tool approvals per session using a stable tool identifier and a hardened shell command allowlist, with focused unit tests.
164
+ * **Metadata-published mode:** the CLI publishes `permissionMode` (+ `permissionModeUpdatedAt`) into session metadata at session creation and on changes (Claude/Codex/Gemini), so the UI can seed state even before the first app-originated message meta exists.
165
+ * **No-op stability:** permission mode updates do **not** bump `permissionModeUpdatedAt` unless the effective mode actually changed (prevents “latest wins” churn overriding real user selections).
166
+
167
+ ### Secrets Vault
168
+ * **Encrypted Storage:** credentials and sensitive env vars are sealed in `SecretString` containers before persistence. Plaintext values are never stored in settings.
169
+ * **Requirement Resolution:** A new `SecretRequirementModal` resolves missing secrets at spawn time, allowing users to provide "session-only" keys in memory ("Enter Once") or select from the vault.
170
+ * Secret requirement UX is modularized and can be used via a dedicated picker route in the New Session flow.
171
+ * **UI Privacy:** Env var cards enforce masking (`***`) for vault-backed values.
172
+ * **Inline add UX:** saved secrets (and env vars) can be added inline via an expander with Cancel/Save actions (reduces modal churn; covered by tests).
173
+ * **Saved Secrets + bindings:** secrets are stored as **Saved Secrets** and can be bound per profile/env var (profile → env var → secret id). Drafts never persist plaintext; session-only values are encrypted before draft persistence.
174
+ * **Tolerant parsing:** one malformed saved secret no longer wipes other valid secrets (invalid entries are dropped individually; regression test included).
175
+
176
+ ### Daemon Process Safety
177
+ * **Strict Reattach:** The daemon persists "session markers" to disk. On restart, it only re-adopts processes if the **PID and Command Hash** match exactly.
178
+ * **Safe Kills:** The daemon verifies process identity before sending SIGTERM, preventing accidental killing of reused PIDs.
179
+ * **Cross-stack safety:** marker adoption and webhook updates are gated by `HAPPY_HOME_DIR` so a daemon never reattaches or kills sessions from another stack.
180
+
181
+ ---
182
+
183
+ ## 🖥️ Terminal & Session Management
184
+
185
+ ### Inactive Session Resume
186
+ Users can now reconnect to stopped or crashed sessions.
187
+ * **Resume Flow:** The UI offers a "Resume" action for inactive sessions.
188
+ * **Codex Resume:** Implemented via a `codex-mcp-resume` bridge that re-hydrates session context using MCP.
189
+ * **Experimental gating (Codex):** Codex resume is disabled by default and requires explicit enablement (UI experiment + per-spawn flag), plus daemon-side gating (fail-closed) so we never “silently” resume Codex without user intent.
190
+ * **Resume server install/status (Codex):** machines can report/install the Codex resume MCP server into a Happy-owned prefix (with logged installs + version/status reporting, Windows-aware binary checks).
191
+ * The install spec is explicit/user-provided (default is empty) so we don’t ship fork-specific defaults as global behavior.
192
+ * Codex resume install/update/reinstall modals are localized in both Machine and New Session screens and share consistent success/error framing (including `deps.*` status strings).
193
+ * **Local session persistence:** the machine persists a per-session file under `HAPPY_HOME_DIR/sessions/<happySessionId>.json` (metadata, agentState, versions) to make reattach/resume possible.
194
+ * **Resume plumbing (Happy session resume):** the UI calls a `resume-session` RPC and securely provides the **session encryption key** so the daemon can reconnect to the existing Happy session (`--existing-session <happySessionId>`). This path is intentionally UI-only (a CLI user cannot resume an existing Happy session without the key).
195
+ * **Safer resume flow:** resume avoids passing message payloads via spawn env; instead the UI enqueues the user message first (pending/metadata queue), then requests a spawn-only resume so the agent drains staged messages normally.
196
+ * **Vendor resume (CLI-supported):** the CLI supports resuming *vendor* sessions inside **new Happy sessions** via `--resume <vendorSessionId>` where supported (Claude baseline; Codex is experimental and gated; OpenCode currently falls back because its ACP backend lacks `loadSession`).
197
+ * **New-session resume:** New Session supports selecting a resume id (capability-gated), persists it in the New Session draft, and includes it in the spawn payload when supported.
198
+ * **Resume request shape hardening:** UI resume no longer requires passing an `agentSessionId`; resume is keyed by Happy session id + agent type so vendor-id derivation happens on the machine/daemon side.
199
+ * **Capability-gated resume UX:** resume affordances are gated by machine capabilities/agent registry (per agent type) and the session UI surfaces clearer inactive/offline/pending notices during resume workflows.
200
+ * Resume capability helpers use the agent registry and include vendor resume-id lookup helpers; temp session data is typed to `AgentId` to reduce agent-type mismatches.
201
+ * **Offline resume safety:** offline/continue tooling uses a safer `offlineSessionStub` (EventEmitter-based, aligned to the real client surface) to avoid “missing method/event” crashes.
202
+
203
+ ### Tmux & Headless Support
204
+ * **Headless Mode:** Support for spawning "headless" sessions via `happy-cli --tmux`.
205
+ * **Attach Tooling:** New `happy attach` command handles identifying and attaching to running tmux sessions.
206
+ * **Security:** Fixed path traversal vulnerabilities in terminal attachment metadata filenames (`encodeURIComponent` for session filenames) and blocks unsafe legacy fallback reads when `sessionId` contains path separators.
207
+ * **Attach metadata:** CLI records per-session terminal metadata (requested mode, fallback reason, tmux target/tmpDir) and persists local attach info atomically once a session ID exists (Codex/Gemini/Claude parity).
208
+ * **TMUX correctness:** targeting/parsing is hardened (prefers `TMUX_PANE`, rejects invalid target injection, correct kill-window targeting) with focused tests.
209
+ * **TMUX instance isolation:** supports per-instance socket paths (`-S <socket>`) and passes `TMUX_TMPDIR` via the tmux command environment (not conflated with socket path), with deterministic session selection and opt-in integration tests.
210
+ * **Tmux reliability:** tmux spawn/attach is hardened (including retrying `new-window` on index conflicts) and avoids attach/spawn edge cases that could desync terminal state.
211
+ * **Daemon tmux spawn:** daemon accepts terminal spawn options, supports tmux spawn + isolated servers, strips legacy `TMUX_*` env from agent env, and passes internal runtime flags to surface fallback reasons when tmux is unavailable.
212
+ * **Headless argv validation:** headless tmux argv validation fails closed on missing/invalid `--happy-starting-mode` values.
213
+
214
+ ### General Improvements
215
+ * **Remote-Only Agents display in terminal:** we have made it clearer in the CLI when starting remote-only agents (Codex, OpenCode, Gemini), so that users are not confused anymore as to why they cannot send messages using the terminal to those agents.
216
+ * **`happy connect` clarifications:** we also made it clearer which providers currently supports `happy connect` and which ones are not wired into Happy yet (only connection work, but then it's not effectively used anywhere yet), to reduce confusion with `happy connect claude` and `happy connect codex` not changing the authentication of the CLI yet.
217
+
218
+ ---
219
+
220
+ ## 🤝 Session Sharing (Friends + Public Links)
221
+
222
+ Happy sessions can be shared securely with other users, either directly (friends-only) or via a public view-only link.
223
+
224
+ * **Direct sharing (friends-only):** a session owner/admin can share a session with friends and assign an access level (`view`, `edit`, `admin`). Shared sessions appear in the session list with clear indicators.
225
+ * Sharing management is restricted to the session owner/admin (non-admin recipients cannot manage shares).
226
+ * The session view enforces access levels (e.g. view-only disables sending/agent input).
227
+ * **Public share links (view-only):** a session owner can create a public link with optional expiry and max-uses limits.
228
+ * Public share access is always view-only for safety.
229
+ * Links can require explicit consent before access when detailed access logging is enabled.
230
+ * **Key handling + privacy:** the session data encryption key is wrapped for sharing:
231
+ * For direct sharing, the client encrypts the session DEK for the recipient using their published content public key (verified against the recipient’s signing key binding).
232
+ * For public links, the client generates a token and encrypts the session DEK using that token; the server stores only a hash of the token (not the token itself).
233
+ * **Realtime updates:** share changes (direct shares and public links) emit realtime events so owners/recipients see updates promptly without a full refresh.
234
+ * **Feature gating:** the server exposes `/v1/features` so the app can detect whether session sharing/public sharing/content keys are supported and adjust UI accordingly.
235
+ * **Credit:** Thanks to @54m [slopus/happy#356](https://github.com/slopus/happy/pull/356) (UI) and [slopus/happy-server#25](https://github.com/slopus/happy-server/pull/25) (server) — this PR ports those changes into the monorepo and applies additional fixes/hardening.
236
+
237
+ ## 💅 UI & UX Improvements
238
+
239
+ ### New Session Wizard
240
+ * **Complete Rewrite:** The creation flow is now a route-based wizard (`NewSessionWizard`) with dedicated pickers for Machine, Path, and Profile.
241
+ * **Profile 2.0:** Migrated profiles to be purely environment-variable based (removing legacy provider configs).
242
+ * **Pre-flight Checks:** The wizard runs `preview-env` to ensure the selected machine meets the profile's requirements before spawning.
243
+ * **Picker/navigation stability:** picker screens avoid inline `Stack.Screen` options and pick flows were stabilized to reduce “stale selection / wrong route params” issues; wizard can pre-visualize the selected machine for faster verification.
244
+ * **Web + resume UX polish:** on web, the new-session wizard is presented in a `BaseModal` with an explicit header/close; Codex resume “not installed” dialogs are localized and route users to the Machine screen to install/inspect the resume server.
245
+ * **Wizard polish:** Codex resume banner strings in the wizard are localized and wizard sections use shared header-row primitives for consistency.
246
+ * **Draft persistence + pick flows:** wizard state is persisted before navigating to picker/edit screens, so leaving the wizard doesn’t reset inputs; selections are returned via route params (not global callback plumbing).
247
+ * **Resume pick reliability:** resume session id selection is persisted in new-session drafts and paste-from-clipboard is hardened (safe fallback when clipboard reads fail).
248
+ * **iOS navigation reliability:** picker and profile-edit screens are also presented as iOS `containedModal` (with explicit back buttons) so they never render “behind” the wizard modal.
249
+ * **Recent/favorites UX:** added recent machines/paths helpers and more deterministic favorites/search behavior in picker screens (with feature toggles for picker-search UX).
250
+ * **Agent compatibility correctness:** when the profile changes, the wizard clamps agent type to supported backends and maps permission modes across agents rather than resetting blindly.
251
+ * **Secrets + terminal integration:** the wizard resolves required secrets via the secrets/vault flow (machine env presence checks, saved-secret bindings, or “enter once”), and passes terminal/tmux spawn options into session creation (including tmux warnings when requested but not detected).
252
+ * **Performance hardening:** draft/settings writes are debounced and often deferred via `InteractionManager.runAfterInteractions` on native to keep iOS taps/animations responsive.
253
+
254
+ ### UI Primitives & Polish
255
+ * **Unified Overlay System:** Introduced `Popover` and `OverlayPortal` to handle floating UI consistently on Web (Radix-based) and Native.
256
+ * **Modal Fixes:** Fixed iOS touch-blocking on stacked modals and restored Expo Web modal behavior (enables `EXPO_UNSTABLE_WEB_MODAL=1`, pins/patches `expo-router`, and ensures patches apply in both hoisted and non-hoisted installs).
257
+ * Also pins `libsodium-wrappers` to a compatible version and aligns patch-package directories so the Expo-router patch is applied reliably.
258
+ * **List + row-action primitives:** added a shared `SearchHeader`, refactored `SearchableListSelector` grouping/search placement, and added inline row actions with an overflow menu modal (plus click-through guards).
259
+ * **List/pending polish:** added reusable item-group row-position/title primitives and refined list/pending UI for more consistent layout/behavior (with targeted divider/row tests).
260
+ * **Unsaved-changes prompts:** added a reusable “discard/save/keep editing” alert helper used by picker-friendly edit screens.
261
+ * **Popover + portal overlays:** added `OverlayPortalHost`/`OverlayPortalProvider` and a `Popover` primitive with web/native portal support, spotlight/backdrop options, and a `ModalPortalTargetProvider` for correct web focus/stacking inside modals.
262
+ * **Popover hardening:** improved web anchor measurement (DOM `getBoundingClientRect()` fallback + retries) and iOS portal pointerEvents to prevent invisible/click-through overlay failures.
263
+ * Web popover positioning accounts for scroll offsets and uses a dedicated portal target + more robust measurement to avoid “misplaced overlays” during scroll/resize.
264
+ * **Scroll edge indicators:** list edge indicators are shown without fades when appropriate (improves discoverability without relying on subtle animations).
265
+ * **WebAlertModal safety:** ensures an empty `buttons: []` config still renders a default `OK` button (prevents non-dismissible alert modals).
266
+ * **Overlay action reliability:** improved “close-then-act” behavior for row-action menus (`InteractionManager` with timeout fallback) so actions aren’t delayed indefinitely under continuous interactions.
267
+ * **i18n hygiene:** many previously hard-coded UI literals (including error alerts and permission/microphone prompts) are now translated via `t(...)` keys; tooling was added to help find remaining untranslated literals.
268
+ * **Specialized Tool Views:** Added optimized renderers for common tools (Bash, ReadFile, Grep) and structured ACP results.
269
+ * Tool views handle additional ACP shapes (e.g. diff items and “read” aliases) and can infer pending permissions from tool-call surfaces to keep the transcript state consistent.
270
+ * **Error Surfacing:** Agent errors (Codex/Gemini quota, MCP failures) are now surfaced as visible status messages in the transcript.
271
+ * Includes formatted “status” events forwarded from CLI runtimes so Codex/Gemini startup/stream/tool failures are actionable (not silent hangs).
272
+ * Includes follow-up polish for Codex MCP startup failures and Gemini quota reset formatting (regression-tested).
273
+ * **Input + editor polish:** prompt input adapts to keyboard height on native and env-var editor cards were refined for clearer editing ergonomics.
274
+
275
+ ---
276
+
277
+ ## 🛠️ Foundations & DevX
278
+
279
+ * **Test Harness:** Root scripts validate the full monorepo surface (expo-app + cli + server) via `happys test/typecheck`. Added **Vitest stubs** for Expo/React Native modules to enable fast Node-based unit testing of UI logic.
280
+ * **Test deps alignment:** updated `react-test-renderer` to stay aligned with the repo’s React version (prevents subtle test renderer mismatches).
281
+ * **Expo iOS build stability:** patched `@more-tech/react-native-libsodium` podspec evaluation so `pod install` doesn’t fail when `folly_version` is undefined (falls back to `RCT-Folly` when needed).
282
+ * **Expo install + web runtime stability:** deterministic `expo-app` postinstall that reliably runs `patch-package` even when hoisted; includes libsodium-wrappers patching plus a web adapter that forces the CJS build to avoid Metro parsing failures from ESM/top-level `await`.
283
+ * Also runs patching from both repo root and `expo-app/` so patches apply for hoisted deps *and* non-hoisted deps (e.g. `expo-router`).
284
+ * Postinstall includes verification that critical patches (e.g. `expo-router`) were actually applied, failing fast when patching silently didn’t happen.
285
+ * **App variant hardening:** added opt-in overrides (`EXPO_APP_NAME`, `EXPO_APP_BUNDLE_ID`, `EXPO_APP_SCHEME`) and safe fallbacks when `APP_ENV` is unknown (prevents undefined config values, reduces multi-install collisions).
286
+ * **Test determinism:** defines `__DEV__ = false` in Vitest so dev-gated code paths behave predictably under unit tests.
287
+ * **Unistyles Migration:** Migrated the entire codebase (`expo-app`) from `StyleSheet` to `react-native-unistyles` for consistent theming.
288
+ * Includes a guard test to enforce “no `StyleSheet` imports from `react-native`” and prevent regressions.
289
+ * **Repo commit conventions:** added Conventional Commits guidelines for tooling (Copilot commit instructions).
290
+ * **Workspace hygiene:** ignores `.project` artifacts and adds naming-conventions documentation used by tooling/agents.
291
+ * **i18n Sweep + tooling:** refactored i18n types to be derived from `translations/en.ts`, expanded locale dictionaries for new surfaces, and added scripts to compare translation coverage and scan for likely-untranslated literals (with follow-up parsing fixes for file kinds and `:` in literal grouping keys).
292
+ * Adds device locale helpers (shared + native) used by the text/runtime layer when selecting the best locale.
293
+ * **Production log hygiene:** gated noisy detection/realtime debug logs behind `__DEV__` (keeps errors as errors; avoids incidental message/metadata logging).
294
+ * **Log Redaction:** Hardened CLI logging to redact env vars and secrets from debug output.
295
+
296
+ ---
297
+
298
+ ## 📦 Appendix: Additional Details
299
+
300
+ Additional implementation details and edge-case hardening notes that didn’t fit cleanly in the high-level sections above.
301
+
302
+ ### Auth & Storage Scoping
303
+
304
+ * **Auth token persistence hardening (web):** `tokenStorage` no longer throws on malformed `localStorage` JSON; `setItem/removeItem` failures return `false` (quota/security errors handled).
305
+ * **CLI auth ergonomics:** `happy auth login --no-open` (and `HAPPY_NO_BROWSER_OPEN`) skips auto-opening a browser for login; unit-tested.
306
+ * **Scoped native storage:** storage keys (and selected MMKV ids) are scope-qualified via `EXPO_PUBLIC_HAPPY_STORAGE_SCOPE` to prevent cross-stack/worktree state bleed on device.
307
+ * **Unauthenticated route guard:** app layout redirects unauthenticated users off protected routes (public allowlist is explicit) to prevent flashes of protected screens.
308
+ * Includes a follow-up fix to avoid React hooks-order violations in the redirect path (regression-tested).
309
+ * **Auth failure surfacing:** raw message parsing tolerates `usage.service_tier: null` so messages/events aren’t dropped on schema failures (helps keep auth/401 failures visible).
310
+
311
+ ### Settings, Profiles, and Requirements
312
+
313
+ * **Settings parsing hardening:** tolerant per-field parsing so one invalid field doesn’t reset everything; invalid profiles are filtered individually instead of failing the whole settings object.
314
+ * **Profile shape migration:** legacy provider config objects are normalized into `environmentVariables` entries (e.g. `OPENAI_*`, `ANTHROPIC_*`, `AZURE_OPENAI_*`, `TOGETHER_*`); non-persistable fields (e.g. `startupBashScript`, `tmuxConfig.updateEnvironment`) are dropped from the persisted GUI profile model.
315
+ * **Settings sync convergence:** added “always write” `replaceSettings(settings, version)` to converge after server/account switching or server-side resets (used to prevent version mismatch retry loops).
316
+ * **Env var templates:** added parse/format support for `${VAR}`, `${VAR:-fallback}`, `${VAR:=fallback}` and bash-like empty-string fallback semantics.
317
+ * **Profiles:** profiles are now centered on env-var requirements/selection (with supporting UX + built-in profile gating fixes).
318
+ * **`preview-env` end-to-end:** UI prefers daemon-computed “effective spawn env” (supports `extraEnv` expansion + secrets policy `none|redacted|full` + per-key sensitivity metadata); falls back to *non-sensitive only* bash probing when unsupported (node-backed JSON protocol when available; robust unset sentinel parsing; avoids pulling secret-like values into UI memory). Daemon handler validates key names and caps requests; sensitive-key detection is heuristic with an overridable (safe-fallback) regex.
319
+ * `preview-env` accepts lowercase keys and explicitly blocks prototype-pollution keys (`__proto__` / `constructor` / `prototype`), using `Object.create(null)` to avoid inherited properties.
320
+ * **Model modes:** per-session model-mode persistence + UI allowlisting/clamping (invalid model modes cannot be written from the session UI; persisted maps are filtered to an allowlist).
321
+ * **Experiments + agent-input customization:** settings gained per-experiment toggles (preserving legacy “master experiments” behavior) and new agent-input layout/density controls.
322
+ * The master “experiments” toggle also controls Codex resume enablement (so disabling experiments disables `expCodexResume`).
323
+ * **Session settings consolidation:** message-send policy and tmux preferences are unified under session settings (`sessionMessageSendMode`, `sessionUseTmux`, etc.) with migrations/aliases for legacy keys and routes.
324
+ * Settings list items are localized (e.g. the Session settings row title/subtitle), and Spanish experiment subtitles are fully translated.
325
+ * **Credential requirements resolver:** profiles can declare required secret env vars / machine-login requirements; UI preflights readiness via `preview-env` and provides a resolver modal (use machine env, select a saved credential, or enter once for session-only use).
326
+
327
+ ### Sessions UX
328
+
329
+ * **Message list quality-of-life:** unread badges, inactive-session grouping, archive fallback behavior when kill RPCs aren’t available, and small transcript/message conveniences (e.g. copy-to-clipboard for message blocks).
330
+ * Unread state is cross-device: read markers are stored in encrypted session metadata (`readStateV1`) and updated on focus/blur with debounced writes.
331
+ * Path display is safer: avoids false “under home” matches when formatting paths relative to `homeDir`. Session list formatting consistently shows `~`-prefixed home-relative paths.
332
+ * **Session rename:** session info screen supports renaming by updating encrypted session metadata via `update-metadata` (version-checked), with a prompt-based UX.
333
+ * **Agent-visible errors:** improved surfacing of agent failures (Codex/Gemini quotas/MCP failures) as explicit transcript status, not silent failures.
334
+ * Session-level error fallbacks and profile-info modal copy are localized (avoids hard-coded English “Error / failed to …” messages).
335
+ * **Codex runtime correctness:** Codex ignores per-message model overrides; permission-mode changes restart Codex sessions with explicit context drop (no automatic resume attempt), and mode hashing ignores `model` to avoid spurious restarts.
336
+ * **Codex/Gemini readiness:** prime `agentStateVersion` immediately after session creation so UI readiness flips true without requiring an `update-state` event.
337
+
338
+ ### CLI / Sync / Daemon reliability
339
+
340
+ * **Daemon ownership gating:** reattach/restart safety based on persisted per-PID “session markers” under `HAPPY_HOME_DIR`, strict PID classification, and process-command-hash verification; avoids unsafe cross-process interactions and PID reuse hazards.
341
+ * Resume requests are idempotent (avoid duplicate processes), and the daemon maintains per-session attach files/metadata merges to support safe reattach and clearer session startup behavior.
342
+ * The daemon reports and persists session termination (including keeping sessions tracked until exit) so the app/CLI can present accurate session end state.
343
+ * **Atomic daemon state persistence:** daemon state reads are schema-validated (Zod) and retried on transient errors; writes are atomic (tmp + rename, with Windows fallbacks and tmp cleanup).
344
+ * Includes a retry path for `ENOENT` when the daemon state file appears shortly after startup (race hardening; regression-tested).
345
+ * **Refactor + opt-in integration tests (daemon):** extracted `pidSafety`/`reattach` helpers and added opt-in “real process” integration tests gated by `HAPPY_CLI_DAEMON_REATTACH_INTEGRATION=1` for validating PID hashing + marker adoption on the host OS.
346
+ * **CLI reconnection correctness:** waiter lifecycle cleanup, reconnection/backoff hardening, and metadata/socket coordination fixes.
347
+ * Includes a fix where `waitForMetadataUpdate()` resolves `false` on socket disconnect and always cleans up listeners (prevents hanging awaiters; tested).
348
+ * **Capabilities cache race hardening:** prevents late/stale overlapping prefetches from overwriting newer loaded snapshots (token-guarded updates; race regression test).
349
+ * **Runtime support (daemon subprocesses):** daemon-spawned subprocess invocation supports `node` or `bun` (selectable) with tested invocation building; missing entrypoints surface a clear error instead of failing silently.
350
+ * **Sync robustness:** transport parsing guards + disconnect/await safety for reliability in flaky connectivity scenarios (kept separate from MessageQueueV1 semantics).
351
+ * Includes a fix to ensure `invalidateAndAwait()` never hangs forever when the sync command throws (awaiters resolve; retries are bounded; tests included).
352
+ * Failures are counted consistently even under custom backoff implementations (`failuresCount` increments per attempt; tests de-flaked by stubbing jitter).
353
+ * Metadata waiters are hardened against lost wakeups and abort races, avoiding “hang forever” edge cases under concurrent message/pending events.
354
+ * **RPC compatibility signal:** server returns a structured `errorCode=RPC_METHOD_NOT_AVAILABLE` (while preserving legacy message strings) so the app can do reliable back-compat fallbacks without brittle string matching.
355
+ * **Sync perf + crash-safety:** debounced pending settings persistence with flush-on-background to avoid losing last-second toggles; added a de-duped `refreshMachinesThrottled` helper to prevent network churn.
356
+ * **Error parsing hardening:** guards JSON parsing for non-JSON error bodies (e.g. GitHub OAuth config 400 and disconnect 404s) and preserves correct `HappyError(kind/status)` typing.
357
+ * **Spawn safety boundaries:** GUI-spawned sessions do not inherit the CLI’s active profile implicitly; profile env injection is opt-in from the caller (prevents surprising env leakage).
358
+ * **Profile identity propagation:** `profileId` is threaded through daemon spawn into session metadata (identity only; separate from env var contents), enabling consistent UI display across devices.
359
+ * **Log redaction (daemon/CLI):** spawn logs no longer print tokens or env var values; doctor output masks `${VAR:-default}` / `${VAR:=default}` templates to avoid leaking embedded secrets.
360
+ * **Offline buffering restored:** CLI socket sends rely on socket.io buffering when disconnected (with tests), instead of refusing to emit while offline.
361
+ * **Spawn env flexibility:** spawn RPC accepts arbitrary env var maps (typed as `Record<string,string>`) to keep GUI/CLI interoperable as provider keys evolve.
362
+ * Spawn env inputs are sanitized (including prototype-pollution defenses) before use to reduce risk from untrusted keys.
363
+ * **CLI profile schema alignment:** CLI persistence drops legacy provider config objects and migrates them into env vars at parse-time (preserves data; env-var based profiles are the single source of truth).
364
+ * **Legacy tmuxConfig removal:** CLI profile schema removes deprecated `tmuxConfig` and stops exporting tmux env vars from profiles (terminal behavior is driven by explicit terminal spawn options).
365
+
366
+ ### Server hardening beyond “Server Light”
367
+
368
+ * **Serve UI from server:** hardened optional static UI serving and SPA fallback behavior; improved missing bundle/index handling (404 vs 500), including in SPA error handlers.
369
+ * **Public files safety:** strict path normalization and segment-wise URL encoding in file serving routes (rejects traversal/absolute/drive-letter input; encodes `#`/`?` safely).
370
+ * **Storage validation (S3/Minio):** fail-fast env validation and bucket existence checks (validates `S3_PORT` range and errors if the bucket does not exist).
371
+
372
+ ### Misc
373
+
374
+ * **Codex `/clear` handling:** treat `/clear` as a session boundary so Codex session state resets deterministically.
375
+ * _Credit:_ Thanks to @zkytech — commits ported into the monorepo from [slopus/happy-cli#72](https://github.com/slopus/happy-cli/pull/72).
376
+ * **Friends UX/reliability:** follow-up hardening for friends surfaces (e.g., stable error handling/search behaviors, localized search failure messaging via stable error codes).
377
+ * Friends/Inbox routes are experiment-gated (with hooks + settings toggle) so access/routing is consistent when the feature is disabled.
378
+
379
+ ---
380
+
381
+ ## ✅ Test Plan (what maintainers should validate)
382
+
383
+ This is the suggested “high-signal” manual test checklist for the master PR:
384
+
385
+ * **Server Light:** boot light flavor, create sessions, verify SQLite persistence, verify local-files/public-file serving, verify optional UI serving (SPA routes + missing bundle handling).
386
+ * **MessageQueueV1:** queue messages while agent is busy/offline, resume connectivity, verify CAS semantics prevent duplication, verify in-flight removal happens only after delivery confirmation.
387
+ * **Capabilities + `preview-env`:** verify capability detection for key tools (Claude/Codex/Gemini/Tmux/OpenCode), verify `preview-env` detects missing requirements and wizard shows actionable preflight errors.
388
+ * **Session Sharing:** share a session with a friend, verify access levels (`view/edit/admin`) and enforcement (view-only disables send), verify realtime updates on share changes, create/rotate/disable a public link (expiry/max-uses), verify consent-required flows, and verify `/share/[token]` viewing works as expected.
389
+ * **Secrets Vault:** create/select secrets, verify masking/redaction (no plaintext persistence), verify requirement modal supports “enter once” vs vault selection.
390
+ * **Permissions:** verify default mode per agent, verify mode restoration from transcript across device restart, verify agent-specific allowlists/approvals (Codex/Gemini), verify AskUserQuestion/ExitPlan flows complete via the session `permission` RPC (including answers-on-permission where supported).
391
+ * **Resume:** resume inactive sessions end-to-end (Claude + Codex), verify no transcript loss, verify terminal/runner state is rehydrated correctly.
392
+ * **Terminal/TMUX:** headless tmux session spawn, attach to existing sessions, verify targeting correctness, verify switching local↔remote without orphaned processes.
393
+ * **UI primitives:** overlays/popovers/modals on iOS + web (especially stacked modal touch behavior + Expo web modal behavior).
394
+
395
+ ---
396
+
397
+ ## 🔗 GitHub Issue Crosswalk (happy + happy-cli)
398
+
399
+ This is a conservative, audit-driven mapping between GitHub issues and the changes described above.
400
+
401
+ (Scan date: 2026-01-26; audit base: `upstream/main` vs `leeroy-wip`)
402
+
403
+ **Legend**
404
+ - **Likely addressed/implemented**: strong match + direct code changes in `leeroy-wip` that plausibly resolve the issue.
405
+ - **Partially addressed / needs validation**: PR improves the area, but does not obviously guarantee a full fix.
406
+ - **Related (unverified)**: same surface area; included for reviewer context only.
407
+ - **Already in upstream (PR refines)**: feature existed on `upstream/main`; changes here are refinements (scoping, hardening, polish).
408
+
409
+ ### Server selection & self-hosting (server URL + deployment/docs)
410
+ - **Already in upstream (PR refines):** slopus/happy#51, slopus/happy#340
411
+ - **Partially addressed / needs validation:** slopus/happy#142, slopus/happy#246, slopus/happy#284, slopus/happy#381, slopus/happy#420, slopus/happy#463
412
+ - **Related (unverified):** slopus/happy#415, slopus/happy#421, slopus/happy#54, slopus/happy#472, slopus/happy-cli#14, slopus/happy-cli#31
413
+
414
+ ### MessageQueueV1 / pending-message reliability
415
+ - **Likely addressed/implemented:** slopus/happy#260, slopus/happy#349
416
+ - **Partially addressed / needs validation:** slopus/happy#261, slopus/happy#297, slopus/happy#405, slopus/happy#474
417
+
418
+ ### Inactive session resume
419
+ - **Likely addressed/implemented:** slopus/happy#23, slopus/happy#98, slopus/happy#147, slopus/happy#353, slopus/happy#426, slopus/happy#437
420
+ - **Related (unverified):** slopus/happy#73, slopus/happy-cli#10
421
+
422
+ ### Claude reliability (switching + terminal state restoration)
423
+ - **Likely addressed/implemented:** slopus/happy#301, slopus/happy#304
424
+ - **Partially addressed / needs validation:** slopus/happy#90, slopus/happy#430, slopus/happy#424, slopus/happy#46, slopus/happy#425
425
+ - **Related (unverified):** slopus/happy#123, slopus/happy#422, slopus/happy#423, slopus/happy#443, slopus/happy#379, slopus/happy-cli#11
426
+
427
+ ### Codex MCP / approvals / tool-call correctness
428
+ - **Likely addressed/implemented:** slopus/happy#167, slopus/happy#207, slopus/happy-cli#39
429
+ - **Partially addressed / needs validation:** slopus/happy#157, slopus/happy#158, slopus/happy#164, slopus/happy#181, slopus/happy#445, slopus/happy#447, slopus/happy#470
430
+ - **Related (unverified):** slopus/happy#146, slopus/happy#139, slopus/happy#247, slopus/happy-cli#43
431
+
432
+ ### Permission modes / YOLO / approval state persistence
433
+ - **Likely addressed/implemented:** slopus/happy#29, slopus/happy#446
434
+ - **Partially addressed / needs validation:** slopus/happy#206, slopus/happy-cli#150, slopus/happy#371, slopus/happy#350
435
+ - **Related (unverified):** slopus/happy#375, slopus/happy#225, slopus/happy#146, slopus/happy#365, slopus/happy#469, slopus/happy-cli#147, slopus/happy#227
436
+
437
+ ### ACP agent expansion (Codex ACP + OpenCode ACP + Auggie ACP + agent catalog)
438
+ - **Likely addressed/implemented (OpenCode):** slopus/happy#265, slopus/happy#344, slopus/happy#394, slopus/happy#477
439
+ - **Likely addressed/implemented (Auggie, experimental):** slopus/happy#133
440
+ - **Partially addressed / needs validation (broader ACP roadmap items):** slopus/happy#217, slopus/happy#267
441
+
442
+ ### Slash commands (Claude + ACP)
443
+ - **Partially addressed / needs validation:** slopus/happy#14, slopus/happy#203
444
+ - **Related (unverified):** slopus/happy#182
445
+
446
+ ### Models / Gemini availability
447
+ - **Partially addressed / needs validation:** slopus/happy#176, slopus/happy-cli#146, slopus/happy#471
448
+
449
+ ### Daemon process safety (reattach/ownership gating) + service requests
450
+ - **Partially addressed / needs validation:** slopus/happy#175, slopus/happy#191
451
+ - **Related (unverified):** slopus/happy#433, slopus/happy#434
452
+
453
+ ### Auth / linking / backups
454
+ - **Likely addressed/implemented:** slopus/happy#19
455
+ - **Partially addressed / needs validation:** slopus/happy#399, slopus/happy#400, slopus/happy#80, slopus/happy#387
456
+ - **Related (unverified):** slopus/happy#92
457
+
458
+ ### Secrets / logging / path safety
459
+ - **Likely addressed/implemented:** slopus/happy-cli#44
460
+ - **Related (unverified):** slopus/happy-cli#46, slopus/happy#336, slopus/happy#416
461
+
462
+ ### New Session Wizard + machine/endpoint selection
463
+ - **Partially addressed / needs validation:** slopus/happy#315, slopus/happy#57
464
+
465
+ ### Sessions UX (unread/rename/notifications/deep linking)
466
+ - **Partially addressed / needs validation:** slopus/happy#102, slopus/happy#305, slopus/happy#209, slopus/happy#435, slopus/happy#462, slopus/happy#86, slopus/happy-cli#28, slopus/happy#362, slopus/happy#368
467
+
468
+ ### Terminal/TMUX & headless attach
469
+ - **Partially addressed / needs validation:** slopus/happy#195, slopus/happy#204
470
+
471
+ ### Tool UX (specialized renderers + native interaction routing)
472
+ - **Related (unverified):** slopus/happy#128, slopus/happy#8
473
+
474
+ ---
475
+
476
+ ## 🧾 Upstream Open PRs Cross-check (double-verified)
477
+
478
+ Scan date: **2026-01-26** (open PRs in `slopus/happy`, `slopus/happy-cli`, and `slopus/happy-server`).
479
+
480
+ Verification method: sampled added/removed diff lines from each PR (via GitHub `pulls/<n>/files` patches) and checked whether those lines are present/absent in the monorepo branch `slopus/tmp/leeroy-wip` (file paths mapped to `expo-app/…`, `cli/…`, and `server/…`).
481
+
482
+ - `PORTED`: we intentionally extracted/ported this PR into the monorepo and added explicit credits elsewhere in this PR description.
483
+ - `VERIFIED`: strong evidence the PR’s changes are already present (or superseded) in `leeroy-wip`.
484
+ - `PROBABLE`: meaningful overlap, but not tight enough to claim superseded without a quick human spot-check.
485
+
486
+ PRs without sufficient evidence are intentionally omitted to avoid false positives.
487
+
488
+ ### slopus/happy
489
+
490
+ #### PORTED (credited above)
491
+
492
+ | PR | Title | Author | Evidence |
493
+ | --- | --- | --- | --- |
494
+ | [slopus/happy#299](https://github.com/slopus/happy/pull/299) | feat: add execpolicy approval option for Codex | @OrdinarySF | checks 61; add 93%; remove 78%; missingFiles 1 |
495
+ | [slopus/happy#356](https://github.com/slopus/happy/pull/356) | feat: session sharing UI (friends + public links) | @54m | ported into monorepo; see Session Sharing section |
496
+
497
+ #### VERIFIED (likely superseded)
498
+
499
+ | PR | Title | Author | Evidence |
500
+ | --- | --- | --- | --- |
501
+ | [slopus/happy#345](https://github.com/slopus/happy/pull/345) | Add copy-to-clipboard button to message blocks | @leeroybrun | checks 14; add 100%; remove 100%; missingFiles 0 |
502
+
503
+ #### PROBABLE (review)
504
+
505
+ | PR | Title | Author | Evidence |
506
+ | --- | --- | --- | --- |
507
+ | [slopus/happy#372](https://github.com/slopus/happy/pull/372) | Fix possible issues introduced by #272 | @leeroybrun | checks 1407; add 83%; remove 81%; missingFiles 9 |
508
+ | [slopus/happy#388](https://github.com/slopus/happy/pull/388) | fix: stabilize PR272 new-session UX, profiles gating, and env safety | @leeroybrun | checks 1840; add 82%; remove 88%; missingFiles 15 |
509
+
510
+ ### slopus/happy-cli
511
+
512
+ #### PORTED (credited above)
513
+
514
+ | PR | Title | Author | Evidence |
515
+ | --- | --- | --- | --- |
516
+ | [slopus/happy-cli#72](https://github.com/slopus/happy-cli/pull/72) | feat: handle /clear command as session reset in codex | @zkytech | checks 15; add 92%; remove 0%; missingFiles 0 |
517
+ | [slopus/happy-cli#101](https://github.com/slopus/happy-cli/pull/101) | fix: use runtime execPath for MCP bridge | @OrdinarySF | checks 30; add 39%; remove 58%; missingFiles 0 |
518
+ | [slopus/happy-cli#102](https://github.com/slopus/happy-cli/pull/102) | feat(codex): support execpolicy approvals and MCP tool calls | @OrdinarySF | checks 63; add 59%; remove 96%; missingFiles 1 |
519
+ | [slopus/happy-cli#120](https://github.com/slopus/happy-cli/pull/120) | fix(cli): improve abort error handling to reduce spurious error messages | @cruzanstx | checks 14; add 100%; remove 100%; missingFiles 0 |
520
+ | [slopus/happy-cli#127](https://github.com/slopus/happy-cli/pull/127) | fix: forward signals to child process in binary launcher | @fberlakovich | checks 12; add 25%; remove —; missingFiles 0 |
521
+ | [slopus/happy-cli#139](https://github.com/slopus/happy-cli/pull/139) | fix: move claudeArgs to end of args array for slash command support | @jiogallardy | checks 6; add 100%; remove 0%; missingFiles 0 |
522
+
523
+ #### PROBABLE (review)
524
+
525
+ | PR | Title | Author | Evidence |
526
+ | --- | --- | --- | --- |
527
+ | [slopus/happy-cli#123](https://github.com/slopus/happy-cli/pull/123) | Fix possible issues introduced by #107 | @leeroybrun | checks 413; add 81%; remove 75%; missingFiles 8 |
528
+ | [slopus/happy-cli#134](https://github.com/slopus/happy-cli/pull/134) | fix: stabilize PR107 tmux spawn, offline buffering, and bun runtime | @leeroybrun | checks 414; add 81%; remove 76%; missingFiles 9 |
529
+
530
+ ### slopus/happy-server
531
+
532
+ #### PORTED (credited above)
533
+
534
+ | PR | Title | Author | Evidence |
535
+ | --- | --- | --- | --- |
536
+ | [slopus/happy-server#25](https://github.com/slopus/happy-server/pull/25) | feat: session sharing API/server support | @54m | ported into monorepo; see Session Sharing section |
@@ -131,7 +131,9 @@ See: `docs/server-flavors.md`.
131
131
  - Prefer `happys stack <stack> ...` commands (typecheck/lint/build/test/dev/start).
132
132
  - To run `happy-cli` against a specific stack: `happys stack happy <stack> -- <happy args...>` (stack shorthand: `happys <stack> happy ...`).
133
133
  - **Do not “kill all daemons”**
134
- - Multiple stack daemons are expected. Stop stacks explicitly (`happys stack stop …` or `happys stop …`).
134
+ - Multiple stack daemons are expected.
135
+ - If you use stack daemon **identities** (`--identity=<name>`), multiple daemons for the *same stack* can also be intentional.
136
+ - Stop stacks explicitly (`happys stack stop …` or `happys stop …`), or stop a specific daemon identity (`happys stack daemon <stack> stop --identity=<name>`).
135
137
  - **Main stack safety**
136
138
  - Avoid repointing `main` stack component dirs to worktrees. Use a new stack.
137
139
  - `happys wt use …` will warn/refuse for `main` unless you pass `--force`.
@@ -748,6 +750,21 @@ Login (interactive):
748
750
  happys stack auth <stack> login
749
751
  ```
750
752
 
753
+ Multiple accounts on one stack (optional): use an identity and disable auto browser open so you can choose the
754
+ browser profile/account you authenticate as:
755
+
756
+ ```bash
757
+ happys stack auth <stack> login --identity=account-a --no-open
758
+ happys stack auth <stack> login --identity=account-b --no-open
759
+ ```
760
+
761
+ Start/stop a specific identity daemon:
762
+
763
+ ```bash
764
+ happys stack daemon <stack> start --identity=account-a
765
+ happys stack daemon <stack> stop --identity=account-a
766
+ ```
767
+
751
768
  Non-interactive repair (copy credentials + seed accounts from `main`):
752
769
 
753
770
  ```bash