Last updated: 2026-05-06
Code baseline: current implementation inpackages/webandpackages/server
Scope: Web UI, embedded server, WebSocket command layer
Reading notes:
- Chapters
1 ~ 7describe the current visible product capabilities, page structures, and user interactions from a product review perspective.- Chapter
8preserves implementation boundaries and excluded scope so unshipped capabilities are not written up as shipped features.- The current code is the source of truth. Do not inherit unlanded items from older PRDs, the README, or historical planning notes.
This document only describes product capabilities that are currently wired, reachable, and interactive in the codebase, including:
- Welcome page, auth page, workspace page, settings page, and 404 page
- The desktop and mobile workspace experiences
- Core capabilities around files, Git, sessions, terminals, notifications, and configuration
- Code state is the source of truth: a component or test existing in the repo does not mean the page-level feature is shipped.
- Page-first structure: describe page goals and interactions first, then state handling, boundaries, and error feedback.
- User-visible capability first: the main body stays in product language whenever possible; implementation facts are consolidated in the appendix.
- For product review, focus on Chapters
2 ~ 7. - To decide whether a capability is actually wired, merely UI, or still blocked by implementation boundaries, focus on Chapter
8.
Coder Studio is an AI coding workspace for self-deployed environments, built around the promise Deploy once, coding everywhere. Users can deploy it on a personal computer, development machine, home server, or cloud host, and then access the same workspace, sessions, terminals, and Git capabilities from a browser on desktop or mobile. Depending on how it is deployed, that access can stay on the same machine, remain inside a LAN, or be exposed externally.
The current implementation brings the following capabilities into one workspace system:
- Open and switch between multiple local workspaces
- Create multiple AI sessions inside one workspace (
Claude/Codex) - View and continue agent sessions through terminal-style interaction
- Browse a file tree, edit text files, and preview image files
- Inspect Git status, diffs, commits, push / pull, and branch switching
- Manage providers, notifications, appearance, and part of shortcut configuration
At the product level, the current version delivers three core values:
- Deploy once, coding everywhere: deploy once and continue coding from any reachable device.
- Bring AI sessions, files, Git, and terminals into one workspace workflow.
- Provide two real, distinct access experiences for desktop and mobile.
| Form factor | Shape | Core characteristics |
|---|---|---|
| Desktop | Wide multi-pane workbench | Top bar + left sidebar + main area + bottom terminal |
| Mobile | Sheet / Dock driven workbench | Top bar + single-session main area + bottom Dock + multiple full-screen Sheets |
Note:
The mobile experience is not a scaled-down desktop layout. It is a separate interaction model centered onDock + Sheet.
| Route | Page | Notes |
|---|---|---|
/ |
Welcome page | Default entry when no reachable workspace is available; also provides workspace open and settings entry |
/login |
Auth page | Frontend login route |
/workspace |
Workspace page | Main workspace; desktop and mobile use different experiences |
/settings |
Settings page | Desktop and mobile share the same capability set, with different navigation structures |
* |
404 page | Displays unmatched paths and provides a return-home action |
| Condition | Shell | Page skeleton |
|---|---|---|
Viewport width > 899px |
Desktop Shell | Top bar, left sidebar, main area, bottom terminal |
Viewport width <= 899px |
Mobile Shell | Top bar, main session area, Dock, full-screen Sheets |
Both shells share:
- The same route system
- The same workspace / session / terminal data
- The same global capabilities, such as Quick Actions, branch switching, and Toasts
The actual startup flow is:
- Call the auth status endpoint first to determine whether login is required.
- If server-side auth is enabled and the user is not authenticated:
- Stay inside the auth flow
- Do not continue restoring the workspace view
- If the user is already authenticated:
- Establish or restore the WebSocket connection
- Fetch the workspace list after the connection is available
- Use the workspace list to decide the default destination:
- If the user is on the home page and at least one workspace exists, automatically enter the workspace page
- If the user is on the workspace page and no workspace remains, automatically return to the home page
- Inside the workspace page, if the current active workspace has not resolved yet:
- Show a loading placeholder
- Show an error placeholder if resolution fails
All pages share one connection-state feedback model:
connected: no connection bannerconnecting: no banner; wait for completionreconnecting: showReconnecting...disconnected: showConnection lostrejected: showAnother tab is active
When the app is not connected, both the desktop top bar and mobile top bar also show a lightweight connection indicator.
The welcome page is the default entry when there is no workspace currently available to enter. It serves three purposes:
- Open a local workspace
- Enter the settings page
- Explain the product’s core capabilities in a lightweight way
The main content is a centered welcome card. Mobile only adjusts styling, not the information structure. The card always includes:
- Product kicker
- Title
- Description copy
- Primary button:
Open Workspace - Secondary button:
Settings - Divider
- Three feature highlight cards
| Area | Feature | Interaction rules |
|---|---|---|
| Open Workspace button | Open the workspace launcher | Clicking opens the in-app directory browser; this is not the system-native file picker |
| Settings button | Enter settings | Clicking navigates to /settings |
| Feature highlights | Show core capabilities | Currently fixed to three items: Agent-first, Git tools, terminal capabilities |
- The welcome page itself has no complex error state.
- If the app has already resolved at least one workspace, the startup flow usually redirects the user to
/workspace, so the welcome page is not a long-lived state.
The auth page handles the case where the server has password protection enabled.
The auth page reuses the centered-card layout from the welcome page and includes:
- Product kicker
- App title
- Status / explanatory copy
- Status panel
- Password input
- Submit button
After mount, the page decides what to show based on the auth status check result:
| State | Page behavior |
|---|---|
| Auth status is being checked | Show the Connecting state |
| Server auth is disabled | Immediately mark frontend auth as passed, then exit the auth page flow |
| A valid session already exists | Immediately mark frontend auth as passed |
| Service unavailable / request failed | Status panel shows Unavailable / Unable to fetch status |
| Login required | Stay on the page and wait for password input |
| Scenario | Interaction rules |
|---|---|
| Empty input | Submit button is disabled |
| Status check in progress / submit in progress | Submit button is disabled and the button label switches to the connecting state |
| Submit succeeds | Mark frontend auth as passed after login succeeds |
| Wrong password | Show the server error text directly; the current typical copy is Invalid password |
| Temporary lockout triggered | If the server returns a lockout-until timestamp, the page formats and displays that time in the current language |
| Network error | Show network error copy |
- The input type is fixed to
password. - There is currently no
forgot password,switch account, or explicitlogoutflow here. - The auth page itself has no extra shortcut design.
The desktop workspace is the most complete workbench form in the current product. Its goal is to let the user do all of the following inside a single screen:
- Switch workspaces
- Create / close AI sessions
- Browse and edit code
- Inspect and handle Git changes
- Use the shell terminal
The page is divided into four regions:
| Region | Content |
|---|---|
| Top | Workspace top bar |
| Left | Files / Git panel |
| Center | Agent / editor / diff main area |
| Bottom | Terminal panel |
| State | Page behavior |
|---|---|
| Active workspace is still resolving | Show a loading placeholder card |
| Workspace list failed to load | Show an error card |
| Active workspace is empty | Show a No workspace empty state and do not render the full workbench |
| A valid workspace exists | Render the full desktop workspace |
| Feature | Interaction / rules |
|---|---|
| Workspace tab list | Render in the current workspace order |
| Main tab label | Prefer workspace name; otherwise the last path segment; otherwise the full path or id |
| Status dot | Active workspace uses the active style; others use the idle style |
| Unread badge | Show when unreadCount > 0; display 9+ when count is greater than 9 |
| Click tab | Switch the active workspace |
Keyboard Enter / Space |
Also switches when the tab is focused |
| Close button | Close that workspace and remove it from the local list |
Add button + |
Open the workspace launcher |
| Button / area | Behavior |
|---|---|
| Connection status | Only visible when state is not connected |
| Quick Actions | Open / close the command palette |
| Terminal | Show / hide the bottom terminal panel |
| Files | Show / hide the left sidebar |
| Settings | Navigate to /settings |
| Fullscreen | Visible when supported by the browser; toggles fullscreen for the workspace root node |
- If the closed workspace was the last one, frontend workspace state becomes empty.
- Startup logic then detects that
/workspacehas no available workspace and automatically returns to/.
The desktop workspace always consists of three core content blocks:
- Left sidebar: files / Git
- Center main area: sessions / editor / diff
- Bottom panel: terminal
| Area | Default / range |
|---|---|
| Left sidebar width | Default 280px, range 220px ~ 480px |
| Bottom terminal height | Range 120px ~ 400px |
The current workspace remembers:
- Left sidebar width
- Bottom terminal height
- Focus mode on / off state
- Current active session
- Session split layout
Focus mode is currently wired. When enabled, it:
- Hides the left sidebar
- Hides the bottom terminal
When disabled, both are restored.
Current product boundary:
The only confirmed user-visible entry for focus mode is through the command palette. Do not document a standalone globalFshortcut as a shipped capability.
The top of the left sidebar always includes:
- Current panel name
- Current branch button
Files / Gittabs- Inline Git status bar
Clicking the branch button does the following:
- Switch the left sidebar to the Git tab
- Open the branch quick switcher overlay
The button label prefers the current branch name, and falls back to — if no value exists.
| Tab | Content |
|---|---|
| Files | File tree and file action toolbar |
| Git | Git panel |
When switched to Files, the file toolbar is shown. When switched to Git, the file toolbar is hidden.
| Button | Behavior |
|---|---|
| New File | Open the create modal in file mode |
| New Folder | Open the create modal in folder mode |
| Refresh | Refetch the file tree |
- The root file tree loads on first entry.
- Child directories are lazy-loaded: when a directory expands and its children are not loaded yet, another request is sent for that directory path.
- At the top level,
app,packages, andsrcexpand by default.
| Feature | Rules |
|---|---|
| Search input | Typing triggers file search |
| Trigger timing | Fire after roughly 150ms of idle time |
| Result limit | Default upper limit is 10 items |
| Result row | Shows file name, containing directory, and a delete action |
| Click search result | Open the file directly in the editor |
| Node type | Click behavior | Inline actions |
|---|---|---|
| Folder | Expand / collapse; fetch children on first expansion | New file, new folder, delete |
| File | Set as current active file and open it in the main area | Delete |
The actual rules for the create modal are:
- It is shown as a modal
- If launched from a folder row action, the input is prefilled with
directory-path/ - If launched from the toolbar, the input starts empty
- Empty path produces an error
- Creating a file with a path ending in
/produces an error - After submit succeeds:
- Refetch the file tree
- If a file was created, automatically open that file
- Deletion runs through a confirmation dialog
- After confirmation, the delete request is sent
- After delete succeeds:
- Refetch the file tree
- If the deleted path is the currently open file, close it and clear the active file
The Git panel contains, from top to bottom:
- Toolbar
- Commit message input
- Latest commit summary
- Change group list
- Discard confirmation dialog, conditionally
| Button | Visibility | Behavior |
|---|---|---|
| Refresh | Always visible | Refetch Git status |
| Stage All | Visible when changes exist | Stage modified / deleted / untracked files |
| Unstage All | Visible when changes exist | Unstage all staged files |
| Discard All | Visible when changes exist | Open confirm-all discard flow |
| Commit | Visible when changes exist | Only enabled when commit message is non-empty and staged changes exist |
- Uses a single-line auto-growing style textarea
- Clicking
Commitsends the commit request - On successful commit, the commit message is cleared and Git status refreshes
If the current state includes a latest commit summary, the panel shows:
Latest commitlabel- Short SHA
- Commit title
Changes are currently shown in this order:
stagedchanges(modified)deleteduntracked
Each group shows a title, count, and file list.
| Action | Behavior |
|---|---|
| Click file row | Request the file diff and open diff view in the main area |
| Stage / Unstage | Toggle staged state for that file |
| Discard | Open single-file discard confirmation |
The Git panel has a real preview the first item automatically behavior:
- After Git status finishes loading, if diff preview has not been dismissed:
- Keep the current preview if it still exists
- Otherwise automatically select the first change and request its diff
- After the user explicitly closes diff, the
preview dismissedflag becomes true so the UI does not keep auto-opening diff again
The status bar shows three kinds of numbers:
- Total change count
- Ahead count
- Behind count
- Click the ahead count: open the Push confirmation dialog
- Click the behind count: open the Pull confirmation dialog
- If the corresponding count is
<= 0, the button is disabled
The confirmation dialog always includes:
- Title
- Description text
- Cancel button
- Primary action button
When Push / Pull hits HTTP auth failure, and the backend indicates it can continue by asking for credentials:
- The dialog body switches to an auth form
- The username input is prefilled from server
usernameHintwhen available - Both username and password are required before continuing
If the backend marks the case as interactive auth not supported, the dialog only shows the warning and does not provide a submittable form.
The display priority in the desktop main area is fixed:
- If the left sidebar is on the Git tab and a diff preview exists, show diff
- Otherwise, if an active file exists, show the editor
- Otherwise, show the agent session area
This means:
- Git diff is bound to the Git tab
- As soon as the user switches back to the Files tab, the main area leaves diff and returns to the editor or session area
The session area supports:
- Single pane
- Horizontal split
- Vertical split
- Leaf nodes that are either real sessions or new-session draft cards
Each split container ratio is persisted into the current workspace UI state.
When a pane has no real session yet, the main area shows a new-session draft card that supports:
- Choosing
ClaudeorCodex - Creating a session in the current pane
- Splitting to a new horizontal draft pane
- Splitting to a new vertical draft pane
- Closing the draft pane
The desktop draft card and the mobile create-session flow share the same provider launch model:
- Check whether the provider runtime is available
- If the runtime is available:
- Create the session directly
- If the runtime is unavailable but supports auto-install:
- Start installation first
- Poll install status every
1.5s - Create the session after install succeeds
- If the runtime is unavailable and auto-install is not supported:
- Show manual install instructions on the card
- If documentation URL exists, show a link-out action
Desktop-only extra rule:
- If either provider is currently starting or installing, both provider cards are disabled to avoid duplicate launches
Each created session renders as a card containing:
- Top progress bar
- Header: status dot, title, provider badge, state badge, right-side action area
- Conditional Supervisor card
- Session terminal
- Prefer
session.title - If missing, fall back to
SESSION-XX - Provider badge shows
Claude/Codex - State badge converts
starting / running / idle / ended / draftinto Title Case
| Action | Visibility | Behavior |
|---|---|---|
| Stop | Only visible when running |
Stop the current session |
| Split Horizontal | Always visible | Create a horizontal split anchored on the current session |
| Split Vertical | Always visible | Create a vertical split anchored on the current session |
| Close | Always visible | Remove from the pane layout first, then run the session close flow |
- Clicking blank space inside the card sets that session as the current workspace active session
- Clicking buttons, links, or input controls does not trigger that behavior
| Session state | Behavior |
|---|---|
ended |
Delete directly |
| Any other state | Stop first, poll until ended, then delete |
The Supervisor card appears inline inside a Session Card only when all of the following are true:
- The session has full capability
- The session is not
draft - The session is not
ended
The inline area supports:
- Enable objective
- Edit objective
- Pause / resume
- Manually trigger one evaluation
- Disable objective
On desktop, enable / edit / disable all use modal dialogs.
After a file is selected, the page enters one of two modes based on file type:
| File type | Page behavior |
|---|---|
| Text file | Open Monaco editor |
| Image file | Open image preview |
| Feature | Interaction rules |
|---|---|
| Editor | Uses Monaco; switches language mode automatically from file extension |
| Dirty state | Mark unsaved after content changes |
| Save button | Only enabled for text files with unsaved changes |
| Save shortcut | Monaco really registers Ctrl/Cmd + S |
| Close button | Close the current file and clear the active file |
Saving sends baseHash for conflict detection.
- Image files are previewed through
/api/file - That endpoint is only used for image preview, not as a general download endpoint
If the image file is itself a text-based image file, currently mainly SVG:
- The page shows an
Image / Textmode switch button - Switching from image to text:
- Refetches the text content
- Opens Monaco in text-file mode
- Switching from text back to image:
- Reloads in image mode again
The editor responds to refreshes triggered by filesystem or Git changes:
| Scenario | Behavior |
|---|---|
| File changed on disk and the current file has no unsaved changes | Automatically refresh to latest disk content |
| File changed on disk and the current file has unsaved changes | Keep local content and show File has been modified on disk warning |
| File deleted on disk | Show File has been deleted on disk warning |
| Image file resource changed | Refresh image URL / size |
| Scenario | Page behavior |
|---|---|
| Open file fails | Show error information in the main area |
activePath exists but file has not finished loading |
Show a loading placeholder |
| No file selected | Show the editor empty-state prompt |
Diff Viewer is a read-only view containing:
- File path at the top
- Close button
- Line-by-line rendered diff content
- Line numbers
- Distinct visuals for added / removed / meta / context lines
After diff is closed, the current behavior is:
- Clear the current diff preview
- Clear
activeFilePath - Return the main area to the agent view
The terminal panel contains:
- Top toolbar
- Optional terminal tabs
- xterm rendering area for the current terminal
| Feature | Behavior |
|---|---|
| Current terminal title | Formatted from current terminal meta / title |
| Close current terminal | Close the selected terminal |
| New terminal | Create a new shell terminal |
| Terminal selector | Switch terminal when multiple terminals exist |
| Scenario | Page behavior |
|---|---|
0 terminals |
Show empty state and Create terminal CTA |
1 terminal |
Show xterm directly |
> 1 terminals |
Show tabs and also provide selector dropdown |
When creating a new shell terminal:
- The working directory is fixed to the current workspace path
- Unix-like environments default to
$SHELL -i - Windows defaults to
cmd.exe
Desktop terminals and agent terminals share the same xterm host capability and currently behave as follows:
- On first entry, try replay / snapshot restoration first
- Show a restoring overlay before restoration finishes
- Show a degraded overlay if replay is too stale, the terminal has already closed, or restoration fails
- Non-active terminals go through a hydration queue and show a placeholder during that stage
| Feature | Behavior |
|---|---|
| Standard input | Send directly to terminal or session |
| Read-only protection | Non-interactive session terminals cannot accept input |
| Paste / drag-upload files | Upload files into the current workspace first, then inject shell-safe path text into the input |
| Upload in progress | Show Uploading… mask above xterm and temporarily disable input |
After upload succeeds, the terminal receives:
- Each path shell-escaped with single quotes
- Multiple files joined by spaces
- A trailing space, so the user can keep typing the command
The mobile workspace is not a shrunken desktop layout. It is a mobile workflow organized around current session + Dock + multiple full-screen Sheets.
The overall structure is:
- Top bar
- Current single-session main area
- Bottom Dock
- Full-screen Sheets for Agent / Files / Terminal / Supervisor and related flows
Mobile shares the same workspace startup and route-guard logic as desktop:
- Resolving: show loading placeholder
- Load failed: show error placeholder
- Valid workspace exists: enter the mobile workspace
| Feature | Behavior |
|---|---|
| Workspace button | Shows current workspace name; clicking opens the Workspace Drawer |
| Settings button | Navigate to /settings |
| Fullscreen button | Visible when supported by the browser; toggles fullscreen for the workspace view |
Workspace title display follows the same rule as desktop: workspace name first, then last path segment, then full path.
The mobile workspace page embeds the config drift banner at the top of workspace content.
It is not a shell-level global bar spanning every page.
The main area shows only one currently active session.
The current main card behavior is:
- Reuse the same Session Card core content
- Do not show the desktop header action set
- Provide Supervisor entry through a top-corner affordance
So the mobile main card does not directly expose:
- Stop
- Split
- Close
The page shows an empty state and CTA:
- Copy 1: prompt the user to start a session
- Copy 2: explain that file and terminal capabilities remain available from the Dock
- CTA: open Agent Sheet directly in create mode
If an external action, such as clicking a notification, requests focus on a session:
- As long as that session belongs to the current workspace
- Mobile automatically switches the visible current session to it
The Dock always contains three entries:
AgentFilesTerminal
Interaction rules:
| Dock item | Behavior |
|---|---|
| Agent | Open / close Agent Sheet |
| Files | Open Files full-screen Sheet |
| Terminal | Open Terminal full-screen Sheet |
Current active-state rules:
- Highlight
Agentwhen Agent Sheet is open - Highlight the matching item when Files or Terminal Sheet is open
Agent Sheet has two modes:
sessions: session listproviders: create new session
Default rules:
- If sessions already exist, default to
sessions - If no session exists yet, default to
providers
Content includes:
Create sessionaction row- Session list for the current workspace
Each session row provides:
- Primary click: switch to that session and close the Sheet
- Trailing close button: close that session, then close the Sheet
The provider list is currently fixed to:
- Claude
- Codex
Interaction rules:
- After choosing a provider, reuse the same runtime / auto-install / create flow as desktop
- After successful creation:
- Write session data
- Append it into layout
- Switch it into the current mobile session
- Close the Sheet
Difference from desktop:
- Mobile shows busy state per provider and only disables the busy item
- Desktop locks the entire provider area if any provider is busy
Files Sheet is a full-screen Sheet with three route states:
rooteditordiff
The root-state top area includes:
- Current branch button
Files / Gittabs- Inline Git status bar
- Clicking opens the branch quick switcher
- Label shows the current branch name; if empty, show the
no branchcopy
| Tab | Content |
|---|---|
| Files | File tree |
| Git | Git panel |
- Entry: select a file in the Files tab
- Main content: code editor / file preview
- Page-level back: use Sheet Header
Backto return to root - Header right-side actions:
- Text-image files can switch
Image / Text - Text files can be saved
- Text-image files can switch
- Entry: select a change in the Git tab
- Main content: Diff Viewer
- Page-level back: use Sheet Header
Backto return to root - Closing the whole Sheet: exit Files Sheet directly
On mobile, Terminal opens as a full-screen Sheet and reuses the same terminal capability set internally.
Compared with desktop:
- Only show the current terminal selector when at least one terminal exists
- Use
MobileSelectSheetfor multi-terminal selection - Do not show desktop-style tabs
A real soft key bar appears above mobile xterm and includes:
CtrlShiftEscTab↑←↓→Enter
Interaction rules:
| Key | Behavior |
|---|---|
| Ctrl tap | Toggle between off and armed |
| Ctrl long-press | Lock as locked |
| Shift tap | Enter armed; auto-consume after the next soft-key input |
| Arrow / Esc / Tab / Enter | Write the corresponding control sequence directly |
The soft key bar is disabled when:
- The current terminal is non-interactive
- File upload is in progress
- WebSocket is disconnected
Mobile Supervisor is split into two levels:
| Scenario | Page behavior |
|---|---|
| Current session already has Supervisor enabled | Show a status card and Edit objective / Disable buttons |
| Current session has Supervisor disabled | Show empty state and Enable objective button |
Enable, edit, and disable all enter the detail level, which supports:
- Showing mode-specific title, subtitle, and icon
- Editing the objective
- Choosing the evaluator provider
- Fixed bottom
Cancel / Confirmbuttons
Choosing the evaluator provider opens another selection Sheet.
Each workspace row contains:
- Primary area: switch to that workspace and navigate to
/workspace - Close button: close that workspace
The drawer footer contains one fixed button:
- Open the workspace launcher
When the last workspace is closed from the mobile drawer, the flow explicitly requires return home when empty, so the app returns to the welcome page.
The settings page manages:
- Notifications
- Provider launch args and config files
- Appearance
- Part of shortcut configuration
Desktop and mobile share the same capability set, but use different navigation structures:
| Form factor | Navigation structure |
|---|---|
| Desktop | Left-side section navigation + right-side content area |
| Mobile | Root list page + detail subpages |
Current visible section scope:
| Form factor | Visible sections |
|---|---|
| Desktop | General / Providers / Appearance / Shortcuts |
| Mobile | General / Providers / Appearance |
Note:
Mobile currently has noShortcutsentry.
| Scenario | Back behavior |
|---|---|
| Mobile detail page | Return to the mobile root list first |
| All other cases | Prefer browser history; otherwise go to /workspace; otherwise go to / |
After connection becomes available, the settings page loads settings data and syncs the following into page state:
- Notification master switch
- Notification sound switch
- Terminal renderer
- Language
- Provider additional args
- External config audit
If loading fails:
- An error notice appears at the top of the content area
- The user can click
Refreshto refetch
The bottom of the settings page always shows:
- Autosave hint
- Version string
v0.2.6
The settings content area embeds the config drift banner at the top to handle Codex config drift.
General currently contains notification settings only.
| Setting | Interaction rules |
|---|---|
| Notifications Enabled | Toggle saves immediately |
| Notification Sound | Toggle saves immediately; disabled when Notifications Enabled is off |
The frontend also syncs both values into local notification preferences.
The page checks browser notification capability and shows one of three states:
availablelimitedunsupported
Mobile rule:
- If the device is mobile and not running as a standalone web app, capability is marked as
limited
The page shows browser notification permission state:
granteddenieddefaultunavailable
Among those:
- When state is
defaultand capability isavailable, showRequest permission - When state is
denied,limited, orunavailable, show the corresponding explanatory copy
Providers is the most complex section in Settings and is split into two layers:
- Base launch-args layer
- Config-file editing layer
The provider set is currently fixed to:
- Claude
- Codex
Desktop has a second-level switch:
- Base
- Config File
Mobile enters Base first by default, then uses a dedicated entry to go into Config File.
The Base layer currently includes:
| Feature | Interaction rules |
|---|---|
| Additional Args textarea | One argument per line; changes autosave immediately |
| Command Preview | Refresh command preview in real time |
The actual behavior of the config-file editor is:
| Feature | Interaction rules |
|---|---|
| Load | Read real config-file content and absolute path on entry |
| File missing | Show empty state and guidance copy, but keep the card structure |
| Expand / collapse | Card is collapsible; expanded state persists to local storage |
| Editor | Uses Monaco |
| Status display | saved / dirty / saving / error |
| Save | Save to the real config file; if a backup path is created, notify through Toast |
| Reset | Restore the latest loaded / saved content |
| Format | Supported only for claude config; implemented as JSON pretty-print |
| Form factor | Behavior |
|---|---|
| Desktop | Provider tabs + Base / Config File second-level switch; Config File can fill the remaining height |
| Mobile | Base page shows Open Config File Editor; clicking enters the config-file sublayer with a back action to Base |
Appearance currently contains three items:
- Theme
- Terminal Renderer
- Language
| Feature | Interaction rules |
|---|---|
| Dark / Light switch | Switch frontend theme immediately on click |
| Local persistence | Theme choice writes to local storage |
| Server save | The page attempts to sync the setting to the server |
Current implementation boundary:
Immediate theme switching is complete.
Server-side persistence still has limitations; see Chapter8.2.
Two renderer modes are supported:
standardcompatibility
Clicking saves immediately.
Supported languages:
- Chinese
zh - English
en
Clicking switches the frontend language immediately and saves the config.
The Shortcuts page currently provides a shortcut configuration UI, split into four groups:
- Global
- Workspace
- Editor
- Terminal
| Feature | Behavior |
|---|---|
| Click a shortcut binding | Enter capture mode |
| Capture input | Record Mod / Shift / Alt + Key |
Escape |
Cancel the current capture |
| Reset one item | Remove the custom binding for that item |
| Reset All | Clear all custom bindings |
All changes:
- Write into local shortcut config
- Sync-save to settings
The real capability of this page should currently be defined as:
- View default bindings
- Enter / reset custom bindings
- Save configuration
It should not be defined as a global shortcuts take effect immediately at runtime system. The more precise runtime boundary is documented in Chapter 8.3.
The 404 page reuses the visual shell of the welcome page and includes:
- Kicker
- Title
- Description
- A status panel showing the unmatched path
- A
Return Homebutton
The interaction rule is simple:
- Clicking the button returns to
/
Quick Actions is currently wired on both desktop and mobile.
The only globally wired hotkey currently confirmed in code is:
Ctrl/Cmd + K: open / close Quick Actions
| Form factor | Shape |
|---|---|
| Desktop | Centered overlay modal |
| Mobile | Full-screen Sheet |
- Autofocus the search input
- Clear the previous search term
- Reset the selection index to the first item
| Key | Behavior |
|---|---|
ArrowDown |
Move selection down |
ArrowUp |
Move selection up |
Enter |
Execute the selected command and close the panel |
Escape |
Close the panel |
- Open the workspace launcher
- Return to the home page
- Open the settings page
- Switch to any already-open workspace
- When an active workspace exists, also provide
Return home and clear active workspace
- Toggle Focus Mode
- Explicitly enter Focus Mode
- Explicitly exit Focus Mode
- Toggle left sidebar visibility
- Toggle terminal visibility
- Explicitly open terminal
- Explicitly close terminal
The command list may currently display shortcut labels such as:
Ctrl+NCtrl+,F
These are currently display copy only and do not mean the corresponding global shortcuts are actually wired.
The welcome page, desktop top bar, and mobile drawer all use the same workspace launcher.
| Form factor | Shape |
|---|---|
| Desktop | Modal |
| Mobile | Full-screen Sheet |
| Feature | Behavior |
|---|---|
| Home button | Jump to ~ |
| Go Up button | Jump to parent directory; hidden at root / |
| Preset root chips | Currently fixed to /, ~, and /home/spencer |
| Current path chip | If the current path is not in preset chips, append one extra current-path chip |
| Single-click directory row | Select directory |
| Double-click directory row | Enter directory |
| Inline action after selection | Show Enter directory action button |
Startis disabled when no directory is selected- Clicking
Startopens that directory as a workspace - After success:
- Add the workspace into the local list
- Update workspace order
- Set it as the active workspace
- If not currently on
/workspace, auto-navigate to/workspace - Close the launcher
The desktop launcher listens for:
Escape: close the modal
- Desktop left sidebar branch button
- Mobile Files Sheet branch button
| Form factor | Shape |
|---|---|
| Desktop | Overlay popover |
| Mobile | Selection Sheet |
| Feature | Behavior |
|---|---|
| Search input | Filter branch list by name |
| Current branch | Shows a checkmark |
| Remote branch | Shows Remote badge |
| Select existing branch | Switch to that branch directly |
The current implementation is not one click creates immediately. It uses a two-step confirmation:
- When the user types a branch name that does not exist, the list shows
Create xxx - After selecting it once, the entry becomes
Confirm create xxx - Only after selecting again is the branch actually created and checked out
| Key | Behavior |
|---|---|
ArrowDown / ArrowUp |
Move selection |
Enter |
Select branch / initiate create / confirm create |
Escape |
Close |
The global connection banner handles these states in a unified way:
reconnecting: showReconnecting...rejected: showAnother tab is active- Any other disconnected state: show
Connection lost
The Toast container supports:
- Keeping at most the latest
5toasts at once - Four types:
success / error / warning / info - Auto-dismiss, default
5s;duration = 0switches to manual close
| Attached toast data | Click result |
|---|---|
workspaceId + sessionId |
Jump to that workspace and focus / scroll into view / pulse-highlight the session |
workspaceId only |
Switch to that workspace and navigate to /workspace if needed |
| No navigation data | Only close the toast |
Notifications currently fire only when an agent finishes one round of work, with explicit rules:
- Primary trigger:
running -> idle - Fallback trigger:
running -> ended
And additionally:
- Rounds shorter than
4sdo not notify - When the page is visible:
- If desktop is already on the workspace that owns the session
- Or mobile is already showing that session
- Then suppress the notification
- When the page is visible but the user is not on that workspace / session:
- Send in-app toast
- When the page is hidden:
- Send browser system notification
If sound is enabled:
- Prefer playing
/task-complete.wav - Fall back to a Web Audio synthesized sound if playback fails
Supervisor editing interactions are carried by two containers:
| Form factor | Container |
|---|---|
| Desktop | Modal dialog |
| Mobile | Full-screen Sheet + optional selection Sheet |
Supported modes:
enableeditdisable
Editable fields:
- Objective text
- Evaluator Provider
This chapter lists only interactions that are currently confirmed as wired. It does not repeat historical PRD items that were planned but do not have unified runtime listeners today.
| Interaction | Status |
|---|---|
Ctrl/Cmd + K |
Wired: open / close Quick Actions |
| Overlay | Wired interaction |
|---|---|
| Quick Actions | ArrowUp / ArrowDown / Enter / Escape |
| Branch quick switcher | ArrowUp / ArrowDown / Enter / Escape |
| Workspace launcher (desktop) | Escape closes |
| Interaction | Status |
|---|---|
Monaco Ctrl/Cmd + S |
Wired: save the current text file |
Wired soft keys:
- Ctrl / Shift
- Esc / Tab / Enter
- Arrow Up / Left / Down / Right
The following items must not be written as shipped global shortcuts in the current product description:
Ctrl/Cmd + NCtrl/Cmd + ,F- Any pane split shortcut
- Any custom binding entered on the Settings page
At most, these currently exist as:
- Shortcut labels shown inside command lists
- Or code that exists in unmounted components / code paths without unified runtime consumption
The server pushes file-change and Git-dirty events. The frontend reacts by:
- Refreshing Git status
- Refreshing the branch list
- Marking the file tree stale and reloading on demand
- Refreshing already-open editor buffers
The frontend currently has no explicit logout entry, even though the backend has a corresponding endpoint.
The main login-related failure cases are:
- Wrong password
- Login endpoint unavailable
- Temporary lockout after too many failed attempts
Paste / drag-upload into terminals currently has these boundaries:
- Requests must include
workspaceId - The current batch must contain at least one file
- Missing workspace returns
workspace_not_found - Oversized files, parse failures, and write failures return dedicated errors
- Frontend reports failure through error Toast
/api/file currently serves image preview only:
- Non-image types return
not_an_image - Path escape returns
path_escape - It is not a general-purpose file download endpoint
This chapter covers only two kinds of content:
- Implementation facts that should be preserved but do not belong in the main page descriptions
- Items that exist in the repo but must not currently be described as shipped capability
The frontend login page is mounted at /login.
Backend auth endpoints remain under /auth/*, such as:
/auth/status/auth/login/auth/logout
/auth is not a frontend page route and should not be described as one in product-facing flow documentation.
The current frontend UI genuinely supports immediate dark / light switching.
But the server settings schema fully accepts only the appearance.theme = "dark" path.
Therefore:
- Theme taking effect immediately is true
- Theme full and symmetrical persistence across frontend and backend is currently incomplete
The PRD should not describe it as a fully consistent cross-layer theme persistence system.
The following items can be found in the repo as components, tests, or implementation fragments, but must not be described as currently reachable user-facing functionality:
- The component exists
- But there is no reachable mounted entry in actual pages today
- The component exists
- It defines internal logic for
F,Escape, and related behavior - But it is not currently mounted by the shell or workspace page
The only truly user-visible focus mode entry currently confirmed is toggling focus mode state from Quick Actions.
- The Shortcuts settings page exists
- Custom bindings can already be saved
- But runtime global hotkeys are not uniformly driven by those saved bindings
Therefore, the PRD must not claim that custom shortcuts take effect globally and immediately at runtime.
When this PRD is maintained in future updates, follow three rules:
- Write the main body by page and user flow, not by piling up technical modules.
- Write real reachable interactions first, then states, errors, and boundaries.
- A component existing is not the same as a feature being shipped; if it is not mounted or not uniformly listened to, do not document it as current product capability.