Codex Desktop: existing task repeatedly reverts to on-request approvals despite full-access/no-approval settings

Open 💬 7 comments Opened Jul 13, 2026 by Clouddylol
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

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

  1. Open existing task 019dfee1-c0dd-7323-966b-d9f63460807f.
  2. Continue it from another Codex task using send_message_to_thread.
  3. Ask it to edit a file inside E:\Microbot-nightly.
  4. Observe a file-edit approval prompt.
  5. Click Allow always.
  6. Ask/allow another edit.
  7. 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-request
  • sandbox_policy = managed/restricted

Even after manually setting:

  • approval_mode = never
  • sandbox_policy = {"type":"disabled"}

The JSON UI mirror at:

C:\Users\Clouddy\.codex\.codex-global-state.json

also gets rewritten from:

  • :danger-full-access
  • approvalPolicy: never

back to:

  • :workspace
  • approvalPolicy: 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.

View original on GitHub ↗

7 Comments

github-actions[bot] contributor · 1 month ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #32165
  • #32626
  • #32763
  • #32239
  • #32338

Powered by Codex Action

Clouddylol · 1 month ago

the fact there are multiple duplicate issues and they just dont give a single fuck.

bbingz · 1 month ago

Analysis (community)

Residual analysis for #32862 (resumed task reverts to on-request approvals) under docs/contributing.md — invitation-only. No unsolicited PR.

Root-cause hypothesis

The historical approval_policy is persisted (ThreadMetadata.approval_mode) but never auto-restored on resume — resume restores model/provider/reasoning_effort and (since #34664) approvals_reviewer, but not approval_policy — so a thread created under Never/full-access rehydrates to the config default OnRequest whenever the resume request omits an explicit override. Your 0.128-era vscode task resumed by a 0.144 controller is exactly that case. Verified at HEAD 4c43465133:

1. The restore gap, precisely. merge_persisted_resume_metadata (codex-rs/app-server/src/request_processors/thread_processor.rs:151-169) copies only model, model_provider, and model_reasoning_effort into the overrides; merge_persisted_approvals_reviewer (:171-189, added by #34664) restores only the reviewer. Neither touches approval_policy. When the resume request carries no approval_policy override, 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-derives OnRequest; 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_policy IS applied via build_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 sends approval_policy on every resume would not see this. The Desktop send_message_to_thread continuation path doesn't send it.

3. The fix is mechanical and mirrors an existing pattern. Add a merge_persisted_approval_policy alongside :151-189: when no explicit approval_policy override is present, restore the most recent historical value from ThreadMetadata.approval_mode (and/or the persisted ThreadSettingsSnapshot.approval_policy in RolloutItem::TurnContext), with the same explicit-override-wins short-circuit the reviewer merge uses. One risk worth stating: ThreadMetadata.sandbox_policy is 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 — the tokio::select! has only cancel_token.cancelled() => Abort and decision = fut; under the default ApprovalsReviewer::User config (the Guardian auto-review deadline at guardian/review_session.rs:905-911 doesn't apply), if the approval future never resolves the thread waits in WaitingOnApproval forever. A third select arm with a generous timeout (e.g. 10 min, returning Abort/a new TimedOut variant with a distinct UI flag) unsticks the permanent hang.
  • Pending approvals are in-memory oneshots (core/src/state/turn.rs:89, HashMap<String, oneshot::Sender<ReviewDecision>>) with three silent-collapse paths: overwrite of the same call_id (session/mod.rs:2310-2322 / :2388-2401 — the dropped sender resolves the first waiter to Abort via unwrap_or(ReviewDecision::Abort) at :2371/:2413, with only a warn!), cancellation (codex_delegate.rs:928-938), and turn teardown (clear_pending_waiters). Persisting ApprovalLifecycle events 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 Never with no request override → rehydrated approval_policy == Never (today: OnRequest); (2) explicit OnRequest in 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 same call_id resolves the first to a visible non-frozen state (today: silent Abort). Happy to draft the test patch if a maintainer wants it. No unsolicited PR from me.

pasihaapasaari-sys · 22 days ago

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:

  • "Allow similar commands"
  • "Allow all edits"

Examples include:

  • Reading internal Codex reference files under:

.codex\plugins\cache\...

  • Harmless PowerShell diagnostics (e.g. Write-Output 'abc')
  • Python read-only validation of generated PDFs
  • Microsoft Word/PDF rendering and QA checks

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:

  • One approval for reading Codex's internal reference/documentation files.
  • One approval for equivalent read-only validation commands during the same task.
  • "Allow similar commands" should apply to subsequent commands of the same type, even if temporary filenames or generated paths differ.

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.

bbingz · 22 days ago

@pasihaapasaari-sys — worth separating these; they look like two different defects on the same surface.

  1. What this issue traces: the historical approval_policy is 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 only model, model_provider and model_reasoning_effort; merge_persisted_approvals_reviewer (:171-189) restores only the reviewer. Neither touches approval_policy, so a thread created under full-access rehydrates to the config default OnRequest. Symptom: settings still look right, and the whole task reverts to prompting after a resume or a background continuation.
  1. What you are describing: approvals are granted, but the matching is too narrow, so each new temp path counts as a fresh command inside one session. That is approval-rule scope, not policy rehydration — a fix for (1) would not help you.

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.

almiho · 13 days ago

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_command call with sandbox_permissions=require_escalated and 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.

irgmedeiros · 1 day ago

I can reproduce a closely related case on macOS in the Codex desktop app:

  1. A controller task creates and delegates work to a new project task in a Codex worktree.
  2. The user selects the persistent “approve for me”/allow option.
  3. The delegated task still enters waitingOnApproval and 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.