Dispatch
agent-board decides what job to start; something else runs it. The runner of
agent jobs is meant to be pluggable: agentic-job
on a CI runner is one backend, and any tooling that can run an agent job for an
issue should be able to take its place. In code, every caller below starts a
job through one interface (board_forge::dispatch): a start request (target
repository, item, kind, brief, pool, runner, optional base) and a trusted route
from configuration, answered with a run handle, a start without one, a refusal
that started nothing, or an unknown outcome. Its only backend is a GitHub
Actions workflow_dispatch request to a caller workflow. Status queries on a
handle, and other backends, are still
agent-board#295.
This page describes the interface as it exists.
Who dispatches
dispatch ISSUE --applystarts the job the issue's newest accepted job plan describes. The caller repository, workflow and ref come from--caller,--workflowand--ref(defaultmain).poll --applystarts fix, rebase, continuation and diagnostic rounds on the bot's pull requests, and triage or research runs for operator comments and notifications (pull request follow-up). It usesdispatchRepoanddispatchWorkflowfrom the caller'sagent-board.json, atmain.supervise executestarts the triage, research and implement runs the supervisor requests, with the same two settings.- Pass uses the same settings plus
dispatchRef.
Every route, identity and pool allowlist comes from the caller's trusted configuration, never from a plan, an issue or a dispatcher's inputs.
The request
Each of them sends POST /repos/{caller}/actions/workflows/{workflow}/dispatches
with a ref and these string inputs, which the caller workflow must accept:
| Input | Meaning |
|---|---|
task | The brief: a plan's brief, or the task agent-board writes for a fix or triage round |
repo | Target repository, OWNER/NAME; the caller's bounds must allow it |
item | Issue or pull request number in repo |
kind | implement, triage, research or fix: the profile the run gets |
pool | Inference pool, or empty to leave it to the caller |
base | Only for a stacked plan: the branch to start from |
A plan's runner is checked (only hosted is accepted) but not sent: the
caller workflow has one runner. Batched plans add their briefs to task.
What comes back
- Run handle. The request asks for
return_run_details; where GitHub answers with aworkflow_run_id, agent-board records the run's Actions URL on the issue (the dispatch record) or in the pull request's round marker. Where the API refuses that field (HTTP 422) it asks again without it, and there is no handle. - Status. There is no status call on a handle. Runs in flight are found by
listing the caller workflow's queued and in-progress runs and matching their
title,
KIND OWNER/REPO#N, optionally followed by(POOL). The caller workflow must set itsrun-namethat way. The overlap hold, the supervisor's in-flight check,statusandrun record --callerall read runs like this; the poll reads a round's run by the id in its marker. - Ambiguity. A request whose outcome is unknown is recorded and never retried automatically; a writer edits or replaces the plan to try again.
agentic-job's dispatch caller is a workflow of this shape.
Recording a run on the board
request dispatch and run record are an operator-driven join for a board
with Run and Result fields (project init creates them). Both read offline
snapshots. request dispatch prints the gh workflow run argv for an item and
never writes. run record proposes the Run/Result update, and --apply writes
the validated update with the operator's GH_TOKEN. Routing comes from explicit
operator flags, not item prose. Eligibility rejects incomplete or non-issue
inputs to avoid launching work from unknown state. URL grammar excludes
unrelated result targets, but is not evidence of authorship or success: the
operator verifies run/item correlation and the applied result, and an editable
snapshot is never write authority.
When no Run is recorded, run record --caller searches one page of at most 100
of the caller's dispatch.yml runs for the single one titled KIND OWNER/REPO#N
and needs --yes (or an explicit --run) to use it. No scheduled admission,
automatic Run/Result recording, refusal-to-Blocked conversion or stuck-run
recovery is implemented. Agent output reaches the board only through
independent check and apply; the pass's own writes are direct
(architecture).
A post-run controller would need the caller to expose applied pull request and comment URLs and refusal reasons as trusted workflow outputs, with run identity and attempt, so it can correlate results without parsing model prose or picking the latest run by title.