Maka v0.1.6 already ships a quote companion that forks the active Session at its latest completed turn, inherits the model, workspace context, and permission profile, hides it from the conversation list, and removes it when the panel closes.
The generic side-conversation entry extends that foundation:
/side opens an empty side chat, while /side <prompt> creates a titled side chat and sends the prompt as its first turn;/ suggestion layer exposes Side with its icon and description; selecting it executes the command and removes the query instead of creating a fake Skill token;mode:side_conversation label, which adds a system boundary declaring inherited parent history reference-only;/ Skill discovery, @ file references, files, quotes, and draft ownership with the main Composer;Codex implements /side as an ephemeral thread fork.
The TUI uses thread/fork with excludeTurns, injects a hidden boundary item, keeps separate parent/side UI state, and interrupts plus unsubscribes the side thread during cleanup. The Desktop app marks the fork as a sideConversation, opens it in a sidechat:<thread-id> right-panel tab, excludes it from recent conversation surfaces, and confirms before permanently closing a non-empty temporary chat.
Primary references:
openai/codex#18190 introduced /side.openai/codex#34198 stopped replaying inherited turns in the side UI.openai/codex#35011 kept a side conversation open while toggling to its parent.openai/codex#35887 moved interrupt/unsubscribe cleanup to the background.The current local Codex Desktop snapshot inspected on 2026-08-06 is app build 26.730.61639 (bundle build 6234, packaged on 2026-08-05). Its side chat is a tab type inside a generic application-shell panel system, not a dedicated drawer.
The shell creates independent right and bottom tab controllers. Each controller owns:
moveTabTo / receiveMovedTab;Closing an active tab does not merely choose the next array item. The controller tracks opener relationships and recent activation so a child tab can return to its opener before falling back to an adjacent tab.
The persisted layout is a topology snapshot containing right and bottom tab order, active ids, open state, focus area, full-width state, and restorable routes. Preview tabs are excluded. Browser tabs additionally persist browser storage ids, restore URLs, device-toolbar state, and target panel.
The New Tab page is therefore a registry surface over available tab types (Review, Terminal, Browser, Files, Side chat, and feature-gated additions), not a fixed menu wired to the side-chat feature.
Codex installs a non-closable sidechat-loading:<parent>:<index> tab, forks the latest parent state, then swaps in sidechat:<conversation-id>.
Maka diverges from that eager loading contract: opening a side chat installs a normal sidechat:<conversation-id> tab whose Composer is usable immediately — there is no loading tab or preparation spinner, and the tab is closeable, draggable, and reorderable from the start. The fork is created lazily on the first send: it branches from the latest settled parent turn when one exists, or forks with an empty context (inheriting the parent‘s model, cwd, and permission but no transcript, and no in-progress Todo) when the parent has not completed a turn yet. Opening the panel never depends on the parent’s turn state, and no mid-flight turn is ever copied.
The fork is marked both ephemeral and side-conversation, excluded from recent conversation surfaces, and receives a developer boundary that:
A side-chat tab can move between right and bottom panels. Closing a non-empty temporary side chat runs an onBeforeClose confirmation (with a persisted “don't ask again” preference), then discards the conversation from cache in its close hook. Existing retained side chats can instead resume and opt into preserveOnClose.
The panel visibility controller deliberately distinguishes hiding, closing, and moving:
The inspected right and bottom visibility atoms default to closed and are not backed by a localStorage preference. Tab and route restoration are separate mechanisms from whether the panel is currently visible.
The current product still has known recovery and focus gaps. Open upstream reports cover unrecoverable closed chats, expiration after inactivity, focus switching between the main and side composers, and crashes involving multiple side chats plus Browser tabs. Maka should not copy those failure modes merely for visual parity.
The inspected Desktop bundle registers a Composer slash command with id side. Its parser accepts only /side or /side <prompt>. A non-empty prompt is sanitized into the tab title and sent as the first side turn. The command is unavailable inside a side chat and before the parent conversation exists. The current Desktop bundle does not register /btw; that alias belongs to other Codex surfaces.
The same Codex build uses a real xterm surface rather than a command field over terminal result cards. The renderer loads xterm, FitAddon, WebLinksAddon, and ClipboardAddon. Every terminal owns a stable session id and is represented by a dynamic terminal:<session-id> tab with a durable route carrying cwd, host id, and session id.
The renderer does not own the process. A singleton terminal controller owns:
The main process owns local node-pty and remote process-session backends. It enforces window ownership, creates or attaches sessions, streams raw data, resizes, writes, closes, and retains a bounded replay buffer. Moving a tab between right and bottom panels remounts or relocates the xterm view while the PTY remains under the same main-process session. Closing the tab closes the session. Opening another Terminal creates another PTY and another dynamic tab.
Dynamic verification matched the static chain: opening right and bottom Terminals in the inspected build created two direct child login shells on different PTYs. Both surfaces remained live simultaneously.
Codex uses one fixed diff tab whose source changes inside the panel. It is not an aggregation of tool-result messages. The Review model issues Git queries against repository snapshots and supports:
review-diff requests with snapshot generations and stale snapshot rejection;Last Turn can aggregate changes across all repositories. Git-backed sources can be disabled independently, while Last Turn remains available from conversation diff state. Maka's existing ToolResultPreview remains a good renderer to reuse, but persisted file_diff tool results are not an equivalent data authority.
| Boundary | Codex | Maka |
|---|---|---|
| Entry | /side, keyboard shortcut, Desktop actions | /side, titlebar, command palette, keyboard shortcut, and selected-text actions |
| Initial transcript | parent history hidden | parent history hidden; only side turns render |
| Parent history | reference-only developer instruction plus hidden boundary | reference-only system prompt from the side label |
| Tool policy | read-mostly guidance; explicit side requests may mutate under the active permission profile | inherited permission profile; only explicit side-chat requests are active |
| Lifetime | temporary, with Desktop confirmation and some retained-tab behavior | temporary; close deletes the fork with durable cleanup recovery |
| Conversation list | suppressed | suppressed |
| Recovery | expired/closed side chats are not reliably recoverable | intentionally not recoverable; cleanup is reliable |
Maka now has the first usable slice of the same architecture:
file_diff results, through the same highlighted diff renderer;terminal:<ref> multi-tab surface backed by xterm and FitAddon;side, btw, 侧聊, and 追问 search terms;/side and /side <prompt> handling with automatic first-turn send and a prompt-derived transient tab title;Maka now also mirrors Codex‘s panel transition rules: hiding preserves live tabs, closing the final tab closes that panel, moving the final tab leaves the source panel on New Tab, and selected text reuses right-side chats before bottom-side chats. Maka intentionally continues persisting general workbar visibility across restarts; Codex’s inspected visibility atoms are in-memory.
The first Side Chat steering implementation delivered inserted text correctly but projected it incorrectly. A steering_message shares the active turn id with the original prompt. The settled turn projection stored only one turn.user, so the later steering row replaced the prompt; the live projection also ignored steering_message, leaving the inserted text invisible until settlement.
Turns now preserve their first user row as the prompt and project later same-turn user rows as userInterjections. The live projection adds a steering interjection as soon as Runtime acknowledges it, and the settled overlay deduplicates that optimistic row by message id. The Side Chat regression test requires both user bubbles to appear immediately after insertion and to remain after the assistant response settles. Because the fix lives in the shared turn projection, the main conversation gets the same behavior.
The renderer production build remains split at the workbar boundary. After the panel-lifecycle changes, direct gzip -9 measurement reported 22,237 bytes for the session-workbar chunk and 75,703 bytes for the main index chunk, both slightly below the previous 22,260-byte and 75,801-byte snapshots.
It does not yet have general durable route restoration or retained side-chat recovery after leaving the owning session. Terminal launch remains local and deliberately narrow: the renderer can request a login shell for the current Session, but cannot yet choose a remote host, arbitrary launch command, or cwd. Review still lacks commit-source browsing, hunk-level actions, filesystem watching, and multi-repository aggregation.
The visual shell is low-to-medium difficulty. Full controller parity is a separate medium-to-high effort because it changes ownership, persistence, focus, and cleanup behavior across every workbar surface.
The panel shell was checked in light and dark themes at 320px, approximately 480px, 600px, and in the bottom placement. Two layout bugs found during that pass were fixed at their ownership boundaries:
The side Composer receives focus as soon as the panel opens (no preparation status, since there is no eager fork). The empty transcript shows the same blank state as an ordinary chat. An interrupted development process was also restarted against the same workspace to verify that its orphaned fork was removed before the session list rendered.
The latest visual pass covered the dark command palette, the dark right-panel and light bottom-panel states. A newly opened side chat shows a normal, closeable tab immediately — there is no separate loading tab or busy footprint.
The active-turn pass confirms that Side Chat changes only its tab icon to a spinner while processing. The close affordance remains available during a turn, then the normal Side Chat icon returns without changing the tab title or layout footprint.
The /side <prompt> visual pass additionally confirms that the command never appears in the parent transcript, the prompt is sent in the side transcript, and the tab uses the prompt as its ellipsized title with the full title available on hover.
One real-model failure found during the final dev-app check had two independent causes:
sha256 and bytes query parameters; Nemotron copied the artifact id and hash into its ArchiveRead call but dropped the second query parameter, so the strict parser returned invalid_ref;Archive refs now encode artifact id, hash, and byte length as path segments, while the parser still accepts the old query form for persisted compatibility. Side forks now inherit only through the latest successfully completed parent turn and start empty when no completed turn exists. A live Nemotron validation read one 10,982-character archived result in three successful pages, and a new side chat opened over an aborted parent turn answered 你好 directly without calling Glob, Read, or ArchiveRead.
The slash-suggestion pass confirms that /si renders a single Side command above the Composer with the normal Side Chat icon and explanatory secondary text. Keyboard selection clears the query and opens an empty side chat.
Measured performance checks on the implemented surfaces:
/side, slash suggestion, dynamic-title, and tab-icon polish added about 0.70KB gzip to the main renderer chunk and about 0.28KB gzip to the lazy workbar chunk in the measured production build.session-workbar chunk from 120,835 bytes gzip to 21,832 bytes gzip, approximately 82%. Terminal is now an 86,747-byte on-demand chunk, Files is 7,756 bytes, and Review, Browser, and Trace are independent 2.4-4.3KB chunks. The main index chunk moved from 75,717 to 75,941 bytes gzip, an increase of 224 bytes.The 19-test workbar interaction suite covers Side Chat, slash and command palette entry, Review, Terminal, tab reordering, panel movement, persistence, and the 320px layout. The shared UI suite passes 432 tests, and the 13-test Skill/mention E2E set confirms that adding Side to the / menu did not change Skill token or draft behavior. Full Runtime and Desktop suites can expose timing-sensitive child-process tests under sustained machine load; every such failure observed in this pass succeeded when rerun in isolation.
Follow-up work continues to preserve the lifecycle and authority boundaries documented above. Its status and decomposition live in the tracker so this design does not become a second checklist.
Tracking: Side Conversation follow-ups #4331