# PR stack plan (draft)

Generated: 2026-01-25T18:08:26.317Z

> ⚠️ Superseded: this file is an older “~15 PRs” draft generated early from topic buckets.
> It does **not** reflect the current PR catalog or the active rewrite execution.
>
> Canonical references:
> - PR definitions/titles: `docs/commit-audits/happy/leeroy-wip.pr-catalog.draft.md`
> - Commit → PR mapping (source of truth): `docs/commit-audits/happy/leeroy-wip.pr-assignment.working.tsv`
> - Current rewrite order/status: `docs/commit-audits/happy/leeroy-wip.rewrite-status.tsv`

This is a **draft** proposal to split the `leeroy-wip` changes into ~15 PRs.
It is derived from the audit metadata (topic buckets + manual verdicts), and must be reviewed/edited by humans before any history rewrite.

Principles:
- Prefer “final feature state” (squash fixups into the feature commits).
- Keep commit granularity *within* a PR, but avoid “evolution noise” (back-and-forth) in the rewritten history.
- Avoid mega-commits: when a commit is marked `split`, execute it as multiple commits by file/feature boundary.

Coverage:
- Total commits: 249
- notesReviewed=yes: 249
- Split candidates: 4
- Assigned to PRs: 249

## PR01: Foundations: tooling, deps, test infra
- Buckets: `crypto`, `deps`, `config`, `format`, `typecheck`, `dev`, `runtime`, `logging`, `test`
- Commits: 11
- Commit list:
  - 001 58528a7c37d3 chore(crypto): patch react-native-libsodium
  - 002 552b8da0f621 test(deps): add @types/react-test-renderer
  - 003 017b15c07ad7 chore(config): harden app variant defaults
  - 012 207ef1b2f572 fix(dev): gate CLI detection logging
  - 023 d97924f3ef39 chore(test): define __DEV__ for vitest
  - 046 ea2e4d19d633 chore(deps): align react-test-renderer with react
  - 051 43f23f2f082e chore(format): replace stray tabs with spaces
  - 072 82d74454c3c4 fix(typecheck): restore permission imports and Popover web styles
  - 088 a7d23148c311 fix(logging): gate debug output and redact templates
  - 092 6b0bfe546d9e feat(runtime): support bun for daemon-spawned subprocesses [notesUpdated]
  - 128 d317f6bfa282 fix(typecheck): resolve duplicate terminalRuntime and RPC handler types

## PR02: Expo web modals + expo-router pin/patch
- Note: Draft: later we will split expo-app commits across PRs based on touched files (router/postinstall vs feature UI).
- Buckets: `expo-app`, `expo`
- Commits: 12
- Commit list:
  - 069 c06b6202b5d4 Add copy-to-clipboard button to message blocks
  - 163 84df0d260513 fix(expo-app): stabilize postinstall and libsodium patches
  - 177 893ce7af5df0 fix(expo-app): avoid hooks order violation on redirect
  - 178 7afbc9a2decd fix(expo-app): persist resumeSessionId and harden clipboard paste
  - 179 9a13879b753a fix(expo-app): avoid false homeDir prefix matches
  - 180 c107a779e07d fix(expo-app): avoid stuck loading in capabilities cache
  - 181 35c0974eff1f refactor(expo-app): remove dead code and dedupe types
  - 185 947b8d1814fb refactor(expo-app): remove unused optimistic flag
  - 191 0dd19e7fb257 fix(expo-app): default codex resume spec to empty
  - 246 384b15252026 fix(expo): harden tool submit and pending send
  - 248 bf3027799623 Set EXPO_UNSTABLE_WEB_MODAL env var in Expo scripts
  - 249 c803115dcbdc Improve postinstall script for symlinked paths and patching

