State Management
Relevant source files
The following files were used as context for generating this wiki page:
State management in OpenWork is primarily handled using SolidJS stores and signals, persisting critical data to IndexedDB or LocalStorage. The architecture is designed to manage the lifecycle of the OpenCode engine, session histories, and user configurations across different runtime modes (Host and Client). It emphasizes a local-first approach where UI actions map directly to engine-level state changes.
Sources: AGENTS.md:32, packages/app/src/app/app.tsx:100-150
Architecture Overview
The system utilizes specialized "stores" or state-creation functions to encapsulate logic for specific domains such as sessions, workspaces, extensions, and system-level alerts. These stores are often cross-linked, allowing for complex interactions like triggering a workspace reload when an extension is updated.
Core State Domains
| Domain | Responsibility | Primary File |
|---|---|---|
| System State | Manages application-wide alerts, reload requirements, updates, and global errors. | packages/app/src/app/system-state.ts |
| Workspace State | Handles engine lifecycle (start/stop), directory authorization, and multi-workspace switching. | packages/app/src/app/context/workspace.ts |
| Session State | Manages individual task runs, message history, tool execution todos, and permission prompts. | packages/app/src/app/context/session.ts |
| Command State | Manages the creation, deletion, and execution of workspace-specific and global commands. | packages/app/src/app/command-state.ts |
| Extension State | Tracks the availability and configuration of skills, plugins, and MCP servers. | packages/app/src/app/context/extensions.ts |
Sources: packages/app/src/app/app.tsx:238-310, packages/app/src/app/system-state.ts:1-20
Workspace and Engine Lifecycle
The workspace state manages the transition between Host and Client modes and the underlying OpenCode engine. In Host mode, the state tracks the spawned process (PID) and the health of the local server.
The diagram shows the two primary paths for initializing the workspace and engine state. Sources: packages/app/src/app/app.tsx:190-230, packages/app/src/app/context/workspace.ts
Engine Reload Logic
A critical piece of state is the reloadRequired signal. This is triggered when configuration files (like opencode.json or skills) are modified.
- Triggering:
markReloadRequired(reason, trigger)is called by various stores. - Resolution:
reloadWorkspaceEngine()invokes the engine's dispose/reload sequence and clears the state.
Sources: packages/app/src/app/system-state.ts:135-155, packages/app/src/app/app.tsx:1870-1902
Session and Message State
Session state is the most dynamic part of the application, handling streaming Server-Sent Events (SSE) from the OpenCode engine. The createSessionStore manages a list of messages and "todos" (tool calls) associated with a selectedSessionId.
Data Flow for Task Execution
The sequence illustrates how a user prompt results in a reactive update to the message history via SSE. Sources: packages/app/src/app/context/session.ts, packages/app/src/app/app.tsx:430-480
Permission State
When the engine requires user intervention (e.g., file system access), it sends a permission request event. The state management system:
- Captures the request in
pendingPermissions. - Sets the
activePermissionsignal to display the UI modal. - Sends the user's
reply("once", "always", or "reject") back via the SDK.
Sources: packages/app/src/app/context/session.ts, packages/app/src/app/app.tsx:3130-3180
Configuration and Extension State
Configurations such as preferred models and theme modes are stored in LocalStorage or IndexedDB to persist across restarts.
Persistent Settings Table
| Setting | Storage Key | Description |
|---|---|---|
| Default Model | openwork.model_pref | The global default LLM used for new sessions. |
| Theme Mode | openwork.theme_mode | User preference for light, dark, or system theme. |
| Mode Choice | openwork_mode_pref | Whether the app starts in Host or Client mode by default. |
| Keybinds | openwork.keybind_pref | Custom user-defined shortcut overrides. |
Sources: packages/app/src/app/app.tsx:1910-1980, packages/app/src/app/theme.ts
Skill and Plugin Management
The Extension store (createExtensionsStore) handles the installation and removal of skills. It interacts with the file system (via Tauri in Host mode) or the OpenWork Server API (in Client mode). Modifications to these extensions update the local skills and pluginList signals, subsequently triggering the reloadRequired state in the System store.
Sources: packages/app/src/app/context/extensions.ts
Global Synchronization
The useGlobalSync hook (evidenced in app.tsx) is used to keep shared data like provider lists and connected account IDs in sync across different components. It acts as a lightweight global registry for data that is periodically refreshed from the engine.
Sources: packages/app/src/app/app.tsx:660-680
Conclusion
State management in OpenWork is a distributed system of reactive stores that synchronize local UI state with a background engine. By decoupling engine lifecycle, session execution, and user configuration into specialized stores, the architecture maintains a responsive and auditable interface even during complex long-running agentic tasks.