Skip to main content

Module conduct

Module conduct 

Source
Expand description

The conductor: a single agent seat that arranges the queue.

crate::queue orders runnable tasks by priority alone; nothing in it can express that one task should wait for another, or that a task whose last run stopped short deserves a second look before the loop blindly retries it. Once per polling cycle, Conductor::maybe_run shows one agent seat three things - the runnable tasks, the tasks stuck running with no live daemon behind them, and the failed/held tasks nobody has decided about yet - and asks it to decide blocked_by for the first and a recovery for the other two. Everything else about the loop - which unblocked task runs next, one at a time, in priority order - is unchanged; see crate::daemon.

§What the conductor may not do

Decision has no field for priority, for deleting a task, or for touching git, a worktree, or a branch directly. Recovery::Review only ever reopens a branch crate::daemon itself resolved from the task’s own run record ([surviving_branch]) - never a name the model wrote - through crate::graph::Runner::review, which reviews and verifies but never rewrites history.

§Non-blocking by construction

crate::ask::ask_and_wait is never called from here, and the prompt tells the model the same: that CLI command blocks until a human answers, and calling it from inside the conductor’s own invocation would park the whole polling loop behind one task’s question. Instead a decision that wants the operator’s judgement carries a question field, and apply files it with Question::new and Questions::put and moves on in the same call. Something still has to read the owner’s reply: the question carries a Deputy brief, and magi serve starts a short-lived seat of its own for it (crate::deputy) - never this loop.

§Fails soft, always

Conductor::maybe_run never returns an error: an unusable roster, a timed-out invocation, or a reply verdict::extract_json cannot parse are all logged and treated as “this cycle changes nothing.” crate::daemon’s loop always falls through to its own Queue::next_runnable regardless of what happened here.

Structs§

Conductor
The conductor’s state across polling cycles: its own CLI-side conversation and the last (revision, stalled ∪ finished ids) pair it actually acted on.
Decision
The conductor’s decision for one task. Deliberately has no priority field: see this module’s doc.
QuestionDecision
The structured meaning of a question, separate from its displayed wording.
Verdict
The conductor’s whole reply for one cycle.

Enums§

QuestionOperation
The operation for which the operator’s decision is requested. These are fixed protocol values, independent of the language of the displayed choices.
QuestionTarget
The concrete object of an operator decision. Sources resolve to commit ids; runs must belong to this task. A generated prose label is never an identity.
Recovery
What the conductor may choose for a running-but-stalled or a failed/held task.

Constants§

NODE
Node name reported to the invoked agent (MAGI_NODE) and recorded on any question it files, so an operator reading the questions list can tell a conductor’s question from one a run’s own agent asked.

Functions§

apply
Apply every decision in verdict. A single bad decision - a task id that no longer exists, one already claimed elsewhere - is logged and skipped rather than losing every other decision in the same reply.
busy
Is a conductor turn in flight right now?
load_seat
The seat the conductor last used, if it has taken a turn.
seat_path
Where the conductor’s seat is kept between turns, so the daemon waiter can resume it when the owner answers a question it asked.