Windows Desktop: new threads/handoffs persist as on-request/workspaceWrite instead of inheriting visible Full Access state

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

Summary

On Windows Codex Desktop, newly created threads can persist as approvalPolicy = on-request / sandboxPolicy.type = workspaceWrite even when the user workflow appears to be operating in a Full Access-like mode.

This is reproducible with:

  • ordinary fresh test threads
  • handoff-created threads

and does not require Goal auto-continuation.

Environment

  • Codex Desktop app: OpenAI.Codex_26.527.7698.0_x64__2p2nqsd0c76g0
  • Platform: Windows

Expected

If the user has switched into a Full Access-like mode in the app, newly created threads should inherit that mode consistently, or the UI should clearly indicate that new threads will still be created with approval prompts.

Actual

Newly created threads are persisted as:

  • approvalPolicy = on-request
  • approvalsReviewer = guardian_subagent
  • sandboxPolicy.type = workspaceWrite

This then causes approval prompts to originate from those new threads.

Repro

  1. Open Codex Desktop on Windows.
  2. Work in a thread until the UI/workflow suggests Full Access-like behavior is active.
  3. Create a new thread from that session, or create a handoff into a new thread.
  4. Let the new thread do almost nothing, e.g. only answer once with a short reply.
  5. Inspect persisted thread state in C:\Users\강인철\.codex\.codex-global-state.json.
  6. Observe that the new thread is stored as on-request / guardian_subagent / workspaceWrite.

Concrete repro evidence

Host-level persisted mode in app state:

  • agent-mode-by-host-id.local = guardian-approvals
  • preferred-non-full-access-agent-mode-by-host-id.local = guardian-approvals

Fresh / recent threads created during reproduction:

  • current thread 019e866c-0a1c-7601-a60c-686b686bcc5c -> on-request / guardian_subagent / workspaceWrite
  • test thread 019e8764-2aa9-73d2-9b3d-87ecb202af5a -> on-request / guardian_subagent / workspaceWrite
  • test thread 019e8765-f908-7410-b44d-443df7934c73 -> on-request / guardian_subagent / workspaceWrite
  • test thread 019e877d-fb12-7683-8033-3f909b8ca714 -> on-request / guardian_subagent / workspaceWrite
  • handoff-derived thread 019e8689-b909-7ed1-a141-d0b3323a21cf -> on-request / guardian_subagent / workspaceWrite

Additional pattern:

  • among currently stored thread states on this machine, only 1 thread had approvalPolicy = never
  • 60 threads had approvalPolicy = on-request

Why this seems like a bug

This does not look like a one-off stuck thread.

It looks like one of:

  • thread creation is not inheriting the currently visible Full Access selection
  • host-level permission mode is not being committed correctly before thread creation
  • handoff/new-thread creation is using a different policy source than the visible UI state
  • the app is exposing a misleading Full Access state to the user while still creating threads in guardian-approvals mode

Related

This may be related to, but broader than, the behavior discussed in #24300.

I also added Windows reproduction details there in a comment:

View original on GitHub ↗

8 Comments

github-actions[bot] contributor · 1 month ago

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

  • #25590
  • #24739

Powered by Codex Action

andrewkangkr · 1 month ago

Small follow-up after checking the related discussion in #24300:

  • an OpenAI collaborator there said the currently known issue can be worked around by sending a dummy prompt after changing permissions and before creating a Goal
  • however, my Windows Desktop repro appears broader than that specific Goal-related case

In my reproduction:

  • this happens even without Goal auto-continuation
  • it also happens for newly created test threads that already received a user prompt and then stopped

Concrete examples from my local persisted thread state:

  • 019e8764-2aa9-73d2-9b3d-87ecb202af5a -> on-request / guardian_subagent / workspaceWrite
  • 019e8765-f908-7410-b44d-443df7934c73 -> on-request / guardian_subagent / workspaceWrite
  • 019e877d-fb12-7683-8033-3f909b8ca714 -> on-request / guardian_subagent / workspaceWrite

Those were fresh test threads that only received a short user prompt and replied once.

So if this is the same root cause, it seems to affect thread creation / policy inheritance more generally on Windows Desktop, not only the "change permission -> create Goal" path.

andrewkangkr · 1 month ago

Additional Windows Desktop follow-up from June 3, 2026:

I have a clearer split now between auto-review vs thread policy.

