Skip to content

bug(frontend/review): a missing harness (worker or reviewer) fails silently/opaquely — no user-facing message, no install pre-flight #303

@neversettle17-101

Description

@neversettle17-101

Bug

If a user doesn't have the selected harness installed (e.g. claude-code, or the reviewer harness), AO's behavior ranges from silent to opaque. The backend detects the missing binary, but nothing actionable reaches the user.

Source: code audit (requested) | Reported by: @aditi1178 | Analyzed against: 73649b0
Confidence: High

What I found (by path)

1. Worker/orchestrator spawn — backend detects it cleanly ✅

  • session_manager/manager.go:266 calls validateAgentBinary (and adapters return ports.ErrAgentBinaryNotFound from GetLaunchCommand, e.g. adapters/agent/claudecode/claudecode.go:356).
  • service/session/service.go:350 maps it to a clean AGENT_BINARY_NOT_FOUND (422) carrying the real message (agent binary "claude": agent: binary not found on PATH).

2. Worker/orchestrator spawn — frontend SWALLOWS it ❌

  • components/ShellTopbar.tsx:88-92:
    } catch (error) {
        console.error("Failed to spawn orchestrator:", error);
    } finally {
        setIsSpawning(false);
    }
    The only handling is console.error. The user clicks Spawn Orchestrator, sees "Spawning…", and the button silently resets to idle with no toast, no banner, no message. The good AGENT_BINARY_NOT_FOUND text the backend produced is never shown.

3. Reviewer — backend reports it OPAQUELY ❌

  • The reviewer reuses the worker claude-code adapter, so it does surface ErrAgentBinaryNotFound (adapters/reviewer/claudecode/claudecode.go:37GetLaunchCommand).
  • But the trigger path doesn't classify it: review/review.go:226 returns fmt.Errorf("launch reviewer: %w", err) (a raw error), which falls through writeReviewError's default in controllers/reviews.go to HTTP 500 REVIEW_OPERATION_FAILED "Review operation failed" — a hardcoded generic message that drops the real cause.
  • Also, the InsertReviewRun happens after the spawn, so a missing reviewer leaves no review run recorded — no persistent trace of why the review never happened.

4. No install pre-flight anywhere ❌

  • The harness pickers are hardcoded lists, not filtered by what's installed:
    • components/ProjectSettingsForm.tsx:16 AGENT_OPTIONS = ["claude-code","codex","opencode","amp","goose","kiro"]
    • components/ProjectSettingsForm.tsx:25 REVIEWER_OPTIONS = ["claude-code"]
  • There is no "installed/available harnesses" capability endpoint exposed to the frontend (the daemon registers ~23 adapters, but availability ≠ installed). So a user can select goose/codex/etc. that isn't installed and only discover it via the silent (worker) or opaque (reviewer) failure above.

Reproduction

  1. On a machine without claude-code on PATH (or pick a harness you haven't installed).
  2. Worker/orchestrator: click Spawn Orchestrator → spinner shows briefly → resets with no message. (Backend returned AGENT_BINARY_NOT_FOUND.)
  3. Reviewer: trigger a review with an uninstalled reviewer harness → POST /sessions/{id}/reviews/trigger returns 500 REVIEW_OPERATION_FAILED "Review operation failed"; no run recorded; UI shows a generic failure at best.

Fix

  1. Frontend spawn: surface the error. Catch the AGENT_BINARY_NOT_FOUND code and show a toast/banner with an install hint (e.g. "claude-code is not installed — install it and try again"), instead of console.error only. Same for worker spawn.
  2. Reviewer backend: classify ErrAgentBinaryNotFound in writeReviewError (e.g. 422 with a REVIEWER_BINARY_NOT_FOUND code + real message) rather than the catch-all 500; consider recording a failed ReviewRun so the gap is visible in the reviews panel.
  3. Pre-flight (enhancement): add an "installed harnesses" capability the frontend can read, and either disable/annotate uninstalled options in the agent/reviewer pickers or warn on save.

Impact

  • New users without the default harness installed hit a dead-end with no guidance — the app looks broken.
  • The reviewer feature (this branch) silently never runs when its harness is missing, with only an opaque 500 — hard to diagnose.

Related

  • #210ao spawn --harness <unknown> opaque 500 (unknown vs. uninstalled; CLI; closed).
  • #291 — PATH-pin defeat breaks hook resolution (adjacent harness-resolution surface).
  • #295 — reviewer/PR signals not surfaced (adjacent reviewer-UX gap).

Metadata

Metadata

Labels

bugSomething isn't workingfrontendElectron frontend lanepriority: mediumFix when convenient

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions