Codex Desktop resumes thread with workspace-write sandbox despite UI showing Full Access
Summary
Codex Desktop can show Full Access in the UI while a resumed thread is actually persisted and executed as workspace-write / on-request. After stopping and restarting the same thread several times, the thread kept asking for access even though the UI still indicated Full Access.
Expected behavior
When the UI/global state says Full Access, resumed turns for that thread should start with something equivalent to:
approval_policy=never
sandbox_policy={"type":"danger-full-access"}
permission_profile={"type":"disabled"}
Actual behavior
The thread initially had many turns with:
approval_policy=never
sandbox_policy=danger-full-access
permission_profile=disabled
After a stop/restart/resume sequence, a later turn_context switched to:
approval_policy=on-request
sandbox_policy=workspace-write
network_access=false
permission_profile=managed
The local per-thread row in ~/.codex/state_5.sqlite also showed the restricted state:
approval_mode=on-request
sandbox_policy={"type":"workspace-write","writable_roots":["~/.codex/memories"],"network_access":false,...}
Meanwhile the global app state still showed Full Access, for example:
electron-persisted-atom-state.agent-mode-by-host-id.local = full-access
So the UI/global Full Access state and the persisted per-thread sandbox/approval state diverged.
Impact
The affected thread repeatedly prompts for access and cannot operate as Full Access, even though the UI says it should. Toggling the UI setting is confusing because the visible state already appears correct.
Suspected cause
The thread resume / active-goal continuation path appears to apply or preserve a per-thread workspace-write / on-request override that is not reflected by the visible Full Access UI state.
Workaround
The local workaround was to stop the running turn, fully quit Codex, back up ~/.codex/state_5.sqlite, and rewrite the affected thread row to:
UPDATE threads
SET approval_mode='never',
sandbox_policy='{"type":"danger-full-access"}',
updated_at=strftime('%s','now'),
updated_at_ms=CAST(strftime('%s','now') AS INTEGER) * 1000
WHERE id='<thread-id>';
Then reopen Codex and verify the next turn_context starts with approval_policy=never and sandbox_policy=danger-full-access.
Requested fix
Please make the UI Full Access state and persisted per-thread sandbox/approval state consistent across stop/restart/resume flows, especially for active-goal continuations. If per-thread permission overrides are intended, the UI should expose and repair them instead of showing Full Access while the thread runs under workspace-write / on-request.
9 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
Adding another report that this still appears to reproduce on a newer Codex Desktop build and is not macOS-specific.
Observed behavior from the reporter:
Current macOS environment where this was reported:
26.609.4111427.0(26A5353q)codex --version:codex-cli 0.128.0This matches the suspected resume/session state issue here: the active thread/goal seems to retain or re-enter an approval-requiring execution state after app restart/resume, even though the user believes Full Access is enabled. The key distinguishing signal is that it does not happen when the app remains open from goal start through completion; it appears after closing Codex during an unfinished goal and later continuing it.
This looks like an effective-policy drift bug, not just an annoying approval prompt.
The user is making a decision from one surface:
but execution is governed by another surface:
I would make the resumed turn contract explicit: before the next model turn starts, Codex should resolve one effective execution policy and show that same policy everywhere the user is asked to reason about access.
If a saved per-thread policy wins over the global Full Access setting, that is fine as a product decision, but it should be visible as the active thread policy. If Full Access wins, the persisted per-thread row should be repaired or ignored before execution starts.
The regression I would pin is:
The failure state should not be "UI says Full Access, turn context says workspace-write." That leaves the user debugging a policy they cannot see and makes permission prompts look random.
The useful invariant is simple: one resumed turn, one effective policy record, and every renderer reads from it before showing the run as ready.
Adding another concrete Windows reproduction with local evidence.
Environment:
Codex Desktop0.140.0-alpha.2C:\Users\mattr\Documents\Repositories\Space Survivors019ec937-b8df-73c2-9530-325e712be3f5C:\Users\mattr\.codex\sessions\2026\06\15\rollout-2026-06-15T12-58-53-019ec937-b8df-73c2-9530-325e712be3f5.jsonlUser-visible state:
Full accessselected.C:\Users\mattr\.codex\config.tomlcontains:approval_policy = neversandbox_mode = danger-full-access[windows] sandbox = elevatedC:\Users\mattr\.codex\.codex-global-state.jsoncontainsagent-mode:full-access.approvalPolicy:neverandsandboxPolicy:{type:dangerFullAccess}.Actual first turn context injected into the model contradicted all of that:
sandbox_modewasworkspace-writeand network was restricted.turn_contextfor the same session had:approval_policy:on-requestsandbox_policy:{type:workspace-write,network_access:false,...}permission_profile:{type:managed,file_system:{type:restricted,...}}Impact:
C:\Program Files (x86)\Steam\steamapps\common\Soulstone Survivors.sandbox_permissions:require_escalated, which caused an approval popup even though the UI and config were Full Access/never.danger-full-accessandapproval policy: never.This appears to be the same effective-policy drift described above: persisted UI/config/global thread state says Full Access, but the first turn in the thread can still receive a workspace-write/on-request execution contract.
I can reproduce the same effective-state drift on a long-running Linux remote/workspace session.
Sanitized observation:
approval_policy = "never"andsandbox_mode = "danger-full-access".turn_context/world_statechanged the effective context toapproval_policy=on-request,sandbox=workspace-write, andpermission_profile=managed.This looks consistent with a per-thread runtime/profile override being rehydrated independently of the user-level Full Access setting. A visible event that identifies the policy source and a way to restore the selected effective profile without restarting the thread would make this diagnosable.
I am intentionally not attaching the full rollout JSONL because it contains local paths and task content; I can provide a minimally redacted context diff if maintainers request it.
Additional reproducible variant on Windows involving an existing child task resumed through
send_message_to_thread.Environment:
019fb118-fc41-7001-84ca-b2536ce1723b0.146.0-alpha.3.1Trace:
approval_policy=neversandbox_policy=danger-full-accesspermission_profile=disabled2026-07-31T06:10:48Z, the parent calledsend_message_to_threadfor the child.2026-07-31T06:10:52.081Z, the child received a host-generatedthread_settings_appliedevent setting:approval_policy=on-requestpermission_profile=managed2026-07-31T06:10:58Z, the resumed child turn ran with:sandbox_policy=workspace-writeapproval_policy=on-requestpermission_profile=managedNo user permission-setting action occurred between these events. The UI continued to display Full Access.
This caused repeated approval prompts for read-only commands. One in-worktree read was unnecessarily marked
require_escalatedby the agent, but a later outside-worktree read required approval specifically because the host had already downgraded the effective profile.This appears to isolate the existing-task background resume/
send_message_to_threadpath as another trigger for the UI/runtime permission-state divergence.I hit what appears to be the same UI/per-task-state mismatch on Windows Codex Desktop [26.814.41407].
This task started in “Ask for approvals.” During the task I changed the UI to “Full access,” and the banner explicitly said it could run commands with network access without approval. However, the active task continued asking for terminal approval.
After the task completed and I returned to it, the UI had reverted to “Ask for approvals” and prompted me to choose Auto-approve or keep the default. This suggests the active task retained its original on-request permission snapshot, or Full Access was only displayed in the UI and never persisted to the task.
Configuration-layer finding (Windows Desktop; not a separate resume-path reproduction)
Environment
26.814.5517.00.148.0-alpha.15Visible configuration
Local audit
sandbox_mode = "danger-full-access"approval_policy = "on-request".codex/config.tomloverride:approval_policy = "on-request"Result after repair
never.approval_policy=neversandbox_policy=danger-full-accesspermission_profile=disabledRelevance to this issue
This report does not independently reproduce the resume regression: the observed prompts were explainable by user- and project-level configuration. It shows why the task should expose the source of its effective policy. A user needs to see whether
on-requestcomes from user config, trusted-project config, or persisted task state; otherwise a genuine UI/runtime mismatch and an intentional configuration choice look the same.Related but distinct reproduction: #40125. This issue covers permission drift when resuming an existing thread; #40125 captures a new
create_threadworktree child starting its very first turn ason-request/managed even though the parent, host selection, and all config layers were verifiednever+ Full Access. The child-creation API exposes no permission override.