## PR03: i18n structure + localization passes
- Buckets: `i18n`
- Commits: 15
- Commit list:
  - 017 65bae55a0b61 refactor(i18n): separate translation types and content [notesUpdated]
  - 028 0023ba1ea5aa refactor(i18n): update translations and tooling [notesUpdated]
  - 036 97ca69e0a735 refactor(i18n): replace remaining UI literals [notesUpdated]
  - 052 e1d55fdbd9ee fix(i18n): improve untranslated literal scan parsing
  - 168 9dfa09bef8d8 fix(i18n): add Codex execpolicy button text
  - 182 b319d85e72c3 fix(i18n): correct Spanish resumable label
  - 196 21e096e9454e fix(i18n): localize session settings item
  - 197 7ca9e93196d6 fix(i18n): translate ExitPlanMode strings
  - 198 c4a81947f002 fix(i18n): localize search error
  - 199 208f0222a997 fix(i18n): localize Codex resume dialog
  - 200 02ad6b4a8352 fix(i18n): move openMachine to connect scope
  - 204 a4d7faba961f fix(i18n): localize session error fallbacks
  - 223 73ce32d242a0 fix(i18n): translate Spanish experiment subtitles
  - 224 98bc00096e86 fix(i18n): localize Codex resume banner [SPLIT]
  - 236 054250f408e2 fix(i18n): localize codex resume install modals

## PR04: UI primitives + navigation/UX surfaces
- Buckets: `ui`, `modal`, `popover`, `agent-input`, `a11y`, `web`, `command-palette`, `autocomplete`, `experiments`, `zen`
- Commits: 28
- Commit list:
  - 013 58a892d413d1 fix(command-palette): include navigate dependency
  - 020 8d9f56e85e5a refactor(ui): unify list selectors and modal primitives [notesUpdated]
  - 022 2d4675a5d051 fix(agent-input): use compact permission badges
  - 029 12e75a3b36fa fix(autocomplete): remove debug suggestion logs
  - 031 4dc9c7f8759c feat(agent-input): add configurable action bar layout [notesUpdated]
  - 032 e8e42a6087ad fix(modal): prevent stacked modal touch-blocking on iOS [notesUpdated]
  - 035 7ffd0c3428cb fix(ui): localize error alerts
  - 037 5f5b57df5181 refactor(ui): improve item rendering and action menu timing
  - 038 7976b877259c feat(experiments): gate Zen, file viewer, and voice auth flow
  - 039 6ed379f82c34 refactor(ui): add modal + popover overlay primitives
  - 048 395da4ff3167 refactor(zen): avoid todo variable shadowing
  - 050 2da2f9349ec5 fix(popover): allow web fixed positioning types
  - 054 66c678451335 fix(ui): apply small review fixes [SPLIT]
  - 055 2472b376775c test(modal): make backdrop z-index assertion safer
  - 059 f7f81497444d fix(modal): prevent non-dismissible WebAlertModal [SPLIT]
  - 061 765423af52b4 fix(agent-input): cycle permission mode from normalized state
  - 062 e533db1813a5 fix(popover): add screens cjs helper and fix fixed positioning types
  - 064 e5848c480522 fix(ui): harden overlays and permission cycling
  - 102 c988f68ca4d0 feat(ui): surface Codex/Gemini errors in session UI [notesUpdated]
  - 109 af5000ea6318 fix(ui): polish Codex and Gemini error messages
  - 143 c4beebbfa375 feat(ui): add Codex resume experiment toggle
  - 147 231d7ad9bdd9 fix(ui): clarify Codex resume server label
  - 149 bcf10af94626 test(ui): update useCLIDetection hook tests for capabilities
  - 164 544f9711b6cf fix(ui): respond to plan/question tools via session RPC
  - 201 ce42bf56d7b6 fix(web): correct libsodium wrapper typing
  - 202 f0417ca11ac5 fix(web): keep libsodium wrapper namespace typing
  - 215 82968aa8fe6c fix(ui): send pending messages before closing modal
  - 239 e2618e04a26b fix(a11y): add labels to codex resume actions

