Skip to content
Open source Apache-2.0, on GitHub

Run your GitHub Actions locally. Merge on the green check.

Baste runs the workflows you already have in a fresh Linux VM on your machine every time you git push, then posts each job to GitHub as a check branch protection accepts. No queue, no workflow rewrites, no servers.

npm install -g @weftsh/baste

No Node.js? Use the install script instead.

macOS on Apple Silicon, Linux, and Windows 11 via WSL2. Uses your GitHub CLI login.

Runs the workflow files you already have

  • actions/checkout
  • actions/setup-node
  • JavaScript actions
  • composite actions
  • Docker actions
  • strategy.matrix
  • needs:
  • if:
  • artifacts

Why Baste

Cloud CI is rented and queued. Your laptop is mostly idle.

Every push waits for a hosted runner, then bills you for the minutes. Local tools have only ever solved half of that: they run something on your machine, but either not your real workflow or not in a way GitHub will accept.

Baste does both. It runs the jobs in .github/workflows in a runner-like VM, and reports each one to GitHub as a check you can make required.

How Baste compares with other local CI tools
act gh-signoff Baste
Runs the jobs in your workflow files ✓ A script you choose ✓
Each job in a fresh, runner-like VM Docker on your host – ✓
Result shows up on the commit in GitHub – ✓ ✓
Starts on git push, in the background You run it You run it ✓

How it works

Set it up once. Then just push.

No new workflow syntax, no runner to host, no change to how you work.

  1. 1

    Install and run baste init

    It checks virtualization, your GitHub CLI login and that your token can write commit statuses, then installs a pre-push hook. If anything is missing, it says what and changes nothing.

  2. 2

    Push like you always do

    git push returns right away. Within seconds each local job shows as pending on the commit, and boots a fresh VM that checks out exactly what you pushed, not your working tree.

  3. 3

    Merge on the green check

    Each job's check turns green or red with its duration and run id. Make the baste/… checks required, and pull requests merge on a local pass.

Features

A local pass you can trust to predict GitHub's

Fidelity first: Baste runs what it can run faithfully, and hands the rest to GitHub before the run starts.

A fresh VM for every job

Each job boots a copy-on-write clone of a pinned Ubuntu 24.04 image, as the runner user with passwordless sudo and Docker. Nothing leaks between runs, and nothing depends on what's installed on your laptop.

Checks GitHub accepts

One commit status per job, with a stable name like baste/CI/test that works as a required check in branch protection and rulesets.

Never blocks a push

The hook starts the run in the background and returns. A newer push to the same branch cancels the older run.

Honest hand-offs

Windows, macOS and service-container jobs are listed as handed to GitHub before the run starts. Never half-run.

Secrets in your keychain

Secrets come from the macOS Keychain or Secret Service, never from GitHub. A missing one fails the job by name.

Live logs, one-command reruns

baste logs latest streams each step as it runs. baste rerun re-checks the same commit.

Insights that justify the switch

Time per step, the slowest steps, and how long the same workflow last took on GitHub-hosted runners, at the end of every run and in baste insights.

Zero infrastructure

Your machine does the work and GitHub is the only backend. Baste uses the token from gh auth token and never stores one. Logs stay on your machine.

Merge gates

Merge on a local pass. Two ways.

A Required check Default
Require the baste/<workflow>/<job> checks that baste init lists, and make the GitHub-hosted versions optional. No workflow edits.
B The gate action Opt-in
Add one job to a workflow. When Baste already passed the commit locally, the GitHub-hosted jobs skip and the workflow passes in seconds, saving the Actions minutes. With no local result, everything runs on GitHub as usual.
.github/workflows/ci.yml
jobs:
  baste-gate:
    runs-on: ubuntu-latest
    outputs:
      skip: ${{ steps.gate.outputs.skip }}
    steps:
      - id: gate
        uses: weftsh/baste/gate@v1

  test:
    needs: baste-gate
    if: needs.baste-gate.outputs.skip != 'true'
    runs-on: ubuntu-latest
    # ...your steps, unchanged

Runs where you work

A real VM on every major desktop

Linux jobs run locally on every host. Baste picks the VM backend for your machine.

macOS 14+

Apple Silicon

Linux VMs through Tart, with Rosetta running x86_64 binaries and images.

x86_64 and arm64

Linux

Firecracker microVMs on KVM that boot in seconds.

Windows 11

WSL2

Firecracker inside WSL2, with nested virtualization turned on.

Runs locally

  • runs-on: ubuntu-* jobs
  • push and pull_request
  • JavaScript, composite, Docker actions
  • Matrices, needs, if, outputs
  • Artifacts between jobs
  • Step summaries and annotations

Handed to GitHub

  • Windows and macOS jobs
  • Self-hosted runners
  • services: and container:
  • Deployments (environment:)
  • OIDC (id-token: write)
  • Reusable workflows

The full list is in the compatibility guide. Intel Macs aren't supported.

Get started

Your first local check in a few minutes

One binary. It needs the GitHub CLI, logged in with gh auth login.

  • Free and open source under Apache-2.0
  • No account, no server, no workflow changes
  • baste uninstall removes the hook and statuses stop
Terminal
# install
npm install -g @weftsh/baste
# or, without Node.js
curl -fsSL https://raw.githubusercontent.com/weftsh/baste/main/install.sh | sh

# in your repository
baste init
git push
baste status
baste logs latest

FAQ

Questions teams ask first

Do I need to change my workflows?

No. Baste reads the workflows at the commit you pushed and runs the ubuntu-* jobs as they are. The optional gate action is the only edit, and only if you want GitHub to skip jobs that already passed locally.

Does my code leave my machine?

Only the commit statuses go to GitHub. The checkout comes from your local repository, and logs, artifacts and insights stay on your machine. Jobs still reach the network the way they would on GitHub, for example to install dependencies.

What happens to jobs Baste can't run?

They're listed as handed to GitHub before the run starts and get no local status, so GitHub keeps running them as usual. A job that needs one of them is handed over too.

Can a teammate fake a green check?

Statuses are posted with each developer's own GitHub token, so anyone with write access could post one by hand, just as they could today. Baste is built for small, trusted teams. Signed attestations are on the roadmap; if you need separation of duties, keep CI on GitHub.

How is this different from act?

act runs workflows in Docker containers on your host, and its results stay on your machine. Baste runs each job in a fresh VM built like a hosted runner, starts on push, and reports to GitHub so the result can gate a merge.

What does it cost?

Nothing. Baste is open source under Apache-2.0 and runs on hardware you already have. Jobs that pass locally don't need to use GitHub Actions minutes.

Stop waiting on the queue.

Install Baste, run baste init, and your next push is checked on your own machine.