The title rides the user message the moment it lands — a long agentic turn no longer holds the session name hostage; an opener signature keeps the completion hook (background turns) from burning duplicate attempts.
Approval origins (reviewer/user/bypass, notes, grants) ride the tool message display sidecar so chips and deny blocks survive reload.
The Auto-Approve explainer is persisted once per session server-side with new shorter copy; later switches persist one-line markers.
swe-lead (minimal tools, coordination verbs) + swe/design/test workers with the shared worker contract; workers never surface in the picker — they're staffed, not started.
Staffing card rides the approval slot; workers nest under the lead's ONE expandable RECENT entry in both sidebar layouts.
Per-session coworker+folder chips replace the sidebar split-button picker; code family gets a send-time folder dialog with git-ready temp dirs and Save as project.
Builtins ship enabled; user-facing noun is Coworker; personas flag now defaults on.
Boundary-hardening pass addressing three audit findings on the local sidecar.
Shell command allowlist (andrewyng/openworker#28):
- Replace prefix-string matching in PermissionEngine._command_allowed with
argv-aware matching: reject any command containing shell operators
(; & | > < ` $( ( and newlines) before consulting the allowlist, then require
the allowlisted entry's tokens to be an exact argv prefix. This closes the
auto-run bypass where an allowlisted "git status" also auto-ran
"git status && rm -rf ~", pipes, redirection, and command substitution.
- Drop language interpreters / package managers (python, python3, node, npm,
npx) from DEFAULT_ALLOWED_COMMANDS — allowlisting an interpreter allowlists
arbitrary code (python3 -c "..."), defeating approval gating. Read-only
inspection commands and pytest remain.
MCP OAuth loopback (andrewyng/openworker#29):
- Verify the OAuth state at the loopback boundary. The MCP SDK already validates
state (compare_digest), so this is not a CSRF fix but defense-in-depth: capture
the state from the authorize URL and have deliver_callback ignore a callback
whose state does not match WITHOUT consuming the pending future, so a stray or
forged local hit can no longer abort a user's in-progress sign-in. Falls back to
prior accept-any behavior when no state was captured.
WebSocket ingestion caps (andrewyng/openworker#38):
- Bound a single user_message frame in the session WS loop: max text length,
max attachment count, and max total attachment bytes. Oversized frames get a
visible error frame and are dropped instead of being buffered into a turn; the
socket stays alive. Guards the unauthenticated loopback socket against cheap
memory spikes.
Tests:
- Allowlist: reject operator chaining (8 variants), argv-boundary matching, and
interpreters-not-auto-allowed-by-default.
- OAuth: state extraction, and mismatched/missing state ignored without consuming
the flow while the matching state still resolves it.
- WS: oversized text and too-many-attachments rejected with an error frame, and a
normal message still works afterwards.
Full suite: 865 passed (1 pre-existing unrelated failure in
test_provider_router::test_manager_curated_models, present on origin/main).
Gmail/Calendar/Drive show a disabled Coming-soon button; the server refuses the flow too.
Manual token connect and already-connected accounts are untouched.
Picker stays live for the session; switches persist a model_switch notice (§17 revised).
Rebinds refused mid-turn; images become placeholders for non-vision targets at send time.
Engine appends a display-only notice message on error/interrupted; providers never see it.
New retry frame re-runs a failed turn with no new user message, guarded on the error tail.
GUI renders persisted notices on reload and a Retry button on the trailing error.
Imported from andrewyng/aisuite@1b4bbf303e
(contents of its platform/ directory, hoisted to the repo root).
Development history prior to this commit lives in that repository.
Co-authored-by: Devika <devikaverma11@gmail.com>