## PR05: Core storage & persistence primitives
- Buckets: `storage`, `persistence`, `settings`, `env`, `auth`
- Commits: 17
- Commit list:
  - 004 4890a471df31 fix(auth): harden tokenStorage web persistence
  - 006 a5fbc3e8ba00 feat(persistence): scope storage and validate draft modes [notesUpdated]
  - 010 39cc25154cdd feat(storage): persist session model modes
  - 011 c2d3507357dc fix(settings): make parsing tolerant for profiles [notesUpdated]
  - 014 41479b35415f feat(env): add env var template parsing
  - 015 695bcd09eb9e fix(env): improve remote env resolution and previews
  - 016 6cdb90a49aad feat(env): update env var list, cards, and preview modal
  - 024 9c19baa833b9 feat(settings): add api keys and experiment toggles
  - 030 679877c26ea9 feat(settings): expose per-experiment toggles
  - 060 bb09f91de715 fix(settings): keep valid secrets when one entry is invalid
  - 094 809be82b53e7 fix(env): implement default assignment semantics
  - 104 f53cf71d416c refactor(persistence): remove deprecated tmuxConfig
  - 115 a8093e3e4ddb docs(persistence): update profile schema version comment
  - 156 8c16ee8f9cef fix(auth): surface auth failures and gate unauth routes
  - 203 b6d3874bf175 fix(settings): include Codex resume in master experiment toggle
  - 210 b7f63e928e4f fix(persistence): retry daemon state read when file appears
  - 243 0b7db6945325 fix(storage): validate S3_PORT and bucket existence

## PR06: Secrets / vault / SecretString
- Buckets: `secrets`
- Commits: 3
- Commit list:
  - 041 66ee1eaf88a6 feat(secrets): add secrets management + requirement resolver [notesUpdated]
  - 057 ff7bec72358f fix(secrets): tighten callback deps and fix indentation
  - 063 2ed3100311c7 fix(secrets): hide values when using secret vault

## PR07: Profiles + API keys + environment variables UX
- Buckets: `profiles`, `api-keys`, `env`
- Commits: 6
- Commit list:
  - 019 9e08047d2478 fix(profiles): harden routing, grouping, and editing [notesUpdated]
  - 025 21cc6df79f50 feat(api-keys): add saved API keys UI [notesUpdated]
  - 027 7899bbd8433e feat(profiles): add API key requirements flow [notesUpdated]
  - 056 02450d179aaf fix(profiles): align experimentsEnabled for built-in profiles
  - 090 1f90659694be refactor(profiles): remove unwired startup script and local env cache
  - 091 7aed8aaee02f refactor(profiles): drop provider config objects

## PR08: New session wizard + session creation UX
- Buckets: `new-session`, `new`, `machine`
- Commits: 7
- Commit list:
  - 018 2993b5c860ff fix(new-session): restore standard modal flow [notesUpdated]
  - 026 ce9cd74d408a feat(machine): surface detected CLI status
  - 033 daa0b4527d7f feat(new-session): add api key selection and wizard extraction [notesUpdated]
  - 043 bc779e4f7909 refactor(new-session): integrate secrets + terminal spawn options [notesUpdated]
  - 049 2e956f32f220 fix(new): keep pick screens above iOS modal
  - 058 1bb65f5dd494 fix(new-session): avoid stuck secret requirement modal guard
  - 225 4fabec9b69b3 feat(new-session): add WizardSectionHeaderRow

## PR09: Permissions + tool views
- Buckets: `permission`, `tools`
- Commits: 8
- Commit list:
  - 008 f7bb8a28fff7 fix(tools): harden ACP tool parsing and titles
  - 073 4f2b533f99c2 feat(tools): add approve/reject buttons to ExitPlanMode
  - 132 88494b122194 fix(tools): support Windows arm64 tool unpacking
  - 160 7fbe1f1cc727 fix(permission): avoid no-op permissionModeUpdatedAt bumps
  - 208 61a18ac95e17 fix(tools): require permission id for ExitPlanMode actions
  - 209 5b36c9bf91c1 test(tools): avoid null permission in ExitPlanToolView tests
  - 211 55428fb0253c fix(tools): alert when AskUserQuestion permission id is missing
  - 226 c461ed1cb4ef feat(permission): add permission mode option helpers

