Skip to content
Oeiuwq Faith Blog OpenSource Porfolio

bahdotsh/wrkflw

Validate and Run GitHub Actions locally.

bahdotsh/wrkflw.json
{
"createdAt": "2025-03-29T07:25:48Z",
"defaultBranch": "main",
"description": "Validate and Run GitHub Actions locally.",
"fullName": "bahdotsh/wrkflw",
"homepage": "https://github.com/bahdotsh/wrkflw",
"language": "Rust",
"name": "wrkflw",
"pushedAt": "2026-07-03T05:16:19Z",
"stargazersCount": 3265,
"topics": [
"ci",
"cli",
"devops",
"github",
"github-actions",
"hacktoberfest",
"ratatui",
"rust",
"tui"
],
"updatedAt": "2026-07-13T22:13:55Z",
"url": "https://github.com/bahdotsh/wrkflw"
}

Crates.io [License]!(LICENSE) Build Status Downloads

A command-line tool for validating and executing GitHub Actions workflows locally. Test your workflows on your machine before pushing to GitHub.

![WRKFLW Demo]!(demo.gif)

  • TUI interface — interactive terminal UI with Workflows, Execution, DAG, Logs, Trigger, Secrets, and Help tabs
  • Workflow validation — syntax checks, structural validation, and composite action input cross-checking with CI/CD-friendly exit codes
  • Local execution — Docker, Podman, emulation, or sandboxed secure emulation (no containers)
  • Diff-aware filtering — skip workflows whose on: block doesn’t match the simulated event and changed file set
  • Watch mode — rerun workflows automatically on file changes, with trigger-aware filtering
  • Job selection — run individual jobs with --job or via TUI job selection mode
  • Job dependency resolution — automatic ordering based on needs with parallel execution of independent jobs
  • Expression evaluator — evaluates ${{ ... }} expressions including toJSON, fromJSON, contains, startsWith, etc.
  • Action support — Docker container actions, JavaScript actions, composite actions (with output propagation), and local actions
  • Reusable workflows — execute caller jobs via jobs.<id>.uses (local or owner/repo/path@ref) with output propagation
  • Artifacts, cache, and inter-job outputsactions/upload-artifact, actions/download-artifact, actions/cache, and needs.<id>.outputs.*
  • GitHub context emulation — environment variables, GITHUB_OUTPUT, GITHUB_ENV, GITHUB_PATH, GITHUB_STEP_SUMMARY
  • Matrix builds — full support for include, exclude, max-parallel, and fail-fast
  • Secrets management — multiple providers (env, file, Vault, AWS, Azure, GCP) with masking and AES-256-GCM encrypted storage
  • Remote triggering — trigger workflow_dispatch runs on GitHub or GitLab pipelines
  • GitLab support — validate and trigger GitLab CI pipelines
  • GitHub encrypted secrets and fine-grained permissions
  • Event triggers other than workflow_dispatch for the remote trigger command
  • Private repos for remote uses: — reusable workflows clone over unauthenticated HTTPS
  • concurrency: groups and cancel-in-progress — parsed but not enforced
  • Service containers — services: is parsed but never started, in any runtime
  • Windows and macOS runners — runs-on: windows-* / macos-* is silently mapped to a container image (macOS → a Linux image, Windows → a Windows container that won’t run on Linux/macOS hosts). ${{ runner.os }} reflects the host OS, not runs-on.
Terminal window
cargo install wrkflw

Or with Homebrew (formula):

Terminal window
brew install wrkflw

Or build from source:

Terminal window
git clone https://github.com/bahdotsh/wrkflw.git
cd wrkflw
cargo build --release
Terminal window
# Launch the TUI (auto-detects .github/workflows)
wrkflw
# Validate workflows
wrkflw validate
# Run a workflow
wrkflw run .github/workflows/ci.yml
# Rerun workflows automatically on file changes
wrkflw watch
# List detected workflows and pipelines
wrkflw list
Terminal window
# Validate all workflows in .github/workflows
wrkflw validate
# Validate specific files or directories
wrkflw validate path/to/workflow.yml
wrkflw validate path/to/workflows/
# Validate multiple paths
wrkflw validate flow-1.yml flow-2.yml path/to/workflows/
# GitLab pipelines
wrkflw validate .gitlab-ci.yml --gitlab
# Verbose output
wrkflw validate --verbose path/to/workflow.yml

Exit codes: 0 = all valid, 1 = validation failures, 2 = usage error. Use --no-exit-code to disable.

Terminal window
# Run with auto-detection (default: tries Docker, then Podman, then emulation)
wrkflw run .github/workflows/ci.yml
# Run with Docker explicitly
wrkflw run --runtime docker .github/workflows/ci.yml
# Run with Podman
wrkflw run --runtime podman .github/workflows/ci.yml
# Run in emulation mode (no containers)
wrkflw run --runtime emulation .github/workflows/ci.yml
# Run in sandboxed secure emulation
wrkflw run --runtime secure-emulation .github/workflows/ci.yml
# Run a specific job
wrkflw run --job build .github/workflows/ci.yml
# List jobs in a workflow
wrkflw run --jobs .github/workflows/ci.yml
# Preserve failed containers for debugging
wrkflw run --preserve-containers-on-failure .github/workflows/ci.yml

