4.2.1. Locating Runs, Logs, and Artifacts
💡 First Principle: The Actions tab is a filtered query over run history, and every filter it offers has an API parameter behind it — learning the filter vocabulary once gives you both surfaces.
In the UI, the Actions tab lists workflows down the left and runs in the centre, with filters for workflow, status (success, failure, cancelled, in_progress), branch, event, and actor. The search syntax mirrors this (event:push status:failure branch:main). Opening a run shows the job graph, the summary (including anything written to $GITHUB_STEP_SUMMARY), any annotations produced by ::error::/::warning:: commands, and the artifacts produced. Within a job, each step expands to its log, and the gear menu offers Download log archive — a zip containing every job's full log, plus runner diagnostics when ACTIONS_RUNNER_DEBUG was enabled.
The REST equivalents are worth recognizing by shape rather than memorizing verbatim:
| Purpose | Endpoint |
|---|---|
| List runs for a repo (filterable by branch, event, status, actor) | GET /repos/{owner}/{repo}/actions/runs |
| List runs for one workflow | GET /repos/{owner}/{repo}/actions/workflows/{id}/runs |
| Get a run's jobs | GET /repos/{owner}/{repo}/actions/runs/{run_id}/jobs |
| Download the run's log archive | GET /repos/{owner}/{repo}/actions/runs/{run_id}/logs |
| List a run's artifacts | GET /repos/{owner}/{repo}/actions/runs/{run_id}/artifacts |
| Delete a run (and its logs) | DELETE /repos/{owner}/{repo}/actions/runs/{run_id} |
The gh CLI wraps the common paths — gh run list, gh run view --log, gh run download — which is the quickest correct answer whenever a scenario says "from a terminal" or "in a script."
⚠️ Exam Trap: Log downloads via API return a 302 redirect to a short-lived signed URL, not the log bytes directly. Tooling that doesn't follow redirects appears to fail; this is expected behavior, not an error.
Reflection Question: You need every failed run of one workflow on main in the last week, with their job-level conclusions. Sketch the two-call sequence and name the filter parameters you'd use on the first call.