What I am seeing is not just "auto-review failed to approve something".
Instead, the underlying thread policy itself appears to revert back to restrictive settings after thread execution starts.

New observation

After switching the app-level host mode to Full Access, I could verify the persisted host value became:

  • agent-mode-by-host-id.local = full-access

I then created fresh threads and briefly saw cases that looked consistent with:

  • approvalPolicy = never
  • sandboxPolicy.type = dangerFullAccess

However, after the thread actually started running / continuing, persisted state later showed the same thread as:

  • approvalPolicy = on-request
  • sandboxPolicy.type = workspaceWrite

Why this matters

This suggests the problem may be broader than "new thread creation inherits the wrong initial settings".
It may also involve policy reversion during thread start / resume / goal-setting / delegated execution.

So the bug shape now looks more like:

  1. visible/app-level Full Access can be selected successfully
  2. a new thread may initially appear consistent with Full Access
  3. once the thread actually begins execution, persisted thread policy can be rewritten back to on-request / workspaceWrite
  4. approval popups then come from that downgraded persisted policy

Important distinction: auto-review vs approval policy

At least in my local investigation, auto-review seems to be a separate concept from the popup itself:

  • auto-review / reviewer affects who reviews an approval request
  • approvalPolicy determines whether the thread is effectively never vs on-request

So the user-facing symptom can look like "auto-review is broken", while the deeper issue is actually that the thread got persisted back to on-request.

Scope note

This still does not look Goal-only to me.
I have seen related behavior in:

  • ordinary test threads
  • handoff/delegated threads
  • a Goal-adjacent AKN thread where the thread log later said it set an active goal for itself

So Goal may be one trigger path, but not the whole story.

If useful, I can provide another tightly scoped repro sequence specifically for:

  • create thread under Full Access
  • verify persisted never / dangerFullAccess
  • let thread actually start/continue
  • observe persisted reversion to on-request / workspaceWrite
andrewkangkr · 1 month ago

Additional Windows Desktop / mobile-resume detail that seems worth tracking separately even if the original approvalPolicy drift is fixed.

New behavior observed on June 4, 2026 (KST):

  • I had a parked handoff thread whose explicit instruction was "do not set a goal or proceed; just park the handoff".
  • The parked thread was projectless / handoff-shell style, with cwd like:

C:\Users\<USER>\Documents\Codex\2026-06-03\specialization-layer-handoff-parked

  • The canonical source-of-truth repo for the work was elsewhere:

C:\Users\<USER>\Documents\Codex\2026-05-24\hermes-project-os-expert-agent\expert-repository-poc

After resuming from mobile and sending short messages like:

  • "남은 slice 2개인거지?"
  • "frontier는 어떤 상태?"
  • "1순위부터 해보자"

the parked thread stopped behaving like a parked handoff and resumed actual work. It started trying to read/edit files in the canonical repo outside the current workspace and produced approval prompts such as:

  • "allow reading and then editing the canonical expert repo outside the current workspace..."
  • reads of tools/validate.py
  • reads of tools/test_validate_specialization.py
  • planned patching of latest.md

In other words, the trigger was not a broad new user task from scratch; it was a few short follow-up messages inside a parked handoff thread. The app seems to treat that parked thread as a live execution surface even though its workspace is only a handoff shell, not the real repo.

Separately, one of these parked threads later hit a Windows stale-path resume error even though the JSONL file still existed on disk. The error compared:

  • requested: C:\Users\<USER>\.codex\sessions\...jsonl
  • active: \\?\C:\Users\<USER>\.codex\sessions\...jsonl

