Summary
If the Electron-managed daemon exits while the desktop app is still open, the renderer notices enough to stop showing project data, but it leaves project actions such as New task and Spawn Orchestrator clickable on the stale board route. Clicking Spawn Orchestrator produces no visible error or recovery path in the app and logs an unhandled rejection: AO daemon is not ready.
This makes daemon crash/restart recovery feel broken: the user is left on an apparently usable screen, but actions silently fail and there is no obvious Restart daemon / Reconnect affordance even though the Electron preload/main layer already exposes daemon start IPC.
Reproduced on
- Repo:
AgentWrapper/agent-orchestrator
- Branch:
main
- Commit:
77f33c28
- Platform: macOS / Electron dev app
- Runtime state: isolated local QA state under
/tmp/agent-orchestrator-qa-20260627-230707
- Launch env:
AO_DATA_DIR=/tmp/agent-orchestrator-qa-20260627-230707/ao-data \
AO_RUN_FILE=/tmp/agent-orchestrator-qa-20260627-230707/running.json \
AO_PORT=31021 \
AO_TELEMETRY_EVENTS=off \
AO_TELEMETRY_METRICS=off \
AO_TELEMETRY_REMOTE=off \
VITE_AO_POSTHOG_HOST=http://127.0.0.1:9 \
npm --prefix frontend run dev
Repro steps
- Start the Electron dev app with the isolated env above.
- Add/open a disposable local git project.
- Confirm the Electron UI is on a project board route and daemon-backed data is visible.
- Kill the isolated daemon process listed in
AO_RUN_FILE while leaving Electron open.
- Wait for Electron to observe the daemon exit.
- Click Spawn Orchestrator on the still-visible project board.
Expected behavior
After the daemon exits, the UI should stop offering daemon-dependent actions or show a clear recovery state, for example:
- Disable New task / Spawn Orchestrator while daemon status is stopped.
- Show a visible Restart daemon / Reconnect action.
- Catch action failures and render an inline/toast error instead of producing an unhandled rejection.
- Preferably call the already-exposed
daemon.start IPC when the user chooses recovery.
Actual behavior
- The sidebar loses project data / shows the stopped state, but the project board route remains mounted.
- New task and Spawn Orchestrator remain clickable.
- Clicking Spawn Orchestrator gives no visible user-facing error.
- Dev logs show an unhandled renderer rejection:
[vite] (client) [Unhandled rejection] Error: AO daemon is not ready.
Screenshots / evidence
Before clicking: stale project board still exposes New task and Spawn Orchestrator after daemon exit.

After clicking Spawn Orchestrator: no visible app error; the failure only appears in logs.

Local evidence files from the repro:
/tmp/agent-orchestrator-qa-20260627-230707/evidence/06-daemon-stopped-project-actions-still-enabled-cropped.png
/tmp/agent-orchestrator-qa-20260627-230707/evidence/07-daemon-stopped-spawn-click-no-feedback-cropped.png
/tmp/agent-orchestrator-qa-20260627-230707/logs/electron-dev-tail-after-daemon-stopped-click.log
Key log excerpt:
[vite] (client) [Unhandled rejection] Error: AO daemon is not ready.
> spawnOrchestrator src/renderer/lib/spawn-orchestrator.ts:16:8
> openOrchestrator src/renderer/components/SessionsBoard.tsx:107:21
Code pointers
frontend/src/renderer/components/SessionsBoard.tsx
openOrchestrator uses try/finally but has no catch, so daemon/API errors bubble into an unhandled rejection.
- It also keeps board-level daemon-dependent actions available even after daemon status changes.
frontend/src/renderer/lib/spawn-orchestrator.ts
- Throws the daemon/API error when
/api/v1/orchestrators cannot run.
frontend/src/renderer/hooks/useDaemonStatus.ts
- Applies stopped/ready daemon status and keeps polling, but does not surface a recovery action to the route/action layer.
frontend/src/preload.ts
- Exposes
daemon.start() and daemon.stop().
frontend/src/main.ts
- Registers
ipcMain.handle("daemon:start", () => startDaemon()), so the recovery primitive already exists.
Duplicate / overlap check
I checked current open issues and PRs before filing.
Nearby but not the same:
No exact open issue or PR was found for the stale Electron actions + unhandled AO daemon is not ready flow.
Contribution value
This is a good focused bug because it is:
- User-visible in the real Electron app.
- Reproducible without private credentials or GitHub writes.
- A resilience/onboarding problem that users can hit during local dev, daemon crashes, manual kills, or app/dev-server restarts.
- Likely fixable in one focused PR around daemon status gating, action error handling, and/or exposing a restart CTA using the existing IPC.
Summary
If the Electron-managed daemon exits while the desktop app is still open, the renderer notices enough to stop showing project data, but it leaves project actions such as New task and Spawn Orchestrator clickable on the stale board route. Clicking Spawn Orchestrator produces no visible error or recovery path in the app and logs an unhandled rejection:
AO daemon is not ready.This makes daemon crash/restart recovery feel broken: the user is left on an apparently usable screen, but actions silently fail and there is no obvious Restart daemon / Reconnect affordance even though the Electron preload/main layer already exposes daemon start IPC.
Reproduced on
AgentWrapper/agent-orchestratormain77f33c28/tmp/agent-orchestrator-qa-20260627-230707Repro steps
AO_RUN_FILEwhile leaving Electron open.Expected behavior
After the daemon exits, the UI should stop offering daemon-dependent actions or show a clear recovery state, for example:
daemon.startIPC when the user chooses recovery.Actual behavior
Screenshots / evidence
Before clicking: stale project board still exposes New task and Spawn Orchestrator after daemon exit.
After clicking Spawn Orchestrator: no visible app error; the failure only appears in logs.
Local evidence files from the repro:
/tmp/agent-orchestrator-qa-20260627-230707/evidence/06-daemon-stopped-project-actions-still-enabled-cropped.png/tmp/agent-orchestrator-qa-20260627-230707/evidence/07-daemon-stopped-spawn-click-no-feedback-cropped.png/tmp/agent-orchestrator-qa-20260627-230707/logs/electron-dev-tail-after-daemon-stopped-click.logKey log excerpt:
Code pointers
frontend/src/renderer/components/SessionsBoard.tsxopenOrchestratorusestry/finallybut has nocatch, so daemon/API errors bubble into an unhandled rejection.frontend/src/renderer/lib/spawn-orchestrator.ts/api/v1/orchestratorscannot run.frontend/src/renderer/hooks/useDaemonStatus.tsfrontend/src/preload.tsdaemon.start()anddaemon.stop().frontend/src/main.tsipcMain.handle("daemon:start", () => startDaemon()), so the recovery primitive already exists.Duplicate / overlap check
I checked current open issues and PRs before filing.
Nearby but not the same:
No exact open issue or PR was found for the stale Electron actions + unhandled
AO daemon is not readyflow.Contribution value
This is a good focused bug because it is: