Most GitHub Actions are consumed as a step:
steps:
- uses: actions/checkout@v4Upkeep is consumed as a job, pointing at a workflow file:
jobs:
audit:
uses: wei18/upkeep/.github/workflows/audit.yml@v2That second form looks unfamiliar next to the usual - uses: owner/action@v1, and people reasonably ask why. It is the standard, documented syntax for a reusable workflow (on: workflow_call) — see GitHub: Reuse workflows. Here is why Upkeep is built that way.
Upkeep dispatches a team of reviewers. We want each reviewer to:
- run in parallel — a full audit should not take six times one reviewer's wall-clock; and
- be fault-isolated — one reviewer failing (timeout, API hiccup) must not abort the others.
The native GitHub primitive for "run the same unit many times, in parallel, independently" is strategy.matrix. Matrix is a job-level feature: only a workflow can declare jobs and a matrix. An action cannot. To fan the reviewers out across parallel, isolated matrix jobs, Upkeep must be a reusable workflow.
There are two kinds of action, and neither can express that fan-out:
- JavaScript / Docker action — a single entrypoint (e.g.
main: dist/index.js). It cannotuses:another action, so it could not delegate the LLM work toanthropics/claude-code-action; it would have to call Claude itself. And it still could not run jobs in parallel. - Composite action — runs as a sequence of steps inside one job. It can
uses:other actions (so it could callclaude-code-action), but with no matrix the reviewers would run sequentially, in a single job.
So a composite action (- uses: wei18/upkeep@v2) is possible — at the cost of sequential reviewers. Upkeep deliberately chose the reusable-workflow form to keep reviewers parallel and independently isolated. For a scheduled audit, the slower sequential path would be acceptable; we preferred parallelism and clean failure isolation.
As of v2.1, the repo root ships exactly that trade-off as action.yml (- uses: wei18/upkeep@v2) — a sequential alternative that gets Upkeep listed on the GitHub Marketplace. The reusable workflow above stays the recommended integration path whenever reviewer parallelism matters.
Only the call-site syntax. jobs.<id>.uses: owner/repo/.github/workflows/file.yml@ref instead of - uses: owner/action@ref. Everything else behaves like an action: inputs via with:, secrets via secrets:, version pinning with @v1.