Codex Desktop: existing task repeatedly reverts to on-request approvals despite full-access/no-approval settings
Summary
An existing Codex Desktop task repeatedly asks for file-edit approval even after the user chooses Allow always and even after global/per-task settings are changed to full-access/no-approval. The task rehydrates back to approval_mode = on-request whenever continued through background thread messaging.
Environment
- OS: Windows
- App: OpenAI Codex / ChatGPT Desktop
- App package observed:
OpenAI.Codex_26.707.8479.0_x64__2p2nqsd0c76g0 - Affected task/thread:
019dfee1-c0dd-7323-966b-d9f63460807f - Task title:
Microbot Recode - Project path:
E:\Microbot-nightly - Old task source in local state:
vscode - Old task CLI version in local state:
0.128.0-alpha.1 - Current controller task CLI version observed separately:
0.144.0-alpha.4
Expected behavior
When permissions are set to full access / never ask, and the user chooses Allow always, Codex should not repeatedly prompt:
Allow ChatGPT to edit the following file?
Normal edits inside the trusted project should proceed without repeated modal approval prompts.
Actual behavior
The task repeatedly shows file-edit approval prompts for normal edits inside the trusted project, for example:
E:/Microbot-nightly/runelite-client/src/main/java/.../Rs2Dialogue.java
Clicking Allow always does not persist. The same approval prompt appears again shortly after on the next edit attempt.
Reproduction steps
- Open existing task
019dfee1-c0dd-7323-966b-d9f63460807f. - Continue it from another Codex task using
send_message_to_thread. - Ask it to edit a file inside
E:\Microbot-nightly. - Observe a file-edit approval prompt.
- Click Allow always.
- Ask/allow another edit.
- Observe that the approval prompt returns.
Local state evidence
The task row in:
C:\Users\Clouddy\.codex\state_5.sqlite
repeatedly rewrites to:
approval_mode = on-requestsandbox_policy = managed/restricted
Even after manually setting:
approval_mode = neversandbox_policy = {"type":"disabled"}
The JSON UI mirror at:
C:\Users\Clouddy\.codex\.codex-global-state.json
also gets rewritten from:
:danger-full-accessapprovalPolicy: never
back to:
:workspaceapprovalPolicy: on-request
when the old task is resumed.
Additional observed behavior
A canary edit attempt after permission repair still triggered approval immediately. The dev task reported:
Editing still triggered an approval/pending prompt, so I terminated it immediately. No new patch landed.
The old task is therefore unusable for unattended or delegated code edits even though the project is trusted and the intended global policy is no approvals.
Impact
This breaks long-running multi-task workflows where one task is the controller and another specific existing task is the required development task. It causes repeated blocking approval popups and makes Allow always unreliable.
Severity
High. It prevents unattended automation and invalidates the user's selected persistent permission mode.
Requested fix
Existing tasks should respect current global/project/task permission settings when resumed, or there should be a supported way to permanently migrate an old task from legacy on-request permissions to full-access/never.
Allow always must persist for the task/project and should not be overwritten by task rehydration.
7 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
the fact there are multiple duplicate issues and they just dont give a single fuck.
Analysis (community)
Residual analysis for #32862 (resumed task reverts to
on-requestapprovals) under docs/contributing.md — invitation-only. No unsolicited PR.Root-cause hypothesis
The historical
approval_policyis persisted (ThreadMetadata.approval_mode) but never auto-restored on resume — resume restores model/provider/reasoning_effort and (since #34664)approvals_reviewer, but notapproval_policy— so a thread created underNever/full-accessrehydrates to the config defaultOnRequestwhenever the resume request omits an explicit override. Your 0.128-eravscodetask resumed by a 0.144 controller is exactly that case. Verified at HEAD4c43465133:1. The restore gap, precisely.
merge_persisted_resume_metadata(codex-rs/app-server/src/request_processors/thread_processor.rs:151-169) copies onlymodel,model_provider, andmodel_reasoning_effortinto the overrides;merge_persisted_approvals_reviewer(:171-189, added by #34664) restores only the reviewer. Neither touchesapproval_policy. When the resume request carries noapproval_policyoverride, the rehydrated config falls back to the default —OnRequest— and every file edit re-prompts. Clicking Allow always updates the live session, but the next background-thread continuation resumes from persisted state again and re-derivesOnRequest; that is why the prompt "returns shortly after," matching your reproduction steps 5–7.2. One precision on scope. The request override is not ignored everywhere: on the cold-rehydration path, an explicit
request.approval_policyIS applied viabuild_thread_config_overrides(thread_processor.rs:1404-1405). The match-only/ignored path (:79-86, sole caller:3493) exists only in the reconnect-to-running-thread branch. So the defect is specifically the missing auto-restore of the historical value, not a broken override channel — a client that explicitly sendsapproval_policyon every resume would not see this. The Desktopsend_message_to_threadcontinuation path doesn't send it.3. The fix is mechanical and mirrors an existing pattern. Add a
merge_persisted_approval_policyalongside:151-189: when no explicitapproval_policyoverride is present, restore the most recent historical value fromThreadMetadata.approval_mode(and/or the persistedThreadSettingsSnapshot.approval_policyinRolloutItem::TurnContext), with the same explicit-override-wins short-circuit the reviewer merge uses. One risk worth stating:ThreadMetadata.sandbox_policyis persisted-and-not-restored by the same gap, but restoring sandbox policy is an escalation-risk change and should be assessed separately from restoring approval policy (a downgrade-to-less-prompting is the direction users are asking for here; auto-restoring a broader sandbox would need the inverse scrutiny).Adjacent, same approval surface (distinct defects, for triage — the "freeze" siblings of this issue): while verifying this path I confirmed two related OSS residuals that explain the stuck-dialog reports in the #32165/#32626/#32763/#32239 dup candidates:
await_approval_with_cancel(codex-rs/core/src/codex_delegate.rs:916-944) has no timeout branch — thetokio::select!has onlycancel_token.cancelled() => Abortanddecision = fut; under the defaultApprovalsReviewer::Userconfig (the Guardian auto-review deadline atguardian/review_session.rs:905-911doesn't apply), if the approval future never resolves the thread waits inWaitingOnApprovalforever. A third select arm with a generous timeout (e.g. 10 min, returningAbort/a newTimedOutvariant with a distinct UI flag) unsticks the permanent hang.core/src/state/turn.rs:89,HashMap<String, oneshot::Sender<ReviewDecision>>) with three silent-collapse paths: overwrite of the samecall_id(session/mod.rs:2310-2322/:2388-2401— the dropped sender resolves the first waiter toAbortviaunwrap_or(ReviewDecision::Abort)at:2371/:2413, with only awarn!), cancellation (codex_delegate.rs:928-938), and turn teardown (clear_pending_waiters). PersistingApprovalLifecycleevents to the rollout (as #29627 commenters proposed) and re-presenting unresolved approvals on resume would make the dialog state survive restarts instead of silently collapsing.Fail-first tests I'd want before any merge: (1) resume a thread historically
Neverwith no request override → rehydratedapproval_policy == Never(today:OnRequest); (2) explicitOnRequestin the resume request still wins over the historical value (override precedence preserved); (3) a never-resolved approval future returns within the timeout rather than hanging (today: hangs indefinitely); (4) a second request on the samecall_idresolves the first to a visible non-frozen state (today: silentAbort). Happy to draft the test patch if a maintainer wants it. No unsolicited PR from me.I'm experiencing the same issue on Windows with Codex Desktop.
During long-running document generation (using the Documents skill), Codex repeatedly asks for permission despite repeatedly selecting:
Examples include:
.codex\plugins\cache\...
Write-Output 'abc')The prompts continue even though they are the same class of read-only operations. It appears the "Allow similar commands" matching is too strict, likely because temporary file paths change between commands.
For a single architecture document, I had to approve dozens of nearly identical commands, which significantly interrupted the workflow.
Expected behavior:
This is a UX issue rather than a security concern. The underlying document-generation and QA process works well, but the repeated approval prompts make long-running document-generation tasks much less usable.
@pasihaapasaari-sys — worth separating these; they look like two different defects on the same surface.
approval_policyis persisted (ThreadMetadata.approval_mode) but never auto-restored on resume.merge_persisted_resume_metadata(codex-rs/app-server/src/request_processors/thread_processor.rs:151-169) copies onlymodel,model_providerandmodel_reasoning_effort;merge_persisted_approvals_reviewer(:171-189) restores only the reviewer. Neither touchesapproval_policy, so a thread created under full-access rehydrates to the config defaultOnRequest. Symptom: settings still look right, and the whole task reverts to prompting after a resume or a background continuation.The test that separates them: if your prompts recur within a single uninterrupted session (no resume, no background continuation), it is (2) and probably deserves its own issue so both can be fixed independently. If they come back specifically after the task is resumed or continues in the background, it is this one.
Additional macOS/Codex App reproduction from session
019fab18-fda7-7cd1-ba04-c9d793bf1202(Codex CLI runtime 0.142.5; Darwin 25.5.0 arm64).The user explicitly granted full access for the task and repeatedly instructed the agent not to request per-command approvals. The agent nevertheless issued an
exec_commandcall withsandbox_permissions=require_escalatedand three shell segments joined by semicolons: a read-only diff, a network audit, and another read-only diff check. The app displayed another blocking approval modal and offered to persist a prefix for only the first segment.Expected: full-access/no-approval state should persist for the thread. Independently, the agent/runtime should split mixed commands, avoid escalating read-only segments, and reuse already-approved scoped prefixes. A user instruction not to interrupt unattended work should not result in repeated approval modals for routine checks.
Actual: the approval dialog returned after the user had explicitly objected to the same behavior. This blocked a long-running unattended workflow from the mobile UI.
No secrets or project-specific data are included here. The agent classified its own orchestration mistake as over-escalating a semicolon-chained command, while the recurring prompt/persistence behavior matches this issue.
I can reproduce a closely related case on macOS in the Codex desktop app:
waitingOnApprovaland repeatedly requests permission for ordinary in-scope file changes.This happened with a newly created delegated task, so the behavior does not appear limited to legacy task rehydration or Windows. Expected: the user’s persistent approval choice is inherited or otherwise respected by the delegated task for its designated project/worktree.
I have intentionally omitted task IDs, filesystem paths, repository details, and prompt/project content.