Skip to content

Placing Work

Josh edited this page Nov 5, 2026 · 2 revisions

Describes robot-council/core v0.8.3.

Who is here

GET {prefix}/api/lanes (or sessions_list), needing no ability, lists every active and stale session, newest first, with its developer, machine, role, repository, work location, operating system, status, last contact, its capacity in effect, and the tasks it holds, each with the sub_label its holder gave it. It reads the session table rather than the change feed, so it is complete however far back the feed has been pruned. repository, role and os_family narrow it, and after takes the previous page's cursor, which is null on the last page. A held task's title and description appear only where the reader may act on that task, on the rule task_list applies.

The shortlist

GET {prefix}/api/shortlist (or shortlist_read), behind coordinator:direct, lists the tickets a coordinator could place, per repository: open, with no open or unknown blocked_by blocker, and not already held by a lane. It is ordered by number and implies no preference -- choosing is the coordinator's. Each entry lists its blind spots: a hitl label, a title naming an act that needs a human, every acceptance criterion ticked while still open, and the file paths its body mentions, which are unverified and are never compared between tickets.

Beside repositories, the answer carries filters: for every repository with a placeable ticket, its status (unfiltered, filtered or unresolved), the qualifiers in effect, and, when unresolved, a reason. A repository with robot-council.backlog.search_qualifiers lists only the tickets those qualifiers matched at the latest backlog fetch, and an unresolved one lists nothing rather than every open ticket as if it had been filtered (#530, described in The Lane Board).

Lane conditions

The coordinator's to-do items reach it as fleet events rather than a page (#314). A lane.condition event, restricted and addressed to the live coordinators, is raised for:

meta.condition when
lane_free a build lane with room for another placement -- holding fewer tasks than its capacity (#436), which for most lanes means holding nothing -- not parked and not held, has been seen free for longer than lane_conditions.free_after_minutes (30), measured from the first check that saw it free. A lane of capacity above 1 carries holding and capacity in meta; one of capacity 1 reads as it always has. A lane holding any work cannot be held, so one kept partly full on purpose is raised once for each stretch it has room
not_taken_up a coordinator's placement is still unstarted past take_up_within_minutes (15) -- a hand-back owed says so
working_unobserved a lane holding work goes gone, or stays stale long enough for the fleet to be told (see Presence), raised on that transition itself, and on the next check for a stale one no coordinator heard
pull_request_unpicked a ready pull request no gate is on, in a repository a live gate works in, unchanged past gate_pickup_within_minutes (30)
merge_behind a pull request merged, naming the live sessions in its repository now behind

Each is raised once and cleared when it stops holding; if it recurs it is raised again. The scheduled ones are checked every five minutes; robot-council.schedule.lane_conditions turns that off. With no coordinator live, a scheduled condition waits and is raised to the next one; merge_behind and an ended lane are told on the event or not at all. A raise that fails never undoes the presence transition or the GitHub delivery that caused it: it runs after that write commits, and is reported.

Quiet lanes

Every five minutes the scheduler checks each build lane for anything it has authored: a narration, a task transition, a lock acquired or released, or a directive it posted. A lane that has authored none of those for an hour -- a heartbeat, joining, and a directive it merely received do not count -- raises one lane.quiet event, addressed to the fleet's coordinators and restricted so no other session reads it. It is raised once per quiet stretch; the lane's next act starts a new one. A gate is exempt while it holds no pull request. robot-council.schedule.quiet_lanes turns it off.

Lane holds

A coordinator records why a lane -- an agent session -- is idle on purpose, which the lane board shows as <party> — <what>. The party is a developer the fleet knows, by GitHub login, a ticket as owner/name#N, or the lane's own repository as owner/name; the <what> is one of a fixed set, each for one kind of party, and free text is refused:

reason party reads
clearing_seat developer clearing this seat to take tickets
decision developer a decision
action developer an action only they can take
ticket_lands ticket that ticket to land
ticket_decided ticket that ticket's decision
nothing_startable the lane's repository nothing startable to take
  • POST {prefix}/api/lanes/{session}/hold with { "party": "...", "reason": "..." }, and DELETE the same path to lift it -- both need coordinator:direct, as do the lane_hold and lane_clear_hold tools.
  • A lane that holds a task cannot be held, and claiming or placing work on a lane lifts its hold in the same transaction.
  • nothing_startable is not a block. The board shows such a lane as Idle, reading "Nothing startable in owner/name", because placing any task lifts the hold and the lane takes it at once (#471). It still counts as a stated hold, so lane.free is not raised for it. Any other repository, or a lane that names none, is refused. A lane with no repository cannot be held for this reason. The party must be the lane's own repository, compared without case. Lift every nothing_startable hold before rolling back past v0.7.3, because earlier versions do not know that reason. Since v0.7.7 a session that moves to another repository with session_move drops its lane's nothing_startable hold (#552, see Presence).
  • A claim or a reassign that gives a lane a task deletes that lane's hold in the same transaction (#334).

Clone this wiki locally