Skip to content
This text was generated by an LLM (how cgwalters uses LLMs). cgwalters has not reviewed it yet.

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 --apply starts the job the issue's newest accepted job plan describes. The caller repository, workflow and ref come from --caller, --workflow and --ref (default main).
  • poll --apply starts 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 uses dispatchRepo and dispatchWorkflow from the caller's agent-board.json, at main.
  • supervise execute starts 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:

InputMeaning
taskThe brief: a plan's brief, or the task agent-board writes for a fix or triage round
repoTarget repository, OWNER/NAME; the caller's bounds must allow it
itemIssue or pull request number in repo
kindimplement, triage, research or fix: the profile the run gets
poolInference pool, or empty to leave it to the caller
baseOnly 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 a workflow_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 its run-name that way. The overlap hold, the supervisor's in-flight check, status and run record --caller all 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.