The auto_approve flag (and its shadow sibling) become first-class settings
instead of hand-edited TOML, and the Auto-Approve mode entry appears in the
picker only when the flag is on.
Server:
- manager: auto_approve()/auto_approve_shadow() read prefs.json first,
falling back to the config.toml value a power user may have set; both
writers persist to prefs. Both stores are user-global, so a cloned repo
still can't enable either (the 1.5 invariant, unchanged).
- get_settings() exposes both; POST /v1/settings/auto-approve and
/auto-approve-shadow write them (same shape as context-bar).
- Session builds pass the prefs-backed values into build_engine via new
optional auto_approve/auto_approve_shadow overrides (None = config value),
so a Settings flip takes effect on the next session build with no restart.
Scheduled runs keep reading config only - they are unattended, so the
live reviewer can never fire there regardless.
GUI:
- Mode picker: the Auto-Approve entry is `gated` - shown when
getSettings().auto_approve is true, fetched on menu open. A session
already IN auto-approve always shows its own entry so the current mode
stays legible even if the flag was later turned off. This replaces the
TEST-ONLY unconditional entry.
- Settings: AutoApproveCard with the feature toggle and the nested shadow-
evaluation toggle ("records what it would have decided next to your own
choice - without changing anything").
- api.ts: ModelSettings.auto_approve/auto_approve_shadow + setters.
Verified live against the running sidecar: flag off hides the entry on an
interactive session, flag on shows it, the Settings toggles round-trip and
persist. tests/test_auto_approve_settings.py (6): defaults, REST round-
trip, restart persistence, config fallback, prefs-beats-config, and the
build_engine override. tsc clean; 111 GUI unit tests pass.
coworker GUI (React + Tauri)
A thin client of the coworker server (OpenAI-compatible API + WS event/approval stream). Same codebase runs in a browser (dev) and as the OpenWorker desktop app.
First time: bootstrap the Python backend
A fresh checkout has no server to run — create the venv both flows below expect (from the repo root):
bash packaging/setup_dev_env.sh # → .venv (server + aisuite)
Run it (browser, two terminals)
- Start the server (needs a model key, e.g.
OPENAI_API_KEY, in the environment — or add one later in the app's Settings), from the repo root:./.venv/bin/openworker-server --cwd /path/to/your/project --port 8765 - Start the UI:
cd surfaces/gui npm install # first time npm run dev # → http://localhost:5173
Open http://localhost:5173. The UI talks to http://127.0.0.1:8765 (override with
VITE_COWORKER_HTTP / VITE_COWORKER_WS). Start the server before Vite so the
UI can read its per-launch token from <state-dir>/sidecar-8765.token; restart
Vite if the server is restarted.
Run the desktop app from source
The Tauri shell wraps the same UI and supervises the Python server itself — no separate
terminal. It needs the Rust toolchain (rustup) plus the venv from the bootstrap step;
in dev it finds the server at .venv/bin/openworker-server automatically (a
packaged sidecar binary is only produced by the release scripts in packaging/).
cd surfaces/gui
npm install # first time
npm run tauri dev # builds the shell, launches the window, starts the server
Tests
npx tsc --noEmit && npx vitest run # typecheck + unit
npx playwright test # hermetic e2e (mocked /v1 + WS, no Python needed)