Skip to content

feat(orchestration): renderer→main run/taskCreate preload binding (#15) - #19

Merged
zaridan merged 1 commit into
mainfrom
zaridan/feat-orch-15-renderer-run-binding
Jun 24, 2026
Merged

feat(orchestration): renderer→main run/taskCreate preload binding (#15)#19
zaridan merged 1 commit into
mainfrom
zaridan/feat-orch-15-renderer-run-binding

Conversation

@zaridan

@zaridan zaridan commented Jun 23, 2026

Copy link
Copy Markdown
Owner

What

Exposes the already-registered orchestration.run and orchestration.taskCreate RPC methods to the renderer through a new window.api.orchestration preload binding. Today these are CLI-only (the sole caller is src/cli/handlers/orchestration.ts) and there is no window.api.orchestration binding — this is F4 (#15), the plumbing that lets a recipe director (and any renderer-side trigger) start a coordinator run or create a task from the app.

How

  • Shared contract — new src/shared/orchestration-binding.ts defines the renderer-facing param/return types (OrchestrationRunParams/Result, OrchestrationTaskCreateParams/Result, OrchestrationTask) plus the RPC method-name constants. It mirrors the RPC shapes — including F1's worktree/target-key handling and slice-1's worktreeBacked/workerAgent options — and passes them through verbatim (the semantics live in the main handler). Lives in shared so preload, renderer, and any future client share one contract without importing main internals across the layer boundary.
  • Type surfaceorchestration: OrchestrationPreloadApi added to PreloadApi in src/preload/api-types.ts.
  • Desktop preload (src/preload/index.ts) — orchestration methods are runtime RPC methods (not dedicated IPC channels), so the binding forwards through the existing runtime:call envelope and unwraps it. No new main-process handler.
  • Web preload (src/renderer/src/web/web-preload-api.ts) — reuses callRuntimeResult, the same unwrap path every other runtime-backed namespace uses.

Routing through runtime.call means the binding is SSH/remote-safe (the renderer talks to main/host over the same channel for local and paired runtimes alike).

Scope / safety

Test evidence

New web orchestration preload API block in web-preload-api.test.ts (mocks the IPC/runtime boundary):

  • orchestration.run forwards all params (incl. worktree/worktreeBacked/workerAgent) verbatim and unwraps { runId, status }.
  • orchestration.taskCreate forwards all params (incl. callerTerminalHandle) verbatim and unwraps { task }.
  • Runtime ok: false surfaces as a rejected promise.

Gates run locally, all green:

  • pnpm run typecheck (node + cli + web) ✓
  • vitest run web-preload-api.test.ts → 54 passed (3 new) ✓
  • vitest run orchestration RPC registry → 99 passed ✓ (asserts no behavior change)
  • oxlint on changed files ✓
  • pnpm run build:electron-vite

(One pre-existing switch-exhaustiveness error in task-page-github-work-item-status.ts — unrelated, not in this diff.)

🤖 Generated with Claude Code

Add a `window.api.orchestration` preload binding exposing the already-registered
`orchestration.run` and `orchestration.taskCreate` RPC methods to the renderer,
so a recipe director (and any renderer-side trigger) can start a coordinator run
or create a task from the app — today these are CLI-only.

The binding routes through the existing `runtime.call` channel (desktop unwraps
the `runtime:call` IPC envelope; web reuses `callRuntimeResult`), so it works for
local and remote/SSH runtimes alike with no new main-process handler. A shared
`orchestration-binding.ts` holds the renderer-facing param/return contract,
mirroring the RPC shapes (incl. F1 worktree/target-key handling and slice-1
worktreeBacked/workerAgent pass-throughs) without importing main internals.

Additive only: no existing behavior changes and nothing in the UI calls it yet
(that's the recipe backend, #9). Pure plumbing, so no experimentalOrchestrators
gate is needed. Does not touch coordinator.ts or the orchestration DB.

Test: web preload parity tests assert the binding forwards run/taskCreate params
(including worktree-backed and callerTerminalHandle pass-throughs) verbatim to
the runtime method and unwraps the result, and surfaces runtime failures.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@zaridan

zaridan commented Jun 23, 2026

Copy link
Copy Markdown
Owner Author

Review panel verdict — nits-only (ship it)

Three independent adversarial lenses (type-faithfulness · lane/IPC/SSH · test-honesty) + synthesis. 0 blockers, 0 should-fixes, 9 nits. Core contract verified correct on both preload surfaces: verbatim param pass-through, RuntimeRpcResponse unwrap, additive-only PreloadApi extension, .ts per AGENTS.md, F1 target-key + slice-1 options forwarded faithfully. Confirmed lane-clean — no coordinator.ts/DB touch (so no conflict with the parallel slice-2 branch).

Nits (optional, cheap)

  1. Desktop preload binding (callOrchestrationRpc, src/preload/index.ts) has no direct test — only the web path (web-preload-api.test.ts) is covered; the desktop path is a structurally-distinct inline unwrap. tsc-verified + type-parity today, but the primary Electron surface rides on indirect coverage.
  2. Shared mirror types (src/shared/orchestration-binding.ts) have no compile-time link to TaskRow/Zod params → future-drift risk (field-exact today).
  3. RPC-method-name constants not asserted against the registry (cheap: have the registry test import them).
  4. taskCreate rejection path untested (only run has one).

Over-flagged + dropped on review: the status union widening (justified forward-compat), and a clean-bill note miscounted as a finding.

Recommendation: approve. Optionally fold in the desktop-preload test (#1) + the two trivial test hardenings (#3, #4) first.

@zaridan
zaridan merged commit e32a233 into main Jun 24, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant