Skip to content

Checks

Checks report facts about the external world: “does this file exist?”, “does this command succeed?”, “has this target changed?” When a check passes, Bivvy skips the step (unless --force is used). Use check: for a single check or checks: for multiple (treated as an implicit all).

Checks can also be used in satisfied_when conditions, which declare when a step’s purpose is already fulfilled.

Migrating from an older config? See the Migrate to the New Check Schema guide for converting completed_check:, watches:, and prompt_if_complete: to the modern fields.

Check Types

Presence

Confirms that a file, directory, or binary exists:

steps:
deps:
command: "yarn install"
check:
type: presence
target: "node_modules"

Use kind: binary to check for a binary on $PATH:

steps:
install_rustup:
command: "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh"
check:
type: presence
target: "rustup"
kind: binary

Use kind: custom with a command: for more complex presence detection:

steps:
docker_running:
command: "open -a Docker"
check:
type: presence
kind: custom
command: "docker info"

When kind is omitted, Bivvy infers from context: targets containing /, ., or ~ are treated as files; simple names like rustc or node are treated as binaries.

Execution

Runs a command and validates the result:

steps:
db:
command: "rails db:create"
check:
type: execution
command: "rails db:version"

The validation field controls how the result is interpreted:

  • success (default) — command exits with status 0
  • truthy — command exits 0 and produces non-empty stdout
  • falsy — command exits 0 with empty stdout, or exits non-zero
steps:
seed:
command: "rails db:seed"
check:
type: execution
command: "rails runner 'exit(User.any? ? 0 : 1)'"
validation: truthy

Change

Detects whether a target has changed since the last run. This replaces the old watches field with a richer model:

steps:
deps:
command: "yarn install"
check:
type: change
target: "yarn.lock"
on_change: proceed

The on_change field controls what happens when a change is detected:

  • proceed (default) — the step runs (change means “work needed”)
  • fail — the step fails immediately (change means “unexpected drift”)
  • require — flags another step as required via require_step
steps:
deps:
command: "yarn install"
check:
type: change
target: "yarn.lock"
on_change: require
require_step: deps

Change checks support different target kinds:

  • file (default) — hash a single file
  • glob — hash all files matching a pattern
  • command — hash the output of a command
steps:
codegen:
command: "cargo build --build-script"
check:
type: change
target: "src/**/*.proto"
kind: glob
on_change: proceed

Baselines

Change checks compare the current hash against a stored baseline. By default the baseline updates after each successful run (each_run). Use first_run to freeze the baseline after the first evaluation:

steps:
check_runtime:
command: "asdf install"
check:
type: change
target: "ruby --version"
kind: command
on_change: fail
baseline: first_run

You can also compare against a named snapshot or a git ref instead of the run-based baseline:

check:
type: change
target: "schema.rb"
on_change: fail
baseline_snapshot: v1.0 # compare against named snapshot "v1.0"
check:
type: change
target: "schema.rb"
on_change: fail
baseline_git: main # compare against content at git ref "main"

Size Limits

Change checks refuse to hash targets larger than 50 MB by default. Override with size_limit (in bytes) or set to null for no limit:

check:
type: change
target: "data/fixtures.sql"
on_change: proceed
size_limit: 104857600 # 100 MB

Snapshot Scope

By default, change check baselines are shared across all workflows in the project. Use scope: workflow to isolate baselines per workflow:

check:
type: change
target: "Gemfile.lock"
on_change: proceed
scope: workflow

Combinators

all

All checks must pass (this is the default when using checks:):

steps:
deps:
command: "yarn install"
check:
type: all
checks:
- type: presence
target: "node_modules"
- type: execution
command: "yarn check --integrity"

Using checks: directly on the step is equivalent to wrapping in all:

steps:
deps:
command: "yarn install"
checks:
- type: presence
target: "node_modules"
- type: execution
command: "yarn check --integrity"

any

At least one check must pass:

steps:
deps:
command: "yarn install"
check:
type: any
checks:
- type: presence
target: "node_modules"
- type: presence
target: "vendor/bundle"

Forcing Re-run

Bypass check: and satisfied_when evaluation for one or more steps. Preconditions are not bypassed by either flag.

Force specific steps (comma-separated):

Terminal window
bivvy run --force deps,build

Force every step in the workflow:

Terminal window
bivvy run --force-all

--force-all also overrides any step-level configuration that would otherwise prompt or skip — it means “run it all, don’t bother me about it.” --force and --force-all can be passed together; --force-all is a superset.

Named Checks

Any check can have a name field. Named checks can be referenced from satisfied_when conditions on the same step or on other steps:

steps:
install_deps:
command: "yarn install"
check:
type: presence
name: deps_installed
target: "node_modules"

See satisfied_when below for how to reference named checks.

satisfied_when

satisfied_when declares when a step’s purpose is already fulfilled. It is a list of conditions that must all pass for the step to be considered satisfied. Unlike check, which reports whether the step’s side effects already exist, satisfied_when lets you compose conditions from multiple sources, including checks defined on other steps.

When satisfied_when is present and all conditions pass, the step is skipped. When satisfied_when is present but any condition fails, the step runs — even if the step’s own check would have passed. In other words, satisfied_when takes priority over check.

Inline conditions

Each condition can be an inline check definition (same syntax as check):

steps:
install_deps:
command: "yarn install"
satisfied_when:
- type: presence
target: "node_modules"
- type: execution
command: "yarn check --integrity"

Referencing named checks

Use ref to reference a named check. Unqualified names refer to the same step; use step_name.check_name to reference a check on a different step:

steps:
install_deps:
command: "yarn install"
check:
type: presence
name: deps_present
target: "node_modules"
build:
command: "yarn build"
depends_on: [install_deps]
satisfied_when:
- ref: install_deps.deps_present
- type: presence
target: "dist"

In this example, the build step is satisfied only when both install_deps’s deps_present check passes and the dist directory exists.

Mixing refs and inline checks

You can freely mix ref entries and inline check definitions in the same satisfied_when list:

satisfied_when:
- ref: deps_installed # same-step named check
- ref: install_deps.deps_present # cross-step named check
- type: execution # inline check
command: "yarn check --integrity"

How satisfaction is evaluated

Bivvy evaluates satisfaction in priority order (first match wins):

  1. satisfied_when — if present and all conditions pass, the step is satisfied. If present and any condition fails, the step is not satisfied (no fallthrough to check or history).
  2. check/checks — if the step’s check passes, the step is satisfied.
  3. Execution history — if the step ran successfully within its rerun window, the step is satisfied.

If none of these apply, the step needs to run.

Behavior Options

steps:
deps:
command: "yarn install"
check:
type: presence
target: "node_modules"
prompt_on_rerun: false # Skip silently if satisfied (default: false)
skippable: true # Allow skipping (default: true)