Those are the same file, so this looks like another Windows path-normalization bug on top of the workspace mismatch. (Related in spirit to #24178.)

My current working theory:

  1. Parked handoff threads are not strongly isolated from real execution after mobile follow-up input.
  2. Once they resume, Codex continues from the parked thread's current workspace instead of forcing a proper canonical-repo work thread.
  3. That leads to misleading outside-workspace approval prompts.
  4. On Windows, some of those same threads can later fail resume due to raw-string path comparison (C:\... vs \\?\C:\...).

Practical expectation:

  • If a thread is meant to be parked/handoff-only, short follow-up questions should not silently turn it into a real editing thread against a different canonical repo.
  • If work does resume, Codex should either force a proper workspace transition or make the mismatch explicit before attempting outside-workspace reads/edits.
bakemocho · 1 month ago

I have an additional macOS reproduction that looks like the same permission
profile reversion class, but through the Goal quota-reset resume path rather
than Windows new-thread creation.

Observed sequence:

  • A Goal-driven session stopped because of quota limit.
  • Another Goal-driven session showed the same kind of stop.
  • I quit Codex Desktop, rebooted macOS, reopened Codex, used the quota reset

feature, and resumed the existing Goal session.

  • Before pressing resume, the Japanese UI showed ゴールの使用回数制限あり.

I did not confirm what the English UI label says.

  • Toggling the app UI/permission button to Full Access, and trying related UI

permission changes, did not recover this session.

  • After resume, the app/global state still appeared to be full access, but the

resumed thread asked for approvals.

Sanitized local state:

  • global app state included agent-mode = full-access and

agent-mode-by-host-id.local = full-access

  • the affected thread-specific entry still had

activePermissionProfile.id = :workspace

  • the same entry had approvalPolicy = on-request
  • the same entry had sandboxPolicy.type = workspaceWrite
  • the resumed runtime still reported a seatbelt sandbox with network disabled

This seems to add a narrower trigger to the pattern already discussed here:

  1. the UI/global mode can be full-access,
  2. an existing Goal session is resumed after quota-limit recovery,
  3. the resumed thread keeps or receives a stale restricted thread-specific

permission profile,

  1. later UI permission changes do not necessarily repair that thread-specific

state,

  1. the running turn then behaves as workspace-write/on-request.

Expected behavior: after quota reset, resuming an existing Goal session should
either reconcile the thread-specific permission profile with the current
full-access app mode, or make the per-thread restricted override visible before
the resume starts.

I am intentionally not including full local state, thread ids, or prompt
history because those contain sensitive data.

bakemocho · 1 month ago

Small macOS follow-up to my previous comment.

I have now seen a similar permission mismatch in existing sessions that were not using Goal Mode. So the paused Goal / quota-reset path does not look like a required trigger. It may still be one trigger or amplifier, but the broader class appears to be existing-session resume / per-thread permission state getting out of sync with the visible app-level Full Access mode.

Additional recovery observation:

After restarting Codex Desktop, the same affected session now appears consistent across the three surfaces I checked:

  • runtime no longer exposes CODEX_SANDBOX=seatbelt or CODEX_SANDBOX_NETWORK_DISABLED=1
  • .codex-global-state.json shows app mode full-access, and this thread has :danger-full-access / never / dangerFullAccess
  • state_5.sqlite shows this thread as approval_mode=never and sandbox_policy={"type":"disabled"}

So the current evidence from my macOS side is:

  1. UI/global Full Access can diverge from a resumed existing thread's effective policy.
  2. This is not necessarily Goal-only.
  3. Restarting the Desktop app can reconcile the affected thread back to the expected Full Access state, at least in this case.

I am still omitting local thread ids and prompt history because they contain private data.

bakemocho · 26 days ago

Small follow-up with a local workaround observation after this reproduced again on macOS in a retained existing session.

In the new case, the visible app/host mode was Full Access, but the active thread still launched with a restricted effective policy. The useful split was checking two persisted state surfaces for the affected thread:

  • the thread row in state_5.sqlite
  • the thread entry under heartbeat-thread-permissions-by-id in .codex-global-state.json

The emergency workaround that recovered the persisted state for me was to back up both files, then align both surfaces for the affected thread:

  • state_5.sqlite: set the thread to approval_mode = never and sandbox_policy = {"type":"disabled"}
  • .codex-global-state.json: set the thread entry to activePermissionProfile.id = :danger-full-access, approvalPolicy = never, and sandboxPolicy.type = dangerFullAccess

A reload/resume of the affected thread is still required after the state repair. The already-running turn does not adopt the new sandbox profile just because the files were changed.

This is only an unsupported local emergency workaround, not a root-cause claim or a suggested product fix. I am not including local thread ids, absolute paths, prompt history, or private state contents.

sunjiajunsunjiajun · 2 days ago

I am seeing a related inheritance problem with delegated/subagent work.

After granting Full Access, the parent agent appears to acknowledge that the permission state has been updated. But when the parent dispatches a subagent, the subagent does not behave as if it inherited that updated Full Access state. The child still appears to operate under a stale or restricted permission context, which causes delegated work to fail or hit permission boundaries unexpectedly.

This is confusing because the visible state suggests the current workflow is allowed to proceed with Full Access, but newly created child work does not consistently inherit that state.