## PR10: CLI/daemon/RPC plumbing + capabilities
- Buckets: `capabilities`, `cli-detection`, `detect-cli`, `rpc`, `daemon`, `socket`, `hooks`, `happy`, `cli`, `happy-cli`, `app`, `common`, `utils`, `pr107`, `reducer`
- Commits: 50
- Commit list:
  - 021 2ab560bb0535 feat(cli-detection): add daemon detect-cli RPC support
  - 083 7292a29822bb fix(daemon): do not apply CLI active profile to GUI-spawned sessions
  - 085 e58e97fd7ff4 fix(pr107): harden daemon spawn + align profile schema [notesUpdated]
  - 087 a25acab22b64 fix(socket): restore offline buffering for sends [notesUpdated]
  - 089 ef418bc4dda3 fix(pr107): redact profile secrets in doctor + align tmux tmpDir
  - 093 4071466545ab refactor(rpc): accept arbitrary env var maps for spawn
  - 095 4c2a671dc3f4 feat(rpc): add preview-env handler [notesUpdated]
  - 101 1075a768e551 feat(rpc): add detect-cli handler [notesUpdated]
  - 105 8dae65f6c585 feat(rpc): include tmux in detect-cli [notesUpdated]
  - 107 c13d51ee4638 feat(daemon): support tmux spawn + harden runtime [notesUpdated]
  - 108 f7db44dea458 docs: add AGENTS.md symlink
  - 112 45f4eb5d145c test(detect-cli): avoid process.env reassignment
  - 114 0ad76f4877ae chore(cli): fix gemini daemon block indentation
  - 117 d9591372655f fix(common): handle execFileAsync exit codes
  - 121 9c4cb44b7d86 fix(daemon): reattach sessions after daemon restart [notesUpdated]
  - 122 dbde6d871670 test(daemon): add PID classification + session marker tests
  - 123 7cffdd5ce614 fix(daemon): verify PID via command hash for reattach/stop
  - 126 ffad20faa406 fix(cli): publish permission mode for codex/gemini sessions
  - 129 a8682d427794 fix(detect-cli): relax tmux version probe timeout
  - 138 d3aefaa9b598 refactor(daemon): extract reattach and pid safety helpers
  - 139 72397b7e8c94 test(daemon): add opt-in reattach integration tests
  - 140 9c40c54018c2 Revert "fix(tools): support Windows arm64 tool unpacking"
  - 148 8bebf04aca92 refactor(cli): modularize capabilities and env preview [notesUpdated]
  - 150 a5cac698f15b feat(cli): harden session queue, switching, and lifecycle
  - 151 3fc704424e8d feat(app): add pending queue, discard markers, and capabilities [notesUpdated]
  - 154 39c7b8a56b32 refactor(app): rename tmux/message-send settings under session
  - 157 320a89e19ca0 test(happy): run cli and server checks from root scripts
  - 158 3b3609fed434 fix(rpc): add structured code for missing RPC methods
  - 165 8b3f39f22664 feat(cli): add interaction.respond for AskUserQuestion
  - 169 559d39da116d fix(reducer): keep permission messages idempotent
  - 173 332ab2b0cd93 fix(cli): improve abort error handling to reduce spurious error messages
  - 183 46186162ae14 test(happy-cli): fix timer cleanup and MCP schema mocks
  - 184 ac5bf2f3abfa test(happy-cli): reset modules for runtime override
  - 188 04d9c60ef8e7 refactor(happy-cli): remove unreachable gemini error branch
  - 195 8ab11f2788c1 fix(happy-cli): parse CLI versions from full output
  - 207 61bf70183ebf test(cli): set DEBUG before importing logger
  - 214 5bcc7d20cd6b test(utils): stabilize serverConnectionErrors retry count test
  - 218 47f638b73fca test(utils): cover failuresCount with custom backoff
  - 219 2abc70fef03c fix(utils): track failuresCount for custom backoff
  - 222 abf288056636 fix(cli): reject invalid messageQueueV1 inFlight
  - 229 d89a9427e765 fix(cli): clean up metadata waiters on disconnect
  - 230 fedb8a66160a test(cli): accept lowercase preview-env keys
  - 231 fc0ce89b13b7 fix(cli): allow lowercase preview-env keys
  - 232 ad95c5b01c25 test(happy): keep useCLIDetection timestamp stable
  - 233 c251edf3c307 test(happy): fix useCLIDetection timestamp test
  - 234 34fa4091d3cc fix(happy): stabilize useCLIDetection timestamp
  - 235 31340e53294c fix(happy): inline CLI detection request
  - 237 241f0ae24b1d test(cli): prevent legacy sessionId path traversal
  - 238 a1e4a6dd3fbd fix(cli): block legacy sessionId path traversal
  - 245 82bf82cb6715 fix(hooks): prevent stale capabilities cache overwrite

