Skip to content

feat(mcp): pilot/co-pilot control handoff for coordinated tasks#98

Closed
brooksc wants to merge 10 commits intojohannesjo:mainfrom
brooksc:feature/orchestrator-control-handoff
Closed

feat(mcp): pilot/co-pilot control handoff for coordinated tasks#98
brooksc wants to merge 10 commits intojohannesjo:mainfrom
brooksc:feature/orchestrator-control-handoff

Conversation

@brooksc
Copy link
Copy Markdown
Contributor

@brooksc brooksc commented May 4, 2026

Summary

Adds explicit human/orchestrator control handoff for sub-tasks created by a coordinating agent, modelled on a pilot/co-pilot system where control is always unambiguously held by one party.

This is a standalone feature built on top of the coordinating agent concept introduced in PR #31.

How it works

Each sub-task created by a coordinator has a runtime field controlledBy: 'orchestrator' | 'human'. The task panel shows a persistent banner so the user always knows who has the stick:

  • Orchestrator driving — subtle bar with a "Take Control" button
  • Human in control — amber warning banner: "You have control — orchestrator is paused" with a "Return to Orchestrator" button

When the human holds control, the orchestrator's MCP tools are blocked for that task:

  • send_prompt throws immediately so the coordinator agent knows it cannot proceed and must wait or work on other tasks
  • wait_for_idle resolves immediately (rather than hanging) so the coordinator isn't blocked

Control returns to the orchestrator only via explicit user action — never automatically. Returning control also fires any queued waitForIdle resolvers so the coordinator can resume cleanly.

Changes

  • src/store/types.ts — add controlledBy?: 'orchestrator' | 'human' to Task (runtime only, not persisted)
  • electron/ipc/channels.ts — add MCP_ControlChanged channel
  • src/store/tasks.ts + src/store/store.ts — add setTaskControl(taskId, who) action
  • electron/mcp/orchestrator.ts — enforce control in sendPrompt and waitForIdle
  • electron/ipc/register.ts — handle MCP_ControlChanged IPC
  • src/components/TaskPanel.tsx — control banner UI with take/return buttons

Test plan

  • Create a coordinator task; verify sub-tasks show "Orchestrator driving" bar
  • Click "Take Control" on a sub-task; verify banner changes to amber warning
  • While in human control, verify coordinator's send_prompt MCP call returns an error
  • Click "Return to Orchestrator"; verify banner reverts and coordinator can send prompts again
  • Verify non-coordinated tasks show no banner

🤖 Generated with Claude Code

brooksc and others added 10 commits May 2, 2026 16:10
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Enable a Claude Code agent to programmatically create and orchestrate
other tasks in Parallel Code. Adds an MCP server with 9 tools
(create_task, send_prompt, wait_for_idle, get_task_diff, merge_task,
etc.), a main-process orchestrator, REST API endpoints, and UI
support including coordinator mode toggle, sub-task status strip,
and "via Coordinator" sidebar labels.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cherry-picked from cledoux95/task/coordinating-agent (commit 6650b05).
Fixed console.log → console.warn to satisfy eslint no-console rule.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When main has new commits but no conflicts, highlight "Rebase onto main"
as the primary button. Only promote "Rebase with AI" to primary when
conflicts are actually detected.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Address review issues from PR johannesjo#31:
- Try ports 7777-7800 when starting MCP remote server instead of
  hardcoding 7777, preventing silent failure when port is in use
- Validate REST body fields (name, prompt, timeoutMs, squash, message,
  cleanup) in orchestrator API routes, returning 400 on bad input

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds explicit control handoff between the orchestrating agent and the
human user, modelled on a pilot/co-pilot system where control is always
unambiguously held by one party.

Each sub-task created by a coordinator has a new runtime field
`controlledBy: 'orchestrator' | 'human'`. The task panel shows a
persistent banner so the user always knows who has the stick:

- Orchestrator driving: subtle bar + "Take Control" button
- Human in control: amber warning banner "You have control —
  orchestrator is paused" + "Return to Orchestrator" button

When the human holds control, the orchestrator's MCP tools are blocked:
- `send_prompt` throws immediately so the coordinator agent knows it
  cannot proceed and must wait or work on other tasks
- `wait_for_idle` resolves immediately so the coordinator is not left
  hanging; the status signals human control

Control returns to the orchestrator only via explicit user action —
never automatically. Returning control also fires any queued
`waitForIdle` resolvers so the coordinator can resume.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@brooksc brooksc closed this May 4, 2026
@brooksc
Copy link
Copy Markdown
Contributor Author

brooksc commented May 4, 2026

ignore this PR -- I'm trying to create an update to PR 31... but without all the other PRs merged in (which I was using for my own purposes). Another PR incoming, 3...2..1.. :)

@brooksc brooksc deleted the feature/orchestrator-control-handoff branch May 4, 2026 01:50
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