Skip to content

fix(codex): register Desktop projects and bind managed threads - #1442

Merged
Neonforge98 merged 3 commits into
developfrom
codex/fix-codex-desktop-listability
Sep 9, 2026
Merged

Neonforge98 merged 3 commits into
developfrom
codex/fix-codex-desktop-listability

Conversation

@Neonforge98

@Neonforge98 Neonforge98 commented Sep 9, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

New ORG2 Codex conversations are persisted and readable by ID but absent from Codex Desktop's sidebar/search catalog. Ordinary managed turns use codex exec, producing source=exec; the Desktop default thread/list excludes that source. Project metadata is not the cause: the affected records have the same cwd/project fields as visible conversations. Prior native-continuation work only enabled app-server for recovery episodes, leaving normal creation on exec. A directory-only repair also does not register a missing Desktop project or explicitly bind worktree-executed sessions to their repository project.

Solution

Route ordinary managed Codex turns through the existing app-server transport. Before a fresh thread is created, use the native project/list API to find the Desktop project whose root matches the ORG2 session's repository. Reuse that project without changing its name or metadata; if absent, register it through project/create with a stable path-derived idempotency key. Supply the returned projectId to thread/start. Registration uses the repository root even when execution happens in a separate worktree. Resumes preserve the existing native project assignment.

Reuse account-scoped authentication, Desktop binary/index selection, permission/model handling, developer instructions, and bounded turn cleanup. Preserve extra workspace roots through native config. No private database writes or UI filtering are used.

The opt-in real Codex protocol test now registers and lists actual native project objects, verifies reuse without duplicates, and creates a thread executing outside the project root. After fresh and resumed turns in separate processes, querying by the target projectId must return the same thread once; the unrelated project must have no members. The test also checks project name/root metadata and literal user text using local Responses fixtures and isolated account/index/workspace directories.

Potential risks

Codex App catalog/sidebar refresh is owned by the App (periodic state-DB reconcile plus focus refetch, see the discovery section below); a fresh thread can take a few minutes to appear in a running App, and ORG2 cannot force it. Initial App listings reported projectId: null for fresh Astra threads. A later recheck of a fresh, still-unopened thread reported the correct existing sidebar project before any native App continuation. This corrects the earlier inference that continuation was required. The App's explicit thread/project assignment table had no entry for that thread; cwd-based sidebar grouping can supply the assignment after discovery. Automatic registration of an App-side project that does not already exist remains unresolved.

This changes the transport used by ordinary Codex sessions and selects the Desktop-compatible binary through the existing native path. Custom exec-only argument overrides do not apply to native JSON-RPC turns. Automatic project registration requires a Desktop binary supporting the experimental projects API; an unsupported/failed registration is surfaced rather than pretending project placement succeeded. A new workspace creates a durable native project item. An interrupted or failed first turn can leave an empty project; retries reuse it. Existing Desktop project names and metadata are preserved. Hosted/custom gateways, interactive approval flows, images, cancellation, and full rendered Desktop refresh were not exercised end to end in this PR; existing unit coverage runs, but the live fixture uses local HTTP responses without tools.

Existing exec-origin conversations are not relabeled or rewritten; resuming them does not promise to change their native source. Historical migration is separate from preventing new invisible threads. No database/schema migration, credential migration, dependency change, or private Codex SQLite write is introduced; project records are created through the native API. Revert this commit and rebuild to roll back the routing change; already-created native threads and projects remain in their store and can be managed through Desktop normally. The local application bundle was rebuilt from this head and launched for the live checks below.

Verification

  • cargo test --manifest-path src-tauri/Cargo.toml --lib agent_sessions::cli:: — 457 passed, 4 opt-in tests ignored, 0 failures.
  • From src-tauri: ORGII_NATIVE_CODEX_APP_BINARY=/Applications/ChatGPT.app/Contents/Resources/codex cargo test --lib live_native_fresh_and_resumed_turns_are_in_default_desktop_list -- --ignored --nocapture — passed with the installed Desktop binary, two local Responses calls, separate account/index/project/worktree directories, native project creation/reuse, fresh/resume turns, and process restart. Actual project/list records are checked for names/roots and uniqueness. thread/list filtered by the real target projectId returns the worktree-executed thread once after each turn; an unrelated project has no members. No real account requests or production data writes.
  • rustfmt --edition 2021 --check src-tauri/src/agent_sessions/cli/parsers/tests/codex_app_server_tests.rs src-tauri/src/agent_sessions/cli/tests/runner_command_tests.rs — passed.
  • Pre-commit: cd src-tauri && cargo clippy --lib --message-format=short -p org2 — passed; hooks ran without bypass.
  • git diff --check — passed; inspected the diff for secrets, private data, generated artifacts, and unrelated changes.
  • Refetched origin/develop; base remained current before commit (git rev-list --left-right --count HEAD...origin/develop returned 0/0).
  • Full workspace tests and hosted/custom-gateway end-to-end tests were not run. The subsequent live local UI/account checks are recorded below. No UI layout/copy changes; evidence targets the native list boundary, not a screenshot or a claim that Desktop refresh timing was tested.

