Skip to content

Orgabot is in private alpha. Request access, or join our Discord.

← All documentation
The organization

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:

LocationWhat it isBilling
GitHub-hosted runner classA GitHub-managed machine type such as windows-2022Billed per minute by GitHub
Self-hosted poolA 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.

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-approval to 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:

BlockerMeaning
missing_grantThe GitHub connector cannot dispatch workflows. It needs actions: write on the repository
auth_expiredGitHub rejected the connector's token even after a fresh one was minted
workflow_not_foundThe entry workflow is not on the default branch yet
rate_limitedGitHub's rate limit is spent; Orgabot resumes after the reset
paid_execution_needs_approvalA 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

  1. Add the entry workflow .github/workflows/orgabot-target-dispatch.yml and its allowlist .github/orgabot/ci-targets.json to the repository's default branch. Each target gets its own job, gated on the validated target name.
  2. Give the GitHub connector actions: write on that repository.
  3. If you use self-hosted runners, allow the runner group to run that workflow.
  4. 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.