Skip to content

refactor: implement active orchestrator model with unified rules API - #7

Merged
jzila merged 11 commits into
mainfrom
refactor-runs
Jan 24, 2026
Merged

jzila merged 11 commits into
mainfrom
refactor-runs

Conversation

@jzila

@jzila jzila commented Jan 23, 2026

Copy link
Copy Markdown
Owner

Summary

This PR implements a significant architectural refactor to support an always-running orchestrator model:

  • Active Orchestrator Model: The orchestrator now runs continuously rather than being created per-run, enabling better state management and real-time UI updates
  • API Restructure: Split daemon and orchestrator APIs with new URL scheme (/api/orchestrator/* for orchestrator-specific endpoints)
  • Rules System Overhaul: Unified rules format with DENY/ALLOW actions, modal editing UI, drag-and-drop reordering, and per-repo isolation
  • Periodic Beads Sync: Background synchronization of beads state
  • Config Query API: New endpoint to query orchestrator configuration
  • Needs-Input Status: Support for paused tasks awaiting user input
  • Worker Agent Improvements: Better prompt biasing toward forward progress, immediate failure on agent pause

Test plan

  • All existing tests pass (go test ./...)
  • New tests for rule editing modal interactions
  • New tests for per-repo rules isolation
  • Dashboard builds without TypeScript errors

jzila added 11 commits January 23, 2026 00:00
for input

When a Claude agent invokes AskUserQuestion or other interactive tools
during execution, the worker now:

1. Detects the interactive tool use in the stream-json output
2. Immediately terminates the agent process (no hang/wait)
3. Sets InputBlocked=true on the result (for future needs-input status)
4. Returns clear error message with session ID for potential manual resume
5. Records separate "input_blocked" metric status

This prevents:
- False 'completed' status when agent is actually waiting
- Infinite retry loops on input-blocked tasks
- Wasted compute on tasks that can't proceed autonomously
When an agent pauses waiting for user input (InputBlocked=true), mark
the task as 'needs-input' instead of 'failed'. This prevents the
scheduler from re-picking up the task in a loop.

Changes:
- Add NeedsInput method to BeadsClient interface and implementations
- Update HandleFailure to detect InputBlocked and use NeedsInput
- Store session ID in notes for future resume support
- Add 'needs-input' status color (orange) to dashboard
- Add 'Paused' filter button to TaskList component
Add ConfigHandler with HTTP endpoints for querying repository configuration:
- GET /api/config/rules - rules filter settings
- GET /api/config/sandbox - sandbox configuration
- GET /api/config/validation - validation steps

Also adds TypeScript client functions and types for the new endpoints.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Phase 4 of daemon/orchestrator API factoring.

Key changes:
- Add OrchestratorState enum (IDLE, ACTIVE, PAUSED) for state machine
- Add RepoOrchestrator struct to represent always-running orchestrators
- Replace standaloneEngines sync.Map with orchestrators sync.Map
- Implement RegisterRepo/UnregisterRepo for orchestrator lifecycle
- StartRun now performs state transition (idle → active) instead of
  creating a new orchestrator
- StopRun transitions orchestrator back to IDLE state
- Orchestrator goroutine updates RepoOrchestrator state on completion

The always-running model means:
- Orchestrators start when a repo is registered with daemon
- Orchestrators stop when a repo is unregistered
- "Starting a run" = state transition, not object creation
- "Stopping a run" = state transition, not object destruction

For backwards compatibility, RunState and legacy run tracking are
preserved alongside the new RepoOrchestrator model.
…-a7pj)

Update URL structure to reflect ownership between daemon and orchestrator:

New URL structure:
- /api/repos/:repo_id/rules/* - orchestrator (repo-scoped rules)
- /api/repos/:repo_id/config/* - orchestrator (repo-scoped config)
- /api/daemon/runs/* - daemon (cross-repo run listing)
- /api/daemon/repositories/* - daemon (repository management)

Changes:
- pkg/daemon/server.go: Add new routes and redirect handlers
- pkg/daemon/rules_handlers.go: Add RouteRepoRules for new path pattern
- pkg/daemon/config_handlers.go: Add RouteRepoConfig for new path pattern
- web/dashboard/src/api/client.ts: Update API calls to use new URLs

Backwards compatibility maintained via HTTP 307 redirects from old paths.
Proposes shifting from discrete 'runs' to 'repo has an orchestrator' model.

Key changes:
- Orchestrator is always-present per repo (idle/active/paused states)
- 'Runs' become 'sessions' (work periods within orchestrator)
- Rules/config tied to repo, not run
- Clearer mental model for users

Implementation epic: canopy-i4sm
Tasks: canopy-rqcm, canopy-rxoz, canopy-wtnh, canopy-xchh
@jzila
jzila merged commit bfe72fa into main Jan 24, 2026
7 checks passed
@jzila
jzila deleted the refactor-runs branch January 24, 2026 02:28
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