Skip workflows whose on: block wouldn’t fire for a given event/change set. Strict mode is on by default: wrkflw run --event … without --diff or --changed-files is rejected up front rather than silently skipping every paths:-gated workflow.

Terminal window
# Auto-detect changed files from git (vs origin/HEAD, main/master, or HEAD~1)
wrkflw run --diff --event push .github/workflows/ci.yml
# Pin the diff range
wrkflw run --diff --diff-base main --diff-head HEAD --event push .github/workflows/ci.yml
# Supply changed files explicitly (e.g. from a CI wrapper)
wrkflw run --event push --changed-files src/main.rs,Cargo.toml .github/workflows/ci.yml
# Simulate a pull_request — `--base-branch` is required under strict mode
wrkflw run --event pull_request --base-branch main --diff .github/workflows/ci.yml
# Opt out of strict rejection (legacy warn-and-proceed)
wrkflw run --event push --no-strict-filter .github/workflows/ci.yml

See [BREAKING_CHANGES.md]!(BREAKING_CHANGES.md) for full migration notes.

Terminal window
# Watch .github/workflows for changes and rerun affected workflows
wrkflw watch
# Watch a specific path, simulate pull_request, and cap concurrency
wrkflw watch --event pull_request --base-branch main \
--max-concurrency 2 --debounce 750 .github/workflows
# Ignore extra directories on top of the built-in list
wrkflw watch --ignore-dir .terraform --ignore-dir coverage
Terminal window
# Open TUI with default directory
wrkflw tui
# Open with specific runtime
wrkflw tui --runtime podman

Tabs: Workflows · Execution · DAG · Logs · Trigger · Secrets · Help.

Controls:

KeyAction
Tab / Shift+TabSwitch tabs
17Jump to tab by number
w / x / l / hJump to Workflows / Execution / Logs / Help
/ or k/jNavigate / scroll
SpaceToggle workflow selection
EnterRun / view details
rRun selected workflows
a / nSelect all / deselect all
Shift+RReset workflow status
Shift+JView jobs in workflow
eCycle runtime (Docker / Podman / Emulation / Secure Emulation)
vToggle Execution / Validation mode
d / DToggle diff-aware filter / cycle simulated event
tTrigger remote workflow
,Open Tweaks overlay
?Toggle help overlay
q / EscQuit / back

Logs tab adds s (search), f (filter), c (clear), n (next match). Trigger tab adds p (github↔gitlab), b (edit branch), + (add input), c (copy curl preview).

Trigger workflow_dispatch events on GitHub or GitLab.

Terminal window
# GitHub (requires GITHUB_TOKEN env var)
wrkflw trigger workflow-name --branch main --input key=value
# GitLab (requires GITLAB_TOKEN env var)
wrkflw trigger-gitlab --branch main --variable key=value
ModeDescriptionBest for
Auto (default)Detects Docker, then Podman, then falls back to emulationMost users
DockerFull container isolation, closest to GitHub runnersProduction, CI/CD
PodmanRootless containers, no daemon requiredSecurity-conscious environments
EmulationRuns directly on host, no containers neededQuick local testing
Secure EmulationSandboxed host processes with filesystem/network restrictionsRunning untrusted workflows without a container runtime
jobs:
call-local:
uses: ./.github/workflows/shared.yml
call-remote:
uses: my-org/my-repo/.github/workflows/shared.yml@v1
with:
foo: bar
secrets:
token: ${{ secrets.MY_TOKEN }}
  • Local refs resolve relative to the working directory
  • Remote refs are shallow-cloned at the specified @ref
  • with: entries become INPUT_<KEY> env vars; secrets: become SECRET_<KEY>
  • Outputs from called jobs are merged back into needs.<id>.outputs.*

Limitations: private repos for remote uses: are not yet supported (the clone is unauthenticated); declared on.workflow_call.outputs is approximated by flattening all called-job outputs (the explicit mapping is not yet parsed).

WRKFLW supports GitHub Actions-compatible ${{ secrets.* }} syntax with multiple providers:

Terminal window
# Environment variables (simplest)
export GITHUB_TOKEN="ghp_..."
wrkflw run .github/workflows/ci.yml
# File-based secrets (JSON, YAML, or .env format)
# Configure in ~/.wrkflw/secrets.yml

Supported providers: environment variables, file-based, HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, Google Cloud Secret Manager. See the [secrets demo]!(examples/secrets-demo/) for detailed examples.

WRKFLW is organized as a Cargo workspace with focused crates:

CratePurpose
wrkflwCLI binary and library entry point
wrkflw-executorWorkflow execution engine, expression evaluator, artifact/cache stores
wrkflw-parserWorkflow file parsing and schema validation
wrkflw-evaluatorStructural evaluation of workflow files
wrkflw-validatorsValidation rules for jobs, steps, triggers
wrkflw-runtimeContainer and emulation runtime abstractions
wrkflw-trigger-filteron: block parsing and change-set matching
wrkflw-watcherFile watcher with trigger-aware re-execution
wrkflw-uiTerminal user interface
wrkflw-modelsShared data structures
wrkflw-matrixMatrix expansion utilities
wrkflw-secretsSecrets management with multiple providers
wrkflw-githubGitHub API integration
wrkflw-gitlabGitLab API integration
wrkflw-loggingIn-memory logging for TUI/CLI
wrkflw-utilsShared helpers

MIT License - see [LICENSE]!(LICENSE) for details.