## PR11: Terminal/tmux/headless + Ink UX
- Buckets: `terminal`, `tmux`, `ink`
- Commits: 11
- Commit list:
  - 042 bdaf6913141f feat(terminal): add Terminal settings + tmux metadata [notesUpdated]
  - 082 3fbdc10018fe fix: tmux parsing/targeting + review feedback [SPLIT,notesUpdated]
  - 098 0a1a91a631e7 feat(tmux): support per-instance socket path [notesUpdated]
  - 099 c52227082c2b fix(tmux): correct env, tmpdir, and session selection [notesUpdated]
  - 106 ad66c6aaa3ae feat(terminal): add tmux metadata + attach tooling [notesUpdated]
  - 110 f68552d03ab9 fix(tmux): print attach instructions in correct order
  - 111 4e4bb65ff3f0 test(tmux): avoid brittle assertions
  - 152 49893dd7d16a fix(terminal): harden remote→local switching input [notesUpdated]
  - 212 dc6955f88abd fix(terminal): prevent sessionId path traversal in attachment info
  - 213 bb685fbeff7b fix(terminal): clarify missing --happy-starting-mode value
  - 216 b7219c8bfe2b fix(ink): avoid async useInput handler

## PR12: Message queue V1 + pending/discard flows
- Buckets: `queue`, `sync`
- Commits: 17
- Commit list:
  - 005 4adc41d92af0 feat(sync): add permission mode types and mapping
  - 009 292424245277 refactor(sync): centralize outgoing message metadata
  - 034 94814465bf81 perf(sync): debounce pending settings writes
  - 040 f0787de5308e feat(sync): add secrets + terminal settings primitives [notesUpdated]
  - 045 1bc3b9715776 fix(sync): handle non-JSON 400 responses
  - 047 dd041d21ecfc fix(sync): guard JSON parsing on disconnect errors
  - 053 c210c1115598 test(sync): restore stubbed fetch between tests
  - 065 69fdcff96a4c fix(sync): restore session permission mode from last message
  - 066 9b499c5dccce fix(sync): persist permission mode timestamp for restart-safe arbitration
  - 067 def8852509d0 fix(sync): persist permission mode reliably across devices
  - 074 c86cbd26b040 feat(queue): add pending message queue UI and send modes
  - 081 4ddaef02210e fix(sync): omit model meta for queued messages [notesUpdated]
  - 118 ab95e8cf920c fix(sync): avoid hanging invalidateAndAwait on errors [notesUpdated]
  - 130 e2824dbc858b feat(queue): add server-side pending message pull support
  - 155 fcec6c311b6b feat(sync): add cross-device unread markers
  - 227 23b595edd0fe refactor(sync): simplify path formatting
  - 244 74fc860b07b5 refactor(queue): simplify stale in-flight reclaim

## PR13: Resume + session lifecycle
- Buckets: `resume`, `session`, `sessions`, `scanner`, `offline`
- Commits: 19
- Commit list:
  - 007 18e77c46f38a fix(session): clamp configurable model modes
  - 068 b1c8a6fecd01 fix(session): archive when kill RPC unavailable
  - 070 9fc7d3d412b9 feat(sessions): group inactive sessions by project
  - 071 62a8b1b07c3e feat(sessions): add unread badge
  - 075 42da6dae8fe4 feat(session): add session rename support
  - 076 057102f67904 feat(resume): add resume session option for new sessions [notesUpdated]
  - 077 05532bd65c6b feat(resume): show resume chip under path in new session
  - 078 cd5771e50881 feat: resume inactive Claude sessions from UI [notesUpdated]
  - 079 456e2ad8e2b8 refactor(resume): don't require agentSessionId from UI [notesUpdated]
  - 084 ce94cfa512ac feat(session): persist profileId in session metadata via daemon spawn
  - 097 c863db3d5bbc refactor(offline): make offline session stub safer
  - 131 37a2c55a6c2f fix(session): prime agent state for readiness
  - 133 d71587eda2db feat: resume Claude sessions from UI
  - 134 a80868aff50d feat: resume inactive Claude sessions from UI
  - 135 bcaa530b12d7 feat(resume): add happy resume and persist vendor resume id
  - 136 e085e75c5d36 feat(resume): allow resume-session without agentSessionId
  - 141 ab35b47ff699 fix(resume): make inactive resume reliable; gate Codex resume
  - 159 0e2c7928f24c fix(scanner): tolerate onMessage exceptions
  - 162 ee0bec2a0b90 Delete INACTIVE_SESSION_RESUME.md

