Skip to content

codex-restart quits the desktop shell where upstream restarts only the app-server, discarding unsaved client state #4761

Open

Description

@lidge-jun

Client or integration

Codex App

Area

Service lifecycle

Summary

ocx system codex-restart quits and relaunches the whole Codex desktop shell. Upstream's own restart operation does not: codex app-server daemon restart stops and starts only the app-server process it manages, refuses to act when the responding app-server is not daemon-managed, and waits for the replacement to pass a readiness probe. Upstream treats a server restart as something clients survive — SIGTERM means "graceful restart drain", the acceptor stops once running turns reach zero, and connected clients reconnect.

Because we terminate the desktop shell instead, everything that lived only in the client is discarded: an unsaved model-picker selection, an in-progress composer draft, and any approval prompt waiting for the user. The desktop restart path finds root Codex shell processes, asks them to quit, force-stops survivors, and relaunches the app; it never starts or readiness-probes an app-server itself and relies on the relaunched desktop to create replacements.

This is not a regression and not a defect in the current implementation. That code is careful: it revalidates process start times before signalling, refuses uncertain app-server identities, and is gated behind an explicit --yes. The scope is not gratuitous either — model_catalog_json is startup-only upstream, so a catalog change genuinely cannot be picked up by a running desktop without restarting it, and config/batchWrite.reloadUserConfig reapplies only reloadable settings and is documented as neither a process restart nor a catalog reload.

The debt is that the only tool offered for "pick up the new catalog" is the most destructive one available, and the user pays unsaved client state for it every time. Worth considering: detect whether the catalog actually changed and skip the desktop restart when it did not; restart app-servers alone when that suffices; or name the specific unsaved desktop state at risk before quitting rather than describing the scope generically.

Expected: refreshing the catalog should not cost the user their unsaved desktop state unless that is genuinely the only way to apply the change, and the command should say so when it is.

Reproduction

  1. Start the proxy and connect Codex desktop: ocx start --port 10100.
  2. In the Codex desktop app, open a thread and leave unsaved client-side state: type a composer draft without sending it, change the model in the picker without starting a turn, and leave an approval prompt open.
  3. Run ocx system codex-restart --yes.
  4. The desktop app fully quits and relaunches. The draft, the unsent picker selection, and the pending approval are gone.

Compare with upstream codex app-server daemon restart, which restarts only the managed app-server and leaves the desktop client running to reconnect.

Observed against the current restart path in src/codex/app-server-restart-service.ts, src/codex/desktop-app-restart.ts, and src/server/management/system-routes.ts. The upstream contract is in codex-rs/app-server-daemon/src/lib.rs and codex-rs/app-server/src/lib.rs.

Version

dev at 3070d64

Operating system

macOS 27.0 arm64 (the desktop-restart path is macOS and Windows specific)

Provider and model

No response

Logs or error output

Screenshots and supporting files

No response

Redacted configuration

Checks

  • I searched existing issues and documentation.
  • I removed secrets, tokens, account details, request credentials, and personal data.