Live acceptance follow-up

  • Head 77c97a290efa14dc8f68627edee45868930add05; pnpm run tauri:build:fast passed, and the resulting macOS bundle was launched. Codex bundled CLI 0.153.4 and Claude Code 2.1.263 were checked.
  • Created an Astra Medium conversation through the rendered ORG2 composer in the existing repository. Its first response succeeded. The native record had interactive source, the correct cwd and projectId, and was returned by native project-filtered listing. The initial Codex App task listing nevertheless had no project assignment. Continued the same UUID through the Codex App tool: the second response recalled the first marker. Afterwards App listing assigned it to the existing repository project. This proves post-load continuation/placement, not automatic placement before first open.
  • Separately exercised Claude Code / Fable 5.1 High through the rendered ORG2 composer: first and second turns succeeded on the same native UUID, and raw JSONL confirmed claude-fable-5-1 and the expected repository cwd. ORG2 initially displayed “No activity yet” after first completion; Reload recovered the actual history. This is an open hydration defect, not a passing initial-render result.
  • ORG2 “Open in Claude” opened that exact UUID in Claude App with both rounds visible and the repository group present. A third turn from Claude App recalled the marker successfully. Fresh automatic discovery before using Open in Claude was not established. This check does not claim unchanged reasoning effort: ORG2 selected High, while the opened native App displayed Low; the published metadata used the unsplit model variant and warrants separate investigation.
  • Re-ran the opt-in native fresh/resume/project test: passed. Executed the newly built test binary with agent_sessions::cli::session_runner::command_tests: 42 passed.
  • Test conversations were retained; no historical cleanup or direct Codex private-state writes were performed. Codex App sidebar UI automation remains unavailable; app-level listing and native RPC evidence are kept distinct.

Architecture and lifecycle review

Reviewed the changed call chain across the ten architecture layers: compilation, shared transport ownership, naming/comments, separation of recovery from transport, Codex-only defaults, domain boundaries, readability, serialized protocol, fresh/resume initialization, and unchanged account/model/cwd resolution. The source and project-membership invariants are owned by native project/thread creation rather than UI filtering or direct metadata repair. Repository identity is separated from the worktree execution directory. Broad unrelated frontend/type refactors are outside this bug fix.

Area Verdict Evidence Change or reason kept Verification
Background work keep Existing per-turn child plus a short-lived project RPC owner on fresh creation; bounded requests/pages Project discovery runs on a blocking worker with request timeouts and deadline; no idle polling/cache Native test exercises registration/reuse and restarts; child owners kill on drop
Memory keep Existing 256-entry channel and turn-scoped data No new retained cache or registry CLI tests and bounded native fixture
Scope/isolation keep Account CODEX_HOME separate from Desktop sqlite_home Existing identity/store resolution reused Real protocol with separate temporary homes
Rendering/hot path keep No React subscriptions or parser hot-loop changes Existing event path reused No rendered performance measurement
Provider Raw transition App/UI state Topology/boundary Expected invariant Observed evidence
Codex Fresh user/assistant turn Fresh isolated native process Local account home to Desktop index Project item exists with correct name/root; its projectId lists the worktree thread Real binary/local Responses fixture passed
Codex Resume/append Process restarted Same isolated homes Same thread/project IDs after restart; exactly one member in target project, none in unrelated project Real binary/local Responses fixture passed
Codex Hidden/idle/cancel/account switch Rendered Tauri/Desktop Live user UI and multiple identities No leaks or stale cross-account state Not run; no full lifecycle claim

Performance verdict: blocked for full rendered lifecycle acceptance because Tauri hidden/idle/cancel and multi-account measurements were not run. The protocol/listability checks above passed; this PR makes no measured performance-improvement claim.

Desktop UI automation was attempted but the Computer Use tool prohibits access to Codex Desktop. Project registration and membership were verified through native APIs; actual sidebar rendering and clicking to resume remain unverified.

App discovery boundary, resolved by live check (2026-09-09 00:34–00:45 local)

