Actions workflows
Read-only access to the workflow files in a repo plus the
workflow_dispatch trigger that the HTML "Run workflow" button
fires. Workflow runs themselves live at the
Actions workflow runs surface.
Scopes:
repo:readon the list / single-workflow GETsrepo:writeon the dispatch POST (same trust boundary as the HTML UI, where any pusher can run a workflow)
Endpoints
GET /api/v1/repos/{owner}/{repo}/actions/workflows list discovered workflows
GET /api/v1/repos/{owner}/{repo}/actions/workflows/{id_or_file} single workflow
POST /api/v1/repos/{owner}/{repo}/actions/workflows/{file}/dispatches workflow_dispatch
Discovery model
shithub does not keep a workflows table. The list endpoint walks
.shithub/workflows/ in the git tree at the repo's default-branch
HEAD (or ?ref= when provided) and parses each *.yml/*.yaml
file to extract its name:. Files that fail to parse still appear
in the listing — with their basename as the name — so the listing
reflects ground truth rather than silently dropping broken
workflows.
The id field on each entry is a deterministic 64-bit hash of the
file path so gh-shaped clients that pass workflow_id still work:
both ci.yml (basename), .shithub/workflows/ci.yml (full path),
and the numeric id are accepted on the single-workflow GET. The
dispatch endpoint accepts only the basename or full path (the
numeric id is rejected with 400 to keep dispatch a single
round-trip; clients with only an id should hit the list first to
resolve the path).
List response
[
{
"id": 7142839129843290000,
"name": "CI",
"path": ".shithub/workflows/ci.yml",
"file": "ci.yml",
"state": "active"
}
]
state is always "active" for now — enable/disable knobs land
in a follow-up PR alongside a workflow_disabled table.
Dispatch request
POST /api/v1/repos/alice/demo/actions/workflows/ci.yml/dispatches
Content-Type: application/json
{
"ref": "trunk",
"inputs": { "env": "prod", "debug": "true" }
}
refdefaults to the repo's default branch when omitted.inputsmust match the workflow's declaredon.workflow_dispatch.inputs:- Unknown inputs →
400 invalid_request. - Required (non-boolean) inputs missing → 400.
- Booleans must be
"true"/"false"strings. - Choices must match one of the declared options.
- Unknown inputs →
- A workflow without
on.workflow_dispatchreturns 400. - Successful dispatch returns
204 No Content. The run shows up in the actions runs feed shortly after the trigger pipeline enqueues it.
Errors
| Status | Cause |
|---|---|
| 400 | Workflow has no on.workflow_dispatch, or inputs malformed. |
| 400 | Numeric id passed to dispatch (use basename or full path). |
| 403 | PAT lacks repo:write. |
| 404 | Repo, ref, or workflow file unknown. |
View source
| 1 | # Actions workflows |
| 2 | |
| 3 | Read-only access to the workflow files in a repo plus the |
| 4 | `workflow_dispatch` trigger that the HTML "Run workflow" button |
| 5 | fires. Workflow runs themselves live at the |
| 6 | [Actions workflow runs](./actions-runs.md) surface. |
| 7 | |
| 8 | Scopes: |
| 9 | |
| 10 | - `repo:read` on the list / single-workflow GETs |
| 11 | - `repo:write` on the dispatch POST (same trust boundary as the |
| 12 | HTML UI, where any pusher can run a workflow) |
| 13 | |
| 14 | ## Endpoints |
| 15 | |
| 16 | ``` |
| 17 | GET /api/v1/repos/{owner}/{repo}/actions/workflows list discovered workflows |
| 18 | GET /api/v1/repos/{owner}/{repo}/actions/workflows/{id_or_file} single workflow |
| 19 | POST /api/v1/repos/{owner}/{repo}/actions/workflows/{file}/dispatches workflow_dispatch |
| 20 | ``` |
| 21 | |
| 22 | ## Discovery model |
| 23 | |
| 24 | shithub does not keep a `workflows` table. The list endpoint walks |
| 25 | `.shithub/workflows/` in the git tree at the repo's default-branch |
| 26 | HEAD (or `?ref=` when provided) and parses each `*.yml`/`*.yaml` |
| 27 | file to extract its `name:`. Files that fail to parse still appear |
| 28 | in the listing — with their basename as the name — so the listing |
| 29 | reflects ground truth rather than silently dropping broken |
| 30 | workflows. |
| 31 | |
| 32 | The `id` field on each entry is a deterministic 64-bit hash of the |
| 33 | file path so gh-shaped clients that pass `workflow_id` still work: |
| 34 | both `ci.yml` (basename), `.shithub/workflows/ci.yml` (full path), |
| 35 | and the numeric id are accepted on the single-workflow GET. The |
| 36 | dispatch endpoint accepts only the basename or full path (the |
| 37 | numeric id is rejected with 400 to keep dispatch a single |
| 38 | round-trip; clients with only an id should hit the list first to |
| 39 | resolve the path). |
| 40 | |
| 41 | ## List response |
| 42 | |
| 43 | ```json |
| 44 | [ |
| 45 | { |
| 46 | "id": 7142839129843290000, |
| 47 | "name": "CI", |
| 48 | "path": ".shithub/workflows/ci.yml", |
| 49 | "file": "ci.yml", |
| 50 | "state": "active" |
| 51 | } |
| 52 | ] |
| 53 | ``` |
| 54 | |
| 55 | `state` is always `"active"` for now — enable/disable knobs land |
| 56 | in a follow-up PR alongside a `workflow_disabled` table. |
| 57 | |
| 58 | ## Dispatch request |
| 59 | |
| 60 | ``` |
| 61 | POST /api/v1/repos/alice/demo/actions/workflows/ci.yml/dispatches |
| 62 | Content-Type: application/json |
| 63 | |
| 64 | { |
| 65 | "ref": "trunk", |
| 66 | "inputs": { "env": "prod", "debug": "true" } |
| 67 | } |
| 68 | ``` |
| 69 | |
| 70 | - `ref` defaults to the repo's default branch when omitted. |
| 71 | - `inputs` must match the workflow's declared |
| 72 | `on.workflow_dispatch.inputs`: |
| 73 | - Unknown inputs → `400 invalid_request`. |
| 74 | - Required (non-boolean) inputs missing → 400. |
| 75 | - Booleans must be `"true"` / `"false"` strings. |
| 76 | - Choices must match one of the declared options. |
| 77 | - A workflow without `on.workflow_dispatch` returns 400. |
| 78 | - Successful dispatch returns `204 No Content`. The run shows up in |
| 79 | the [actions runs](./actions-runs.md) feed shortly after the |
| 80 | trigger pipeline enqueues it. |
| 81 | |
| 82 | ## Errors |
| 83 | |
| 84 | | Status | Cause | |
| 85 | |------:|--------------------------------------------------------------| |
| 86 | | 400 | Workflow has no `on.workflow_dispatch`, or inputs malformed. | |
| 87 | | 400 | Numeric id passed to dispatch (use basename or full path). | |
| 88 | | 403 | PAT lacks `repo:write`. | |
| 89 | | 404 | Repo, ref, or workflow file unknown. | |