## PR14: Codex & Claude integration
- Buckets: `codex`, `claude`, `gemini`, `fork`
- Commits: 29
- Commit list:
  - 044 cb11d4bdb25a docs: add AGENTS.md symlink + update CLAUDE.md
  - 080 9b0069e3d30c feat(fork): enable Codex resume support [notesUpdated]
  - 096 2973f7fe6861 fix(codex): harden MCP command detection
  - 100 7a01a8e42629 test(claude): align sessionScanner path mapping
  - 103 b2269ee11252 fix(claude): use hook transcript path across switching [notesUpdated]
  - 113 51782fdbfbcd test(codex): reset transport instances between tests
  - 116 b16c3658b944 fix(gemini): normalize error details for UI
  - 119 6f98c95fb5d8 fix(claude): support -c/-r and avoid session loss on switch [notesUpdated]
  - 120 9489d70848f3 test(claude): align sessionScanner path mapping
  - 124 8b88dcd73d40 fix(claude): carry permission mode across remote/local switches
  - 125 8f0e10c9428b fix(claude): publish permission mode in session metadata
  - 127 eb72c6e69434 fix(codex): disable model override and remove experimental resume
  - 137 68a6ba4bc244 feat(fork): enable Codex inactive-session resume via codex-reply
  - 142 aa9b11684389 fix(codex): increase installer output buffer
  - 144 0140ae276869 refactor(codex): install mcp resume server via install-dep
  - 145 2ec41b621b54 fix(codex): detect resume binary on Windows
  - 146 e1deb6db8ddb refactor(codex): add dep-status and drop codex-resume RPCs
  - 153 0126667539b6 fix(claude): forward signals to binary child process
  - 161 2026fbab5cb3 fix(claude): accept -c as continue flag
  - 166 ed4bc007308a feat: add execpolicy approval option for Codex
  - 167 78adc9c58811 feat(codex): support execpolicy approvals and MCP tool calls
  - 170 cc3c711ae28e fix: move claudeArgs to end of args array for slash command support
  - 171 d06d5a833f8e Add signal forwarding to claudeLocal.ts
  - 172 1b7cb3bfea86 feat: handle /clear command as session reset in codex
  - 174 e956463db3e2 fix: use runtime execPath for MCP bridge
  - 175 f0a7d8d0b40c fix(codex): use mcp tool call id for approvals
  - 217 d70a6f6669fe fix(claude): trim CLAUDE_CONFIG_DIR overrides
  - 240 d0f9ad5e8310 test(claude): remove stale transcriptPath red-test scaffolding
  - 241 1464402758bf fix(codex): preserve falsy MCP tool results

## PR15: Server & server-light: sqlite flavor, schema sync, storage backends
- Buckets: `server-light`, `server`, `storage`, `security`
- Commits: 16
- Commit list:
  - 086 86330e263595 fix(security): redact spawn secrets from daemon logs
  - 176 da620b6865ad feat(server): add full/light flavors with sqlite migrations [notesUpdated]
  - 186 8cc823d1ba2d fix(server-light): validate PORT and normalize paths
  - 187 8cb995a1abe1 test(server): fix schema generation sort regex
  - 189 2616e5e19253 fix(server): handle missing UI index.html
  - 190 911365366024 fix(server): make build typecheck tests
  - 192 229e5fc36570 fix(server-light): use file URLs for sqlite db
  - 193 e6f597e436c5 fix(server): fix server-light typecheck
  - 194 1564e800e355 fix(server): relax module settings for typecheck
  - 205 1ea2bddb8bbd test(server): validate processImage resize output
  - 206 1e7d7f8a4747 fix(server): keep light server running
  - 220 dc8016f01c56 fix(server): validate HAPPY_SERVER_LIGHT_DATA_DIR for light migrations
  - 221 b0085827322c fix(server): handle missing UI index in error handlers
  - 228 523989b4de8e fix(server-light): avoid master secret race
  - 242 57f84f0691c6 fix(server-light): harden public file path encoding
  - 247 24b607abfa07 Refactor schema sync and centralize Prisma types [notesUpdated]