Read-only inspection of the installed App and a live run against it identify the actual mechanism, replacing the earlier "unresolved runtime handoff" note:

  • The running Codex App owns its own codex app-server (pid 97737, stdio) and a private catalog (thread_history_1.sqlite, table thread_history_projection_state). That server reconciles the shared state DB (state_5.sqlite, where this PR's project/create and thread/start write) into its catalog on its own cadence. A fresh ORG2 thread created at 00:34:10 entered the App catalog at 00:37:22 with no App interaction. The renderer's sidebar/search are query caches that refetch on window focus and invalidate on thread/started from the App's own connection, so an external process cannot push the update; it appears after the App's next reconcile and focus refetch.
  • Live evidence on head 77c97a290 (bundle /private/tmp/ORG2-native-integration-final.app): ORG2 created APPSYNC_0909_T1 (Codex, GPT-6 Astra Medium, repository ORGII). State DB row: source vscode, project_id 01a048d0… = the App's existing ORGII project, cwd /Users/vinceorz/Projects/ORGII. Before the App regained focus its ORGII section did not list the thread; after focus plus one reconcile the App search returned it tagged ORGII, and the sidebar listed it under ORGII. Opening it in the App rendered T1; a continuation sent from the App quoted the T1 marker and answered APPSYNC_0909_T2_OK in the same UUID, still under ORGII. The App appended to the same rollout file that ORG2's account profile links to.
  • Not part of this PR: ORG2 does not surface App-authored turns in the chat view of that managed session afterward (the event store holds them; the chat projection does not render them, and Reload/tab switch do not help). Tracked separately as a follow-up issue; it is a pre-existing native-session projection gap, not a project-registration regression.
  • Computer Use was allowed on the Codex App for this check at the user's direction. One stray continuation message was sent into the user's already-open Codex thread while locating the new thread; it is visible there and was not removed.

Shared-runtime feasibility check (2026-09-09)

Ran node /tmp/orgii-shared-runtime-probe.mjs against the installed native Codex binary using a fresh temporary CODEX_HOME and repository, a loopback WebSocket listener, and two initialized protocol clients. The creator called project/create and thread/start. The observer received both project/changed and thread/started. No real user prompt/model request, production database modification or App restart occurred. This establishes cross-client notification delivery within one app-server, not live Desktop project registration.

The installed App contains a local-daemon transport branch, but it requires an empty config-override list. Its current local launcher supplies a codex_app MCP override even in the missing-plugin branch, so setting CODEX_APP_SERVER_USE_LOCAL_DAEMON alone does not establish that connection. A separate CODEX_APP_SERVER_WS_URL transport branch exists. Switching an existing App to it would alter startup/runtime ownership and requires separate compatibility validation; it was not enabled in the user's running App. App sidebar project registration also remains separate from receiving native project/changed notifications.

Codex Desktop default thread/list excludes exec-origin threads even when their rollout and index rows exist. Route ordinary managed Codex turns through the existing native app-server path, independently of context recovery, so fresh sessions acquire an interactive source. Preserve extra workspace roots through native configuration.

Cover transport selection and writable roots with unit tests, and add an opt-in real Codex protocol test using isolated account/catalog homes and a local Responses fixture. Verify fresh and resumed default-list visibility with a stable id after process restart. CLI suite: 457 passed; native protocol test passed. Existing exec-origin histories are not rewritten.

Pre-commit hook ran. Total eslint: 0, total circular: 1
Separate the project workspace from account and Desktop index directories in the real native protocol fixture. After fresh and resumed turns, assert the target project lists the same thread exactly once while an unrelated project and both storage directories list nothing.

The isolated real Codex binary test passed using local Responses fixtures; no production conversations were modified.

Pre-commit hook ran. Total eslint: 0, total circular: 1
Resolve the session repository against the native project registry before thread creation. Reuse existing projects without renaming them, create missing projects with an idempotent native API request, and pass the real projectId to thread/start. Keep repository identity separate from worktree execution and retain project assignment on resume.

Project discovery runs on a blocking worker with bounded pagination and request deadlines. The real native fixture verifies project records, reuse, projectId membership, unrelated-project exclusion, and stable resumed identity while executing outside the project root. Native fixture and 457 CLI tests pass. Desktop UI automation remains prohibited by the tool.

Pre-commit hook ran. Total eslint: 0, total circular: 1
@Neonforge98 Neonforge98 changed the title fix(codex): create managed threads through the native transport fix(codex): register Desktop projects and bind managed threads Sep 9, 2026
@Neonforge98
Neonforge98 marked this pull request as draft September 9, 2026 05:35
@Neonforge98
Neonforge98 marked this pull request as ready for review September 9, 2026 08:01
@Neonforge98
Neonforge98 merged commit 01c203c into develop Sep 9, 2026
15 of 18 checks passed
@Harry19081 Harry19081 added bug Something isn't working agent Agent runtime, behavior, memory, providers, or orchestration project-management Projects, work items, routines, GitHub work, or team inbox labels Sep 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent Agent runtime, behavior, memory, providers, or orchestration bug Something isn't working project-management Projects, work items, routines, GitHub work, or team inbox

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants