Like turborepo and nx, actrun can skip workflows when no relevant files have changed since the last successful run. This is useful in monorepos or projects where different workflows cover different parts of the codebase.
Define file patterns per workflow in actrun.toml:
[affected."ci.yml"]
patterns = ["src/**", "*.toml", "Cargo.lock"]
[affected."lint.yml"]
patterns = ["src/**", "*.config.js"]
[affected."docs.yml"]
patterns = ["docs/**", "README.md"]The key after affected. matches the workflow filename (basename, not full path).
# Compare against last successful run
actrun workflow run .github/workflows/ci.yml --affected
# Compare against a specific revision
actrun workflow run .github/workflows/ci.yml --affected HEAD~3
actrun workflow run .github/workflows/ci.yml --affected abc123If no [affected."<workflow>"] section is defined in actrun.toml, actrun falls back to the on.push.paths patterns from the workflow file itself. This means many workflows work with --affected out of the box.
- Find the base revision: use the explicit rev argument (e.g.
HEAD~3), or find the latest successful run'safter_sha - Compute changed files:
git diff --name-only <base_rev> HEAD+ uncommitted/untracked files - Resolve patterns: use
actrun.toml[affected."<workflow>"]patterns, or fall back toon.push.pathsfrom the workflow - If any changed file matches the patterns, run the workflow
- If no files match, skip with a message
# No changes in src/ since last success
$ actrun ci.yml --affected
affected: no changes match patterns for ci.yml (since run-1)
# After editing src/main.rs
$ actrun ci.yml --affected
affected: changes detected for ci.yml (since run-1)
run_id=run-2
...
# First run (no history) always executes
$ actrun ci.yml --affected
affected: no previous successful run found, running
| Pattern | Matches |
|---|---|
src/** |
All files under src/ recursively |
src/* |
Direct children of src/ only |
*.rs |
Files ending with .rs in the root |
**/*.rs |
Files ending with .rs at any depth |
README.md |
Exact match |
docs/** |
All files under docs/ recursively |
When a workflow partially fails, --retry re-runs only the failed jobs, skipping jobs that already succeeded. This saves time by not re-executing expensive build steps.
# First run: build succeeds, test fails
$ actrun workflow run ci.yml
run_id=run-1
state=partial_failed
build/step_1: success
test/step_1: failed
# Retry: only test job runs, build is skipped
$ actrun workflow run ci.yml --retry
retry: re-running failed jobs from run-1:
- test
retry: skipping successful jobs:
- build
run_id=run-2
state=completed
test/step_1: success
# No more failures to retry
$ actrun workflow run ci.yml --retry
retry: last run run-2 was successful, nothing to retry- Find the latest run for this workflow (success or failure)
- If the latest run was successful, print "nothing to retry" and exit
- Extract failed job IDs from the run record
- Filter out succeeded jobs from the workflow
- Execute only the remaining (failed) jobs
--retrylooks at the latest run regardless of success/failure status- Jobs are the unit of retry. If a job has 5 steps and the 3rd fails, the entire job is re-run (all 5 steps)
--retrycan be combined with--skip-actionand other flags- Skipped jobs and re-running jobs are logged before execution
These features work independently and can be used in sequence:
# Normal development loop
actrun ci.yml --affected # Skip if nothing changed
actrun ci.yml --retry # Re-run only failed jobs after fixing
# CI-like workflow
actrun ci.yml --affected --local # Run only if relevant files changedlocal_skip_actions in actrun.toml specifies actions to skip when running locally. This is the primary mechanism for using host-installed toolchains instead of GitHub Actions setup actions.
# Generated by: actrun init (auto-detects installed tools)
local_skip_actions = [
"actions/checkout",
"actions/setup-node",
"actions/setup-python",
]When actions are skipped, actrun logs each one before execution:
skip build/actions/checkout@v4 (actions/checkout@v4)
skip build/Setup Node (actions/setup-node@v4)
run_id=run-1
...
actrun doctor validates that skipped setup actions have corresponding local tools:
$ actrun doctor
...
=== actrun.toml ===
local_skip_actions:
- actions/checkout
- actions/setup-node
- actions/setup-python
ok skip actions/setup-node: local node found (v24.12.0)
ok skip actions/setup-python: local python3 found (Python 3.14.2)
When combined with nix integration, local_skip_actions skips the GitHub setup actions while nix provides the toolchains:
local_skip_actions = ["actions/checkout", "actions/setup-node"]
nix_mode = "" # auto-detect flake.nixThe workflow's actions/setup-node@v4 is skipped, and the run: steps execute inside nix develop where node is provided by the flake.
When --event is omitted, actrun first tries to infer common GitHub context values from the local git repository. If you need stable local values, add [local_context] to actrun.toml:
[local_context]
repository = "owner/repo"
ref_name = "feature/local-demo"
before_rev = "HEAD^"
after_rev = "HEAD"
actor = "your-name"This fills missing values for github.repository, github.ref_name, github.sha, github.actor, and the matching GITHUB_* variables. For precedence details and a runnable example, see Local GitHub Context.
# Workspace
workspace_mode = "local"
# Skip setup actions — use local (or nix) toolchain
local_skip_actions = [
"actions/checkout",
"actions/setup-node",
"actions/setup-python",
]
# Trust third-party actions
trust_actions = true
# Optional local GitHub context override
# [local_context]
# repository = "owner/repo"
# ref_name = "main"
# before_rev = "HEAD^"
# after_rev = "HEAD"
# actor = "your-name"
# Nix (auto-detected from flake.nix)
# nix_mode = ""
# nix_packages = ["python312", "jq"]
# Container runtime
# container_runtime = "docker"
# Affected file patterns per workflow
[affected."ci.yml"]
patterns = ["src/**", "package.json", "pnpm-lock.yaml"]
[affected."lint.yml"]
patterns = ["src/**", "*.config.*"]
[affected."docs.yml"]
patterns = ["docs/**", "*.md"]Some GitHub Actions features are designed for cloud execution and have no local equivalent. actrun handles these gracefully:
Workflows using OIDC for cloud authentication (permissions: id-token: write) work without errors — permissions blocks are silently ignored. However, ACTIONS_ID_TOKEN_REQUEST_URL and ACTIONS_ID_TOKEN_REQUEST_TOKEN are not set, so steps calling getIDToken() will fail.
Recommended approach: skip or override OIDC-dependent steps:
# actrun.toml
[override."aws-actions/configure-aws-credentials"]
run = "echo 'using local AWS credentials'"Or use if: ${{ !env.ACTRUN_LOCAL }} in the workflow:
- uses: aws-actions/configure-aws-credentials@v4
if: ${{ !env.ACTRUN_LOCAL }}
with:
role-to-assume: arn:aws:iam::123456:role/deploypermissions: Silently ignored. Local execution uses host user permissions.concurrency: Silently ignored. Local execution is sequential.