Gitea 1.27.3 has no retention for workflow run records — only for their logs and artifacts. LOG_RETENTION_DAYS clears the logs after 7 days, but the run entries stay listed forever, so the Actions page grows without limit.
On 2026-09-09 that list was 632 entries and had to be cleared by hand: 455 runs older than 7 days deleted through DELETE /api/v1/repos/{owner}/{repo}/actions/runs/{run_id}, one call each. It worked, but it lived in a scratch file on one machine, which is the wrong place for something that has to happen again every few weeks.
Scope
A workflow_dispatch workflow that deletes completed runs older than a given age, plus the script it calls.
Dry run by default. Deleting has to be asked for explicitly, not defaulted into — the operation is irreversible and there is no undo.
keep_days as an input, defaulting to 7 to match LOG_RETENTION_DAYS. Beyond that window the logs are already gone, so the entries being removed are empty shells.
Never touches a run that is not completed, which also means the cleanup run cannot delete itself.
Never touches a run with no usable start time. Queued runs report an epoch timestamp and cannot be aged, so they are kept rather than guessed at.
Reads the host and repository from the Actions context rather than hardcoding them.
The part that needs a decision
Which token. Deleting a run may be beyond what the automatic per-job token can do. The workflow therefore reads a repository secret, ACTIONS_CLEANUP_TOKEN, rather than assuming the built-in one is enough.
If the built-in token turns out to be sufficient, the secret can be dropped and the workflow simplified — worth checking on the first real run, since a token with delete rights sitting in repository secrets is not nothing on an instance that also hosts the deploy.
Out of scope
Running it on a schedule. Manual only for now: the operation is irreversible, the list is only an annoyance rather than a problem, and a cron that quietly deletes history should be a deliberate second step rather than the default.
Done when
The workflow can be dispatched from the Actions tab, a dry run reports what it would delete without deleting it, and an applied run clears the backlog.
Gitea 1.27.3 has no retention for workflow **run records** — only for their logs and artifacts. `LOG_RETENTION_DAYS` clears the logs after 7 days, but the run entries stay listed forever, so the Actions page grows without limit.
On 2026-09-09 that list was 632 entries and had to be cleared by hand: 455 runs older than 7 days deleted through `DELETE /api/v1/repos/{owner}/{repo}/actions/runs/{run_id}`, one call each. It worked, but it lived in a scratch file on one machine, which is the wrong place for something that has to happen again every few weeks.
## Scope
A `workflow_dispatch` workflow that deletes completed runs older than a given age, plus the script it calls.
- **Dry run by default.** Deleting has to be asked for explicitly, not defaulted into — the operation is irreversible and there is no undo.
- **`keep_days` as an input**, defaulting to 7 to match `LOG_RETENTION_DAYS`. Beyond that window the logs are already gone, so the entries being removed are empty shells.
- **Never touches a run that is not completed**, which also means the cleanup run cannot delete itself.
- **Never touches a run with no usable start time.** Queued runs report an epoch timestamp and cannot be aged, so they are kept rather than guessed at.
- Reads the host and repository from the Actions context rather than hardcoding them.
## The part that needs a decision
**Which token.** Deleting a run may be beyond what the automatic per-job token can do. The workflow therefore reads a repository secret, `ACTIONS_CLEANUP_TOKEN`, rather than assuming the built-in one is enough.
If the built-in token turns out to be sufficient, the secret can be dropped and the workflow simplified — worth checking on the first real run, since a token with delete rights sitting in repository secrets is not nothing on an instance that also hosts the deploy.
## Out of scope
Running it on a schedule. Manual only for now: the operation is irreversible, the list is only an annoyance rather than a problem, and a cron that quietly deletes history should be a deliberate second step rather than the default.
## Done when
The workflow can be dispatched from the Actions tab, a dry run reports what it would delete without deleting it, and an applied run clears the backlog.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Gitea 1.27.3 has no retention for workflow run records — only for their logs and artifacts.
LOG_RETENTION_DAYSclears the logs after 7 days, but the run entries stay listed forever, so the Actions page grows without limit.On 2026-09-09 that list was 632 entries and had to be cleared by hand: 455 runs older than 7 days deleted through
DELETE /api/v1/repos/{owner}/{repo}/actions/runs/{run_id}, one call each. It worked, but it lived in a scratch file on one machine, which is the wrong place for something that has to happen again every few weeks.Scope
A
workflow_dispatchworkflow that deletes completed runs older than a given age, plus the script it calls.keep_daysas an input, defaulting to 7 to matchLOG_RETENTION_DAYS. Beyond that window the logs are already gone, so the entries being removed are empty shells.The part that needs a decision
Which token. Deleting a run may be beyond what the automatic per-job token can do. The workflow therefore reads a repository secret,
ACTIONS_CLEANUP_TOKEN, rather than assuming the built-in one is enough.If the built-in token turns out to be sufficient, the secret can be dropped and the workflow simplified — worth checking on the first real run, since a token with delete rights sitting in repository secrets is not nothing on an instance that also hosts the deploy.
Out of scope
Running it on a schedule. Manual only for now: the operation is irreversible, the list is only an annoyance rather than a problem, and a cron that quietly deletes history should be a deliberate second step rather than the default.
Done when
The workflow can be dispatched from the Actions tab, a dry run reports what it would delete without deleting it, and an applied run clears the backlog.