01. UI Information Architecture
Language: English (per ADR 0009). This describes the shipped Codex-aligned shell (D034+). Component detail: 08-component-spec; visual tokens: 07-ui-design-system; behavior: 09-interaction-patterns.
1. Goal
A clear, restrained, developer-first workbench: one window, one active destination, chat as the home surface, tools and permissions inline.
2. Shell regions
+----------------------------------------------------------------------+
| Platform titlebar: macOS traffic lights / Windows/Linux actions |
+------------------+--------------------------------+------------------+
| Sidebar (275px) | Main pane (active destination) | Work panel |
| | chat home / transcript | (optional, |
| | or Extensions page | resizable |
| | | ≥244px, dynamic|
| Sessions +↕ | | surface |
| Recent rows ↕ | | |
| Projects + | | ◫ | App.tsx ⌄ × |
| Project A | | > | |
| Project B | | ◎ | Active |
| Footer [⚙][plug][☾][bell] | Floating composer (chat) | | resource |
+------------------+--------------------------------+------------------+- Sidebar: primary navigation — path-less conversations under a compact Sessions section with new-session and sort actions, retained open-project groups under a following Projects section with a persistent new-project action, and the WorkBuddy-inspired footer. The footer keeps compact Settings, Extensions, Scheduled (clock), and notification icon actions. Each retained project is a path-keyed tab/group that can be collapsed independently. Project and conversation rows expose non-destructive pin/archive actions, an independent conversation-branch command, and sortable views. Projects not retained in the sidebar remain discoverable through Settings → Project archive. Collapsible to an icon rail (Cmd/Ctrl+B). Its expanded column is user-resizable from 240px to 520px (default 275px); dragging below 160px collapses it.
- Product identity: runtime shell copy uses
Nib; the home hero and sidebar reuse the derivedsrc/assets/brand/logo-*.pngmarks, while composer prompt rows have no leading brand icon and session-creation controls use a dedicated message-plus icon. On Windows/Linux, the expanded sidebar begins with a keyboard-accessible Home brand and Collapse sidebar at the right; activating the brand returns the main pane to chat. The macOS expanded sidebar omits the logo/title brand and places only Collapse sidebar at the right of the traffic-light row.Codexremains only an external import source or a design-reference term. - Main pane: exactly one destination at a time; destinations replace the pane (they are pages, not modals). Once Settings or Extensions is selected, bootstrap completion and background refreshes must not replace that destination with the chat home; only an explicit navigation action may do so. The outer pane stays fluid while the sidebar is collapsed. The centered chat content band defaults to 760px and is user-resizable (D439); it compresses with
min(available pane, preferred)instead of tightening to a 640px ceiling. - Titlebar: platform-native desktop chrome (D118). macOS uses
hiddenInsettraffic lights and the system application menu. The expanded sidebar keeps Collapse sidebar in the same 46px row, aligned to the right outside the traffic-light safety area; no logo/title is rendered there, including in fullscreen. When the work panel is open, native window controls stay viewport-fixed at the window's right edge and the panel header reserves that band plus the work-panel toggle. The panel header is a horizontally scrollable tab strip followed by a fixed+add trigger; tab close actions stay in the tabs, so the Windows native close control is not visually duplicated by a second header×. Windows/Linux use a menu-free frameless 46px row with sidebar actions on the left and accessible minimize / maximize-or-restore / close controls at the right edge of the conversation pane when the panel is closed (D129). When the work panel is open, those controls stay viewport-fixed over the panel header rather than travelling with MainPane. One window-level control band stays outside pane stacking contexts across panel open, preview, restore, and Settings transitions. Its background follows the adjacent titlebar surface (dock header when open, conversation surface when closed) in both themes. Boot splash, search, and toasts stay above that band. Preview navigation must also remain above the panel; macOS keeps native traffic lights and its existing fullscreen insets. Destination history is shortcut-first (Cmd/Ctrl+[andCmd/Ctrl+]) with no dedicated back/forward chrome; while Extensions is active, the footer Plugins button performs one Back step as the only pointer affordance. The main titlebar has no notification action; the durable local inbox opens from the sidebar footer bell instead (D130/D117). In work-panel preview mode, MainChat is unmounted and a window-level 46px chrome row keeps New Task, sidebar, and native window controls available without owning a drag or no-drag rectangle across the panel. The panel header alone owns dragging in the preview pane; its actual border box starts after the shell action lane plus an 8px gap, including the expanded-sidebar New Task button, on every platform. The left inset is 8px, or 88px for collapsed-sidebar windowed macOS. Its right native-control exclusion is unchanged. Header paint fills the excluded lane without an opaque overlay hiding tabs or panel actions. The macOS inset uses the shared--ds-window-lead-insettoken — the cluster's 76px right edge (from@pi-desktop/shared) plus a 12px gap — and the main process positions the buttons from that same shared geometry. - Work panel: docked right column (not an overlay) opened by an artifact, the viewport-fixed toggle, or
Cmd/Ctrl + J. File, URL, browser-preview, and successful workspace-edit artifacts create their resources atomically. The 46px content header exposes a tablist and a fixed+trigger. Unused tab-strip space remains a native window drag region; individual tabs and header actions are no-drag so selection, closing, and reordering still work. Its tokenized 44px right-side safe lane (the 28px control, its 12px viewport inset, and the header's 4px control gap) keeps the+, maximize, and viewport-fixed work-panel toggle one button group, spaced by that same gap, while the trigger keeps a distinct hit target. Clicking+creates and activates a unique New launcher tab; its body presents the same data-driven Review and plugin-view rows as buttons, so the user chooses a destination in the page instead of opening a dropdown. Selecting a row replaces that launcher tab with the destination or activates an existing singleton. File paths stay distinct while plugin views deduplicate by view reference. The viewport-fixed toggle andCmd/Ctrl + Jboth toggle the active session's retained panel context — revealing it without creating a resource tab and collapsing it without discarding one; the create trigger remains unavailable while the panel is closed. Closing the final tab keeps the panel open and shows the New launcher. No agent or tool result opens, activates, or resizes the panel: Review is reached only through an explicit user action, so a successful workspace Write/Edit leaves the panel exactly as the user left it and shows its evidence as a transcript card instead. The inner divider resizes the panel through the shared three-column budget; moving it left takes space until MainChat reaches 450px, at which point the expanded sidebar yields immediately, and moving it right gives space back. A manual sidebar reopen spends work-panel width first and otherwise targets a 460px MainChat width, without changing the stored panel width, which returns when the sidebar collapses again. The sole panel-level control is the viewport-fixed toggle; each session retains its own runtime open state, tab set, active tab, and Browser resource in renderer memory. Selecting another session swaps the visible panel context without deleting either session's state; selecting a workspace without an active conversation hides the panel rather than reinterpreting relative resources. Background artifacts update only their originating session's retained panel context and never open, activate, or resize the visible panel. Startup is closed with no retained session contexts, and only the preferred panel width persists across launches. The work panel remains a fixed-width in-flow column beside MainChat inside the existing client area (ADR 0033 / ADR 0151). MainChat keeps a hard 450px minimum; the work panel's effective maximum is the remaining client width after the expanded sidebar and that floor (ADR 0238). When the budget is exhausted the sidebar collapses immediately through its existing animation (the budget still counts it whilesidebar-outoccupies flex space) and returns when the panel closes. Opening and collapsing change only the shell's internal flex allocation and never expand or shrink native window bounds; no panel action requests a positive native reservation. The panel-header preview toggle temporarily unmounts MainChat and expands the panel across the client area beside the sidebar; leaving preview restores the prior panel width and sidebar state without changing native bounds. The renderer-measured panel rectangle continues to position the native Browser view. Window edges resize the app window only; they do not change the panel target. The outer window remains natively resizable from all OS edges and corners, including Electron's frameless hit regions on Windows, with a minimum supported size of 800×560, capped to the current display's work area (D635). Replaces the former context-panel overlay; workspace/model/status info lives in the composer chips and Settings instead. - Composer: workspace-agnostic floating pill anchored to the conversation destination — centered empty-home content above a bottom-reserved composer (D111/D204/D206), bottom-docked in a transcript, with no project / Local / branch rail (D095). Its left-of-input operating-mode chip is the sole active-session control for Agent, Plan, and Goal. Plan shows the same Agent's planning state; Goal shows the same approval boundary for an outcome contract. Both keep the permission-mode chip and expose their host-written immutable
.pi/plan/*.mdor.pi/goal/*.mdartifact opener after submission. The conversation top bar retains only the task title and window actions; the Composer owns model and reasoning selection as well as mode control. - Backend status capsule: appears under the titlebar while the backend restarts or is fatally degraded (D080), with an Open-logs action.
3. Destinations
3.1 Chat home (default)
- Empty state: a restrained hero title ("What can I help you build?" — an open project turns its name into a dotted-underline switcher that lists the sidebar's open projects, can search them, can clone a git repository from a syntactically public remote (ADR 0247 / D416), and can open another local folder or a remote project on a connected host), an optional first-run checklist, and a bottom-reserved composer. Task entry starts directly in the composer; no redundant supporting paragraph, developer starter cards, or contextual quick-action row is rendered (D204/D206).
- Create project uses one dialog with local folder, Git, and remote host sources. The project name is editable for every source and remains locally managed. Remote selection chooses a connected host and an absolute directory, without a Host project catalog; Settings → Remote Hosts opens the same dialog with the clicked host preselected. Browse opens a separate directory dialog with path entry, parent navigation, directory rows and explicit confirmation. Cancel returns to the project form and restores focus; stale host responses cannot replace the current selection. The same sidebar, switcher, archive and chat workflow manage created projects. Model choices and requests use local settings; remote machines execute admitted workspace tools only. Actual remote paths are display/execution data, never local filesystem activation paths.
- With transcript: message stream + tool disclosure rows (D071), a contextual message-scoped review card immediately after each successful workspace Write/Edit row, docked composer, and a session-scoped permission card inline. The card reads the message's durable review snapshot rather than the current Git diff, so it stays visible after commit. It shows the file status and addition/deletion counts, expands the exact message hunks in place, and offers guarded rollback; it is not a global transcript entry. A background session's message, tool, and permission events never replace or cover the visible conversation.
3.2 Sidebar project groups
- Sections: the compact
Sessionsheading precedesProjectsand owns path-less conversation creation plus the existing sort/archive-view menu. Its toolbar places sorting before new-session creation. Both headings keep quiet glyph actions and also accept a right-click create menu on the heading or empty list chrome so section creation stays discoverable without extra chrome. Its list shows at most five compact rows (146px) before scrolling internally, so standalone work stays visible without displacing project navigation. The followingProjectsheading exposes the folder-picker action; retained project groups use the remaining height and scroll independently. - Identity: each project group is keyed by a host-owned logical group id; each root path remains canonical and is never inferred from an ambiguous folder basename. Legacy single-folder projects are compatibility groups.
- Header: project name, current-workspace dot, disclosure, new-task action, and an overflow menu. Workspace context is not navigation selection: project headers have no persistent selected background, including when no conversation is selected. Only the current conversation on the chat page receives selected row paint. Project and conversation rows share full-row hover feedback; the project title itself stays transparent. The directory title is one full-row disclosure target; collapse/expand affects only child visibility, and adjacent groups form one dense tree rather than detached cards. Hovering or focusing the project title reveals the full project path. Pressing the title and moving 8px reorders the group.
- Running activity: a project group whose sessions have live work marks that fact on its header, because a collapsed group folds its body to a zero-height
inertregion and would otherwise hide every row-level status dot exactly when the answer is most useful. Two independent affordances share one amber--ds-warningvocabulary (a pending permission keeps the purple--ds-purpleused by the conversation row):- a count badge after the project name, showing running and permission-waiting counts as separate capsules so the two figures are never read as one number;
- an activity rail: a 2px track down the group's left edge with a travelling pulse, spanning the opened conversation list and shrinking to the header while the group is collapsed, plus a matching count. Remote host groups carry the same pair. Settings → General → Sidebar owns one master switch (
AppSettings.sidebarRunningIndicators) gating two sub-switches (sidebarRunningBadge,sidebarRunningRail). When unset, the master and Count badge resolve on while Activity rail resolves off; explicit saved values remain authoritative. The master gates both affordances, and turning it off leaves the saved sub-switch choices intact. No settings migration is required. Motion is decoration only:prefers-reduced-motionkeeps both static shapes legible with the animation removed.
- Project actions: open folder reveals the primary project directory; Edit project changes the host-owned logical group name and adjusts eligible non-primary roots (keeping renderer metadata in sync); pin/unpin changes presentation priority; archive/restore hides or restores the group in the default view; close removes the retained primary tab without deleting or archiving group roots, sessions, or memory. Expanded Project archive details list every group root.
- Conversation actions: rename, pin/unpin, archive/restore, fork, and delete remain separate actions. Rename edits the task label only; archive never removes the transcript. Open folder is a project action, not a conversation action.
- Isolated sessions (ADR 0329): the project menu offers New isolated session. Opening the menu probes the project: the item stays disabled until the answer arrives, and for an unsuitable project (not git, no commits, detached
HEAD, missing or old git) it stays disabled with the reason shown under it. Creating probes again; a dirty project gets an info toast that uncommitted changes are not included. The menu also holds Worktree setup command…. An isolated row shows anIsolatedbadge (orConflict,Folder missing,Setup failed) and adds Merge into project… (preview of commits and files, then merge; conflicting files are listed and stay in the session; theConflictbadge clears as soon as the session resolves or abandons the conflict, and the next merge concludes it), Sync from project (labelled with the number of new project commits when the menu opens, disabled when there are none or while the session is conflicted, which also hides the↓Nmarker; it merges the project's branch into the session so the session continues on current code, and a conflict stays in the session like a merge conflict; a row that lacks project commits shows a↓Nmarker next to its badge, read in the background when isolated sessions change, after a merge or sync, and on window focus at most every 15 seconds, so rendering the list never waits for git), Show worktree folder, and Setup log. Its delete confirmation states that unmerged work will be lost. Isolated sessions are never reused as the empty draft and cannot move to another project; forks are ordinary sessions. - Temporary-task attachments: selecting a saved attachment opens its file preview even without an open project. Back returns to the no-project browsing state. Branches preserve referenced pasted/imported inputs as child-owned copies; deleting the source task does not break these previews.
- Sort: user-facing modes are Recently updated, Created date, Oldest first, and Name. Pinned rows precede unpinned rows. Project groups switch to
manualby dragging a title or using ArrowUp/ArrowDown on that title. Sessionmanualremains a compatibility value. - Conversation list: each project group shows the ten most-recent sessions in the active sort order by default; the remainder folds behind a Load N more… row. The list has no time-group headings. Rows show the title and a localized last-reply age through seven calendar days, then a concrete date; hovering or focusing a row replaces the date with its session actions. Pinned rows precede unpinned rows and are never pushed behind the fold; expansion is not persisted.
- Standalone sessions: path-less sessions remain in the separate Sessions section and never inherit the last active project's workspace.
- Concurrency: the shell selects one visible project at a time, while agent run state remains keyed by session. Switching project tabs does not cancel a background turn. Background events update only their originating session and never change the active session, page, project, or keyboard focus.
3.3 Scheduled
A task column beside the selected task's page, with an explicit create/edit form, a cadence dropdown, time, next occurrence, saved project, per-task permission/model selection, a per-task conversation mode (a new conversation per run, or one conversation every run continues), pause/resume and delete confirmation. Hourly schedules repeat at one-hour intervals without a time selector. An interval schedule states its own span as a count with a minute or hour unit (5 minutes to 24 hours) and counts elapsed time from the moment it was armed. Daily schedules use a themed time-period dropdown: Morning 09:00, Afternoon 14:00, Evening 19:00, Night 22:00. The form does not expose hour/minute editing. AI tools may set an exact time; a non-preset time displays as Custom with its HH:mm value and survives other form edits until the user explicitly selects a preset. Weekly schedules select one or more weekdays (Monday = 0) in a separate dropdown listing Monday through Sunday with selection markers. Each day toggles independently; there are no preset combinations. An empty selection disables saving. The menu supports arrows, Home/End, Enter/Space, Escape/outside dismissal, exposes selected states, and owns the page while it is open: the task column and the task page step aside rather than compete with the draft. The form also states an interval as a count with a minute or hour unit (5 minutes to 24 hours) and keeps that value while another cadence is selected, so switching a task between a calendar and an interval loses neither. The column reports each task's cadence and clock, the outcome of that task's own newest run — read per task from the host, so a task that has been idle while others ran is never reported as never run — with its duration, and whether it is paused or running. The task page shows that task's last run, next occurrence, project, permission and model, its instruction behind a disclosure, its own run history newest first (status, start time, duration, stable error code), and the transcript of the selected run read in the page through a bounded read. A run's transcript belongs to this route: the SessionList and global session search never list it, and Open conversation is the explicit action that carries it into the chat route, and the chat top bar then offers that conversation's own way back: the row names the task it belongs to, and returning restores the same task and the same run, reusing the navigation history when this route is directly behind it. The footer clock and global search open this route. Run now dispatches in the background, selects the run it admitted, and leaves the reader on this page. Automatic runs never steal foreground focus. See desktop automations.
The application must remain running. The host polls every 30 seconds and skips occurrences more than 90 seconds late or overlapping a running task. Startup rearms future occurrences only. Hourly schedules wait a full hour after saving, enabling, startup or the preceding automatic admission; Run now leaves the automatic occurrence unchanged. Legacy cadence-only tasks require explicit schedule configuration. New tasks explicitly save the selected project, Ask permission mode and the current default provider/model. Each selector writes only to that task. The prompt is labelled Instruction, and these three selectors sit inside its bottom toolbar using the same shell, chip and anchored-menu treatment as the main Composer. Both surfaces render the same controlled permission picker and searchable, provider-grouped model list with capability badges. The task model chip displays the model name or alias without a provider prefix. Task selection callbacks update only the task draft, never the active conversation or app defaults. The instruction input has its own rounded border and tonal background above the toolbar, with no native resize handle; longer text scrolls inside the input. Existing tasks without provider/model fields continue following the app defaults; unavailable saved models remain visible and are not silently replaced. Selecting Auto warns that restricted actions may run without asking. The current project is captured when first configured when no explicit selection exists; subsequent foreground project changes do not retarget it. This includes Manual tasks and tasks saved without a project: Run now, renaming, and cadence changes preserve that binding, including after restart. Only legacy tasks without a saved binding capture the current project on their first explicit configuration. Legacy automatic runs without a saved permission mode use Ask and may wait for input in their conversation. New tasks default to Agent. A migrated Plan or Goal task is allowed to remain stored, but an unattended run is explicitly rejected before provider, artifact, or queue work with PLAN_REQUIRES_INTERACTIVE_SESSION; it cannot display or auto-approve a contract. The user must explicitly switch it to Agent before enabling unattended execution.
Agent tools can change a Manual task to Hourly by supplying only its id and cadence: "hourly"; no calendar time is required. Preserve existing schedule fields and paused state. Daily and Weekly still require a valid saved or supplied schedule. Renaming an Hourly task does not restart its interval.
3.4 Extensions
The Extensions destination is a focused plugin surface with a compact header and only two tabs: Installed and Marketplace. Installed groups plugin cards by state — Needs attention / Updates available / Active / Turned off — as soft tiles in an auto-filling card grid under a group label (D296). Marketplace remains the browse/install card grid and always uses the official catalog. Public ratings and reviews are read-only here: cards carry a rating chip, the detail sheet carries a ratings summary, and a review drawer opens over the sheet; writing a review is a link out to the plugin centre's own page. The page draws no dividers: header, toolbar, cards and the detail sheet's sections are set apart by tone and spacing, and hairlines are reserved for floating layers (menus, sheet, dialogs). MCP, Skills, and Subagents are not tabs or sections of Extensions.
3.5 Settings (full-page takeover)
3.5 Settings (full-page takeover)
Settings replaces the whole shell (D063): back-to-app + search + a grouped settings rail with concise, parallel destination labels. The Agent group contains independent Skills, MCP, and Subagents destinations alongside Instructions and Model configuration; selecting one changes the page destination rather than a tab inside a shared capability panel. Appearance lives inside General; global AI behavior (permissions and context management) lives inside 全局 AI; keyboard shortcuts and global/project instructions have their own destinations; provider management lives inside Model configuration. Models, Skills, and MCP each open their external-store import workbench inline within the owning Settings destination; scans start only when the user asks. Skills and MCP imports follow the current Global / Project filter and selected project. Session import is provided through the plugin API rather than a Settings destination. Project archive owns the durable D086 Projects index (search, add, expand, pin, archive/restore, close, and reopen) and always includes archived records. Opening or switching a project retains a sidebar tab, selects that project as the active workspace, and returns to chat. Other retained tabs stay open. Extension management remains solely on the app shell's independent Extensions destination described in §3.4. Settings > Agent has the following shared capability contract:
- Each capability destination starts with a quiet localized description and scope note, then uses the same neutral elevated Settings surface as the other destinations; no capability page has a decorative hero, colored top bar, or separate visual theme.
- Skills and MCP use one list filtered by Global / Project in a shared toolbar. The toolbar has a project picker and the current filter determines which capability rows and creation/import destination are active.
- Skills keep native file and folder import actions in each level group and provide Scan other tools in the page toolbar. External skill imports use the active filter and preserve the selected project's scope.
- MCP has one Add action per surface. Add and Edit open the existing
McpEditorSheetas a modal overlay with stdio/HTTP branches, validation, duplicate checks, locked edit ids, scope text, and Test connection feedback. Scan other tools opens the external MCP workbench inline and uses the active Global / Project filter and selected project for its import target. - Subagents use one full-width global surface under
~/.agents/subagents; they have no project picker, project surface, or project-level toggle. Creating or editing a subagent picks the pinned model from configured provider models, or inherits the session model; it does not require typing aprovider/modelid. - All three lists flow at natural page height, render a quiet centered empty state inside the panel, dim disabled rows, and store enablement in app-local state rather than capability files. Loading and project changes render skeleton rows with the same anatomy and disable competing controls until the host refresh completes.
4. Overlays
| Overlay | Trigger | Notes |
|---|---|---|
| Command palette | Cmd/Ctrl+K (also Cmd/Ctrl+Shift+P per D014) | builtin + plugin commands |
| Model menu | Composer-right model × reasoning chip | configured provider/model choices + settings entry (D091) |
| Profile menu | sidebar footer | Settings / Logs / Theme cycle (D041) |
| Notification inbox | sidebar footer bell | All/Unread views, task failure rows only (successful completions are hidden, D295), mark-all-read and clear actions (D130/D117) |
| Toasts | events (plugin toast, backend restored, copy) | top-center of the live main-content safe area; viewport fallback; 4s default, 8s for errors |
| Project switcher | empty-home underlined project name | sidebar open projects + search + clone git project + open project |
5. Navigation model
pagestate:chat | scheduled | plugins | settings;chatis the conversation-surface route, not an operating mode. The project archive is theprojectssettings tab rather than a standalone page.- Destination history is linear;
Cmd/Ctrl+[andCmd/Ctrl+]traverse it without persistent back/forward chrome. While Extensions is active, the footer Plugins button reuses one Back step (§2 shell regions); no separate back or forward control is added. - Selecting a project tab reuses
project.setwhen its path differs from the selected host workspace and keeps the other tabs retained. - Selecting a project-scoped thread activates its project before switching to
chat. Selecting a temporary thread clears the visible active workspace before loading it. - Empty home has four explicit session states: a project-bound session shows the project-underlined welcome; clicking the name opens a searchable switcher of the sidebar's open projects instead of the folder picker. An open project with no session yet names the hero the same way, because that empty home already belongs to it and a task started there lands in the project. A temporary session shows dedicated temporary-chat copy with no project underline or switcher; and with no project open the generic welcome title stands.
- New task resolves the current project or temporary group by its most recent session: if that session has
messageCount = 0, it is selected and reused; otherwise a durable empty session is created immediately and appears in the sidebar. Repeated clicks therefore keep one empty slot per visible group; an empty slot remains persisted until the user deletes or archives it.
6. Keyboard map (IA level)
| Keys | Action |
|---|---|
| Cmd/Ctrl+K, Cmd/Ctrl+Shift+P | command palette |
| Cmd/Ctrl+B | toggle sidebar |
| Cmd/Ctrl+[ | previous destination |
| Cmd/Ctrl+] | next destination |
| Cmd/Ctrl+N | new task |
| Cmd/Ctrl+O | open project |
| Cmd/Ctrl+, | settings |
| Cmd/Ctrl+. | abort current run |
| Enter / Shift+Enter / Cmd/Ctrl+Enter | send / newline (Enter-to-send; when off, Cmd/Ctrl+Enter sends) |
| Esc | dismiss overlay/menu |
7. State-dependent chrome
- No provider configured → blocking guidance toward Settings before first run (
MODEL_NOT_CONFIGURED). - No workspace → home hero without project underline. The Composer never renders a workspace rail.
- Background project session → the originating project row retains its running/error indicator. Selected shell state can move independently while the session tool root remains bound to its durable project; its artifacts are retained in that session's work-panel context without opening or activating tabs over the currently selected project. Messages, tool events, permission requests, and panel resources remain scoped to that session. Explicitly opening the conversation restores its retained panel context and reveals any pending permission card, which remains actionable without a deadline.
- Completed/failed turn not already visible → host-core appends one durable inbox row. A result shown in the visible, focused current chat and every
abortedturn append none. Background sessions and any turn finishing while the window is unfocused still append. The sidebar footer bell lists onlytask.failedrows and its badge counts only unread failures; successful completions stay in the durable record for the sidebar outcome badge and native notification but never appear in the inbox (D295). Selecting a row marks it read and activates its bound project/session. Electron additionally presents a native task notification only when the app window is unfocused, and clicking it focuses the window before activating the same session (D117). Interactive ask/permission/plan prompts use their separate native path and may alert for a focused background session. Receiving either durable or native notification events never navigates by itself; only explicit activation does. - Backend degraded → status capsule (restarting) or fatal banner with Open logs (D080); composer submits are rejected with readable errors while down.
- Plan/Goal checkpoint → the originating session shows only the structured title and an opener for its immutable
.pi/plan/*.mdartifact. The renderer retains the latest proposal/execution snapshot per session only for the current renderer lifetime, updated by live Host events; only a livependingrow forms the approval gate. Reload throughplans.pendingwhile the same Host remains alive restores a still-pending row with its original deadline. Rejected, expired, approved/completed, and interrupted terminal cards are not rehydrated; a terminal card may remain visible and non-actionable only until renderer reload. Reject, expiry, or interruption clears the approval gate, leaves the session in its contract state and editable, and requires a later turn to create a new artifact. While pending, the draft remains visible but read-only and only Approve or Reject actions are enabled. Host/app restart interrupts prior work before RPC with no replay or stale action; pending unapproved work remains Plan, while already-approved interrupted execution remains Agent. The UI is not required to present that interrupted terminal snapshot after restart.
- Plan/Goal checkpoint → the originating session shows only the structured title and an opener for its immutable
8. i18n
English is the source locale. Shipped translations (zh-CN, zh-TW, Turkish, German, Spanish, French, and Korean) cover shell chrome; labels are asserted by US-UI e2e scenarios. Copy rules live in 02-i18n-english-first.
