GitHub Actions dispatch: run one CI target remotely
Run a single CI target on a GitHub-hosted runner class or your own self-hosted pool, bound to the exact source commit and reviewed workflow.
Last updated
Most CI can run locally. Some targets cannot: a Windows installer, a signing step bound to a cloud identity, a check that needs a platform you do not own. GitHub Actions dispatch runs exactly that one target on GitHub's infrastructure, on a placement you chose, and brings the result back into the same Orgabot pipeline as everything that ran locally.
It does not re-run your whole old workflow. One dispatch runs one allowlisted target.
Two kinds of remote location
Orgabot keeps these separate on purpose, and you configure them separately:
| Location | What it is | Billing |
|---|---|---|
| GitHub-hosted runner class | A GitHub-managed machine type such as windows-2022 | Billed per minute by GitHub |
| Self-hosted pool | A runner group you enrolled, with its labels (always including self-hosted) | Not billed per minute by GitHub |
A target either names one location (explicit) or an ordered preference list (preferred). With a preference list, Orgabot takes the first eligible entry. A later entry is a fallback, and it is only used when the earlier one is unavailable (for example the pool is offline). A failing test never moves work to another location.
Paid runs need an approved ceiling
A hosted runner costs money, so Orgabot will not start one unless you said it may:
- With no spend authorization, a hosted location is skipped and the plan explains why.
- With
--ceiling-usd, the plan asks for approval and shows the estimate. Add--request-approvalto file the approval. - Once approved, pass
--approval <id>. The approval only covers the exact repository, target, operation, source commit and ceiling it names.
A hosted class with no configured price is never treated as free. Signing, publishing and deployment targets need the same approved authorization before they can be dispatched at all.
What gets checked before anything runs
The request carries no command. It names a repository, an allowlisted target, an allowlisted operation, a full 40-character commit SHA, and an operation id. Orgabot validates all of that against your installation settings, and the reviewed workflow in the repository validates it again against its own committed allowlist. A branch name, a short SHA, a runner label or anything that looks like a shell fragment is refused.
Remote work also waits for its prerequisites. If a local check in the same pipeline is still running, nothing is dispatched, so a billed runner never sits idle waiting on your machine. If a prerequisite failed, the plan is blocked.
Source and workflow are recorded separately
GitHub runs a dispatched workflow from the workflow file on the dispatch branch, so the commit GitHub reports is the workflow's commit, not the one being built. Orgabot records both:
- the workflow definition commit it resolved when it dispatched, and
- the source commit you asked it to build.
The workflow checks out the source commit explicitly and fails unless that is what it got. A run that executed a different workflow definition, or built a different source, is never accepted as evidence.
Correlation, retries and reconnection
Each dispatch has an operation id, and the run's title carries it, so Orgabot can always find its own run again:
- Dispatching twice is safe. The same operation id reconnects to the existing run instead of starting another.
- A lost response is reconciled, not retried blind. If the request timed out, Orgabot looks for the run first. A verification target is resubmitted at most once if no run ever appeared. A signing or deploy target is never resubmitted automatically.
- Duplicates are canceled. If two runs carry one operation id, the earliest one counts and the rest are canceled.
- Reruns replace earlier attempts. Evidence from the earlier attempt is discarded.
- Webhooks speed things up but are not required. If deliveries are lost, Orgabot keeps polling with growing gaps and still reaches the result. A run that outlives its timeout is canceled.
- Restarts are fine. The dispatch record is stored durably, so after a restart Orgabot picks up where it left off.
Setup problems are reported, not worked around
When something is missing, the dispatch stops with a named blocker and the exact next step:
| Blocker | Meaning |
|---|---|
missing_grant | The GitHub connector cannot dispatch workflows. It needs actions: write on the repository |
auth_expired | GitHub rejected the connector's token even after a fresh one was minted |
workflow_not_found | The entry workflow is not on the default branch yet |
rate_limited | GitHub's rate limit is spent; Orgabot resumes after the reset |
paid_execution_needs_approval | A hosted run needs your approval and shows its estimate |
Orgabot never switches to a different GitHub identity or a broader credential to get past one of these.
Commands
orgabot ci-dispatch config [--set <file.json>]
orgabot ci-dispatch plan <owner/repo> <target> <operation> --source <sha> [options]
orgabot ci-dispatch run <owner/repo> <target> <operation> --source <sha> [options] [--watch]
orgabot ci-dispatch status [<operation-id>] [--watch]
orgabot ci-dispatch cancel <operation-id>plan has no side effects. It prints the chosen location, the runs-on labels, the cost estimate, and why each other location was skipped. Useful options: --prereq <id>=<state> for pipeline prerequisites, --pool-online <pool> and --pool-offline <pool> for pool health, --pipeline <id> and --mission <id> to link the run into a pipeline.
status shows the run, its attempt, the two recorded commits, any blocker, and once finished the checks, artifacts, runner names and groups, whether the placement was verified, and the estimated billed minutes. Costs are estimates from job duration and your configured rate, not GitHub invoices.
Setting it up for a repository
- Add the entry workflow
.github/workflows/orgabot-target-dispatch.ymland its allowlist.github/orgabot/ci-targets.jsonto the repository's default branch. Each target gets its own job, gated on the validated target name. - Give the GitHub connector
actions: writeon that repository. - If you use self-hosted runners, allow the runner group to run that workflow.
- Write the installation config (repository, entry workflow, trusted branch, hosted classes with prices, self-hosted pools, and targets) and load it with
orgabot ci-dispatch config --set <file.json>. The config lives in your Orgabot installation, not in the repository, so a pull request cannot grant itself a new target or a paid runner.