WorkspaceView Component
The WorkspaceView component is the heart of Tempest’s desktop application. At 2,646 lines, it serves as the primary container managing a single agent session workspace, coordinating tabs, panes, sessions, and user interactions. It orchestrates everything from terminal spawning to diff rendering to live preview hosting.Overview
WorkspaceView is the root component rendered by the application. It manages:- Project and worktree state (sidebar navigation)
- Session lifecycle (create, resume, close)
- Tab bar and split-pane layout
- Work-done detection for agent sessions
- Keyboard shortcuts and global events
- Theme switching
- Settings and configuration
Data Model
Session Interface
Project and Worktree
Tab System
WorkspaceView supports multiple tab types, each rendered by a dedicated pane:| Tab Kind | Component | Purpose |
|---|---|---|
terminal (default) | TerminalPane | Interactive terminal session (PTY) with xterm.js |
diff | DiffPane | Git status, staging, commit, push operations |
preview | PreviewPane | Live preview of dev server (Vite, Next.js, etc.) |
editor | CodeMirrorPane | Read/edit files with syntax highlighting |
| Agent session | TerminalPane | Terminal running an agent CLI (Claude, Opencode, etc.) |
State Management
WorkspaceView uses over 50useState hooks managing:
Session Management
sessions: Array of all open Session objectsactiveSessionId: Currently focused session UUIDrenamingSessionId: Session being renamed (if any)
Tab Bar
dragTabId,dragOverTabId,dragOverSide: Tab reordering state- Refs (
dragTabIdRef,dragOverTabIdRef) to avoid stale closures
Layout
paneLayout: Split pane tree (null = single pane mode)activeSplitIds: Set of session IDs in current split layoutpaneRects: Computed absolute positions for each pane
Navigation
activeSection: “overview” | “nexus” (main page when no tab active)sidebarOpen: Left sidebar visibilityrightSidebarOpen: Right sidebar visibility
Terminal/Worktree Creation
showTerminalNaming: Modal open state for naming new sessionsterminalName,terminalPrompt: User input for new sessionsterminalLaunching: Async operation in progressgitNotFound,gitNotFoundRoot: Git initialization dialogspendingProjectId,pendingAgent: Deferred session creation
Project Management
projects: Array of projects (default mode only)zenWorktrees: Worktree list for zen mode
UI State
settingsOpen,broadcastOpen,promptPickerOpen: Modal statesctxMenu: Right-click context menu position/contextdeleteDialog: Workspace deletion confirmation stateatlasPromptPath,atlasIndexingPaths: Atlas (Token Intelligence) statequeueOpenSessionId: Message queue panel visibilitygitRevision: Increment counter that triggers DiffPane refreshes
Split Pane Layout
WorkspaceView supports dividing the workspace into a 2D grid using a binary tree structure.Tree Structure
Pane Positioning
Tree functions compute absolute rectangles (0-1 normalized coordinates) for each leaf:patchRatio() to update split ratios on mouse drag.
Split Operations
Session Lifecycle
Creating a Session
openSession() is called from multiple paths: user clicks “New Workspace”, restore loop, split pane. The function:
- Mints or reuses a stable
instanceIdfor persistence - Determines the storage key (
storeKey): root sessions userootSessionKey(cwd, sessionId), worktree agents key oncwd - Builds agent arguments via
buildAgentArgs(): session/resume flags + prompt - Calls
invoke("create_pty_session")→ Rust PTY spawns - Registers with SessionManager, which owns the Channel and runs work-done detection
- Adds to
sessionsstate, making it appear as a tab - Persists metadata to localStorage
spawningPaths ref.
Resuming a Conversation
Agents save theirconversationId (Claude: UUID, Opencode: captured from PTY output). On restore:
buildAgentArgs() function substitutes the UUID into the agent’s resume arguments:
Closing and Cleanup
closeSession(sessionId) is called via tab close button, context menu, or workspace deletion. It:
- Recursively closes all sub-sessions (spawned via split)
- Kills the PTY:
invoke("close_pty_session", {sessionId}) - Marks persisted entry as closed:
markWorktreeSessionClosed(storeKey) - Unregisters from SessionManager
- Removes from pane layout tree if in split mode
- Clears work state badge
- Updates active session if needed
Work-Done Detection
Agent sessions show a spinner badge while the agent is working and a green dot when done. This is powered by the SessionManager, which monitors raw PTY output bytes:Detection Logic (in SessionManager)
- Byte-quiet timer: Start on first data chunk from the agent
- Title watching: Monitor OSC 0/2 escape sequences (agent sends status like ”✳ refactoring”)
- Two thresholds:
- 5 seconds of silence without title changes = “work done”
- 12 seconds of silence with title changes (still thinking) = extend to “done”
- User input resets: When user types and presses Enter, arm a new quiet timer
useWorkState(sessionId) hook, updating the badge in real-time as the state changes from idle to working to done.
Display
Restore on Launch
On mount, WorkspaceView restores all previously open sessions in saved order:- Discover valid paths: Scan each project’s
.tempest/for worktrees, add tovalidPaths - Mark root sessions as valid: Retrieve all root session store keys (project.path + “::root::” + sessionId)
- Prune orphaned entries: Delete persisted sessions whose paths no longer exist on disk
- Collect restore items: Build list from
sessionOrder(tab bar order) + saved active session - Open in order: Restore non-active sessions, then active session last so it gets focus
activeInstanceId from runtimeState, not the current active tab—ensures focus survives a reload.
Keyboard Shortcuts
All shortcuts are registered in the capture phase (before xterm.js can consume).matchesEvent() checks if an event matches a keybinding:
| Action | Default | Usage |
|---|---|---|
| Toggle theme | Ctrl+Shift+T | Switch light/dark |
| Toggle left sidebar | Ctrl+B | Show/hide projects |
| Toggle right sidebar | Ctrl+Shift+P | Show/hide file tree |
| Open settings | Ctrl+, | Settings panel |
| New workspace | Ctrl+Shift+N | Open session menu |
| Close tab | Ctrl+W | Close active session |
| Next tab | Ctrl+Tab | Move right in tab bar |
| Prev tab | Ctrl+Shift+Tab | Move left in tab bar |
| Split vertical | Ctrl+Shift+\ | Side-by-side panes |
| Split horizontal | Ctrl+Shift+_ | Stacked panes |
| Open queue | Ctrl+Shift+Q | Message queue panel |
| Broadcast | Ctrl+Shift+M | Send to all agents |
Event Listeners
WorkspaceView registers global Tauri event listeners:Persistence
Three localStorage stores sync automatically:-
sessionOrder, activeInstanceId: Via
setRuntimeState()- Restores tab bar order and last active tab on launch
-
Per-session metadata: Via
saveWorktreeSession(storeKey, {...})- name, agent, conversationId, instanceId, projectId, isRootSession, noGit
-
Transient tabs (diff/preview/editor): Via
runtimeState.tabsarray- Includes kind, cwd, projectId, previewUrl for preview tabs
-
Project list: Via
saveOpenProjects()- Only default mode (not zen)
Theme Integration
WorkspaceView usesuseTheme() hook to:
- Read current theme name (“Tempest Dark” vs “Tempest Light”)
- Provide sun/moon toggle button in sub-bar
- Pass theme context to all child components
Context Menus
Right-click on sidebar items opens a context menu with actions: Worktree session:- Close session
- Delete workspace (with optional branch deletion)
- Remove session (delete persisted entry)
- Index project (Atlas/Token Intelligence)
- Remove project (close all its sessions)
createPortal() into document.body to escape scroll clipping.
Modal Dialogs
WorkspaceView renders several modals viacreatePortal():
- Terminal naming modal: Enter worktree name, optional prompt, choose git init strategy
- Delete workspace dialog: Two-step confirm with optional branch deletion
- Atlas index prompt: Ask user to opt-in to local indexing
- Settings panel: Full settings UI
- Broadcast dialog: Send message to all agent sessions
- Right sidebar: File tree + git operations
Memoization Strategy
Heavy use ofmemo() prevents unnecessary re-renders:
Refs for Avoiding Stale Closures
Several refs maintain always-current state for event handlers registered once:Sidebar Navigation
Two modes: Default: Multi-project view with expandable projects. Each project shows:- Expandable header with project name
- Root sessions (agent + terminal in project root, badged “main”)
- Worktree sessions (git branches with their own sessions)
- Sub-sessions (spawned via split, indented with connecting lines)
Future-Proofing
Thekind field on Session allows new tab types to be added without breaking existing sessions. When a new kind is added, the render tree checks kind and renders the appropriate component: