github.workflow-job-handle
Route workflow_job webhooks: in_progress → claim-watch; queued → runner.dispatch-from-job-queued; completed → dispatches runner.execution-stop-<backend> (which frees the cap slot when it lands; this step does not wait for it).
Handle a workflow_job event.
Three cases are handled:
action=in_progress — signal runner.execution-claim-watch so it transitions from WATCHING to CLAIMED, confirming the runner registered with GitHub. For retry attempts (run_attempt > 1) the claim-watch ID includes the attempt number: claim_watch_{workflow_run_id}_{run_attempt}.
action=queued (any run_attempt) — start runner.dispatch-from-job-queued with the webhook payload. The runners library picks the best matching active group (label superset, repository scope > org scope), honors max_count, and starts the backend-specific runner.execution-launch-*. Outcome (launched / no_match / cap_reached) is observable on the dispatch workflow's state_data; we don't surface failures here.
action=completed — match the RunnerExecution by github_runner_name and call runner.execution-stop-<backend>. The stop workflow chains runner.scale-check-group on completion, which launches a fresh runner if there are still queued jobs needing the freed slot. This per-job handling is what lets a multi-job workflow_run drain its matrix without waiting for workflow_run:completed (which only fires once the entire run finishes).
If no claim-watch workflow exists for the run_id (e.g. pre-feature execution, or github_workflow_run_ref was unavailable at launch time), the missing workflow is silently ignored.
Inputs:
- action: Job action (queued/in_progress/completed)
- github_workflow_run_ref: GitHub workflow run reference the job belongs to
- github_job_ref: GitHub workflow job reference
- runner_name: Name of the runner that claimed the job (in_progress)
- runner_labels: Labels requested for the job
- run_attempt: Run attempt number (1 for first, >1 for retries)
- repository_full_name: Full name "owner/repo"
- organization_uuid: Public organization UUID
Outputs (terminal state_data):
- claim_watch_signaled: True if claim-watch was successfully advanced
- claim_watch_workflow_ref: Workflow reference of the signaled claim-watch (if any)
- dispatch_started: True if a runner.dispatch-from-job-queued was PUBLISHED. The dispatch runs in the runners image, so this does not mean a runner group was picked -- follow dispatch_workflow_ref for that outcome.
- dispatch_workflow_ref: Workflow reference of the dispatch (if any)
- execution_stopped: True if a stop workflow was DISPATCHED for the runner. Not a confirmation that the runner stopped. The stop runs on its own workflow (it is owned by a per-cloud library this image does not carry, so it must be handed to the bus), and it may still be in flight — or have failed — while this field reads True. A runner reported here as stopped can therefore still be alive, still billing, and still holding its runner group's max_count slot. The pool reconcile nudged alongside this dispatch is what actually reclaims the slot; reconcile, not this field, is the source of truth for execution state (P5.T2).
- stop_workflow_ref: Workflow id of that dispatched stop — poll it for the real outcome.
- stopped_runner_execution_uuid: RunnerExecution the stop was dispatched for
Overview
| Property | Value |
|---|---|
| Workflow type | Atomic |
| Library | App-github |
| Version | 1.0 |
Input Schema
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
action | string | Yes | — | Job action |
github_workflow_run_ref | integer | No | — | Workflow run ID |
github_job_ref | integer | No | — | Workflow job ID |
runner_name | string | No | — | Runner name |
runner_labels | list | No | — | Runner labels |
run_attempt | integer | No | — | Run attempt number (1 = first, >1 = retry) |
repository_full_name | string | Yes | — | Repository full name |
organization_uuid | string | No | — | Organization UUID (public) |
github_installation_ref | integer | No | — | GitHub App installation reference — used to flush the LTIP queued-jobs cache so demand-aware reconcile refetches on the next tick |
workflow_run_id | string | No | — | Parent DAG run ID |
Output Schema
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
claim_watch_signaled | boolean | No | — | True if claim-watch was advanced |
claim_watch_workflow_ref | string | No | — | Reference of the signaled claim-watch |
dispatch_started | boolean | No | — | True if a dispatch was published to the runners image. Not proof a group was picked; follow dispatch_workflow_ref. |
dispatch_workflow_ref | string | No | — | Reference of the dispatch workflow |
execution_stopped | boolean | No | — | True if a stop was DISPATCHED — not a confirmation it stopped |
warm_pool_handled | boolean | No | — | True if handled via warm-pool path |
instance_transitioned_to | string | No | — | Terminal instance state for warm-pool path |
stop_workflow_ref | string | No | — | Workflow id of the dispatched stop; poll it for the outcome |
stopped_runner_execution_uuid | string | No | — | UUID of the execution the stop was dispatched for |
action | string | No | — | Job action |
github_workflow_run_ref | integer | No | — | Workflow run ID |
github_job_ref | integer | No | — | Workflow job ID |
runner_name | string | No | — | Runner name |
runner_labels | list | No | — | Runner labels |
run_attempt | integer | No | — | Run attempt number |
repository_full_name | string | No | — | Repository full name |
organization_uuid | string | No | — | Organization UUID (public) |
github_installation_ref | integer | No | — | GitHub App installation reference |
workflow_run_id | string | No | — | Parent DAG run ID |
failure_reason | string | No | — | — |
failure_type | string | No | — | — |
failed_action | string | No | — | — |
failed_at_state | string | No | — | — |
failed_step | string | No | — | — |
failed_layer | string | No | — | — |
error | string | No | — | — |
error_type | string | No | — | — |
States
| State | Initial | Terminal | Success | Auto-advance | Description |
|---|---|---|---|---|---|
pending | Yes | No | — | execute | — |
completed | No | Yes | Yes | — | — |
failed | No | Yes | No | — | — |
State Diagram
Transitions
| From | Action | To | Description |
|---|---|---|---|
pending | execute | completed | — |
* (any state) | fail | failed | — |
API Usage
POST /api/workflows/start
Content-Type: application/json
{
"workflow_type": "github.workflow-job-handle",
"initial_data": {
"action": "value",
"repository_full_name": "value"
}
}