# Controller guide
Owns UI loop, worker lifetimes, input-to-paint sequencing and workflow admission.
## Where to look
| App/loop/frame/key bursts | `app.rs`, `app/{run_loop,frame,key_bursts}.rs` |
| Event drain/post-drain barriers | `drain.rs`, `app/drain_processing.rs` |
| Terminal capture/flush fence/pacing | `input_bridge.rs`, `pacing.rs` |
| Actions/state/display effect split | `app/{actions,reducer,display_reducer}.rs` |
| Readiness/submission/run lifecycle | `app/{startup,submit,workers}.rs` |
| Auth/theme/catalog/compaction/rewind/export | Matching modules under `app/` |
| Scoped settings/global fast/panel saves | `app/{settings_persistence,fast_mode_persistence,panel_layout_persistence}.rs` |
| Session maintenance/update/quota | `app/{session_maintenance,updates,codex_quota}.rs` |
## Local contracts
- Drain at most 128 events or 2ms/pass. Preserve `DrainResult`/`DrainOutcome`, input-to-paint barriers and redraw decisions; backlog cannot indefinitely delay input feedback.
- Normal-loop joins first check `is_finished()`. Match completion identity before replacing workers; wake markers can outlive workers. Retain join results independently of wake delivery, including settings/maintenance/footer-branch work.
- Session switch drains retained finite snapshot before live events under same budget, never requeues. Match pending request/session generation; rewind/export/model actions also validate captured context.
- Initial queued prompt requires critical readiness, painted frame and input flush fence; decoration cannot block readiness. Action/context values are data-only; display effects belong in display reducer.
- Auth read/remove shares one worker; reads apply only to matching modal, removal blocks prompts. Shutdown can detach reads but must join removal.
- Reopened theme picker reuses catalog work, with one save worker. Match request IDs/theme revisions, retain failed deliveries, cap shutdown catalog waits at 100ms each and join persistence.
- Fast saves are global and update memory after confirmation; preserve delivery/join failures and block retries after restart-required failure. Settings retains prior selection until success; scope/model exclusion remains enforced. Disk save may succeed before refresh fails → restart required.
- Panel saves occur asynchronously after primary input reduction: one worker plus one replaceable latest layout. Shutdown joins old write before queued save; side input/focus/scroll cannot alter preferences. Report errors without reverting visible panels.
- Session maintenance validates captured generation and cannot reopen closed picker. Prune separates from prompt/switch admission; retain report if subsequent list fails. Scope switches preserve global/project separation and bounded/sanitized status.
- Update keeps one timeout-bounded result outside queue; `/update` requests idle restart, never Cargo work in loop or a restart-held session lease.
- Quota uses one join-result worker including stored-auth checks, activity-gated HTTP at five minutes; `/usage` shares pending work. Match final request account, not token revision; clear stale indicators on account change/logout/invalidation/failure.