Activity

  1. lidge-jun commented on Sep 16, 2026

    @lidge-jun
    OwnerAuthor

    리뷰 · 우선순위 66 / 80

    이 이슈는 ocx system codex-restart가 업스트림처럼 app-server만 재시작하는 게 아니라 Codex 데스크톱 셸 전체를 종료·재실행해서, 저장 안 한 클라이언트 상태(작성 중 초안, 모델 피커, 승인 프롬프트)를 버린다는 범위 부채다. 현재 dev HEAD b3035fe292에서도 src/cli/system-command.ts(132–140행)가 ‘fully quits and relaunches the Codex desktop app’이라고 --yes를 요구하고, /api/system/codex-restart로 그대로 호출한다.

    구현 경로도 tip에 있다. src/codex/app-server-restart-service.ts가 카탈로그/재시작 오케스트레이션을 하고, src/codex/desktop-app-restart.ts가 루트 셸을 찾아 quit·force-stop·relaunch한다. 주석(약 5–18행)은 예전 --restart-codex가 app-server만 시그널했다가 피커가 안 바뀌던 이유를 설명하고, 좁은 동작은 --restart-app-server-only로 옮겼다고 적는다. src/server/management/system-routes.ts가 그 서비스를 대시보드/API에 연결한다. 코드는 start-time 재검증·불확실한 app-server 거부 등 조심스럽고, 회귀라기보다 의도된 넓은 범위다.

    업스트림 codex app-server daemon restart는 데몬이 관리하는 app-server만 멈추고 띄우며 readiness를 보고, 클라이언트는 재연결로 산다. 우리는 데스크톱을 죽여서 ‘카탈로그를 다시 읽게’ 만든다. model_catalog_json이 업스트림에서 startup-only인 한, 카탈로그 변경에 데스크톱 재시작이 필요한 경우도 진짜로 있다. 문제는 그 파괴적 도구가 ‘새 카탈로그 받기’의 유일한 공개 경로처럼 쓰인다는 점이다.

    #4720 L2로 #4564(멤버십/POSIX-only Windows 수정)와 #4610(재시작 범위 문구)이 이미 dev에 들어왔다. 그래서 ‘범위 설명이 모호하다’ 쪽은 많이 줄었다. 남은 것은 이슈가 말하는 제품 부채: 카탈로그가 실제로 안 바뀌었으면 데스크톱 재시작을 건너뛰기, app-server만으로 충분한 경우 그 경로를 기본으로 쓰기, 종료 전에 잃을 unsaved 상태를 구체적으로 말하기.

    긴급 런타임 장애는 아니다. --yes 게이트도 있다. 그래도 카탈로그 pull·서비스 수리 흐름에서 자주 눌리는 명령이라 UX 부채 우선순위는 중간 이상이다. types/config 스플릿과 무관하다.

    경로 src/cli/system-command.ts (132–140) - codex-restart가 데스크톱 전체 quit/relaunch를 명시하고 --yes만 요구한다.
    경로 src/codex/desktop-app-restart.ts - 셸 종료·강제 종료·relaunch. app-server readiness probe를 직접 하지 않는다.
    경로 src/codex/app-server-restart-service.ts - 카탈로그/재시작 오케스트레이션이 데스크톱 재시작에 기대다.
    심볼 --restart-app-server-only (src/cli/restart-scope.ts) - 좁은 경로는 이미 있으나 system codex-restart 기본은 여전히 넓다.
    교차 #4564/#4610 via #4720 - 문구·멤버십 수정은 착륙. 범위 축소 정책은 아직 남았다.

    메인테이너의 판단이 필요한 지점

    • system codex-restart 기본을 app-server-only로 바꾸고 데스크톱은 별도 플래그로 둘지.
    • 카탈로그 해시 비교로 ‘변경 없음 → 데스크톱 스킵’을 넣을지.
    • 종료 전 경고에 draft/picker/approval을 이름 붙여 쓸지.

    너의 추천
    받아라. 버그라기보다 범위 부채로 두고, 기본을 app-server-only(또는 catalog-unchanged 스킵)로 좁히는 설계 짧은 PR을 받아라. #4564/#4610은 이미 dev에 있으니 중복 수정하지 마라.

    이 댓글은 grok-bot이 작성했습니다

  2. added
    enhancementNew feature or request
    and removed
    bugSomething isn't working
    on Sep 16, 2026
  3. lidge-jun commented on Sep 23, 2026

    @lidge-jun
    OwnerAuthor

    Partial progress from #5682 (squash-merged as 7f8d538, carrying #5488): the CLI now warns that a restart can discard unsaved client state. codex-restart still quits the whole desktop shell rather than only the app-server, so this stays open.

  4. added
    priority: P2Medium: provider/client-specific bug with a workaround, bounded enhancement tied to a tracked issue,
    on Sep 24, 2026
  5. lidge-jun commented on Sep 27, 2026

    @lidge-jun
    OwnerAuthor

    Status update from the release train 4 bug-hardening lane. On current dev, src/codex/app-server-restart-service.ts:157 still restarts the whole desktop app, and ocx system codex-restart warns that unsaved drafts may be lost (src/cli/system-command.ts:221). An app-server-only restart does not currently refresh the model picker, so switching to it would trade this problem for a stale picker. Changing the consent flow or the desktop UI belongs to the GUI lane, so this stays open as a scope decision there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestpriority: P2Medium: provider/client-specific bug with a workaround, bounded enhancement tied to a tracked issue,serviceService lifecycle (WinSW/launchd/scheduler)

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions