Preconditions and requires:
Two different gates, for two different failure modes:
- Preconditions — "this task cannot run unless this shell check passes."
requires:— "this task cannot run unless these variables are set."
Preconditions
tasks:
deploy:
preconditions:
- sh: test -f ./secrets.env
msg: "Run ./scripts/fetch-secrets before deploying"
- sh: '[ "$BRANCH" = "main" ]'
msg: "Deploy only from main"
cmds:
- ./deployEach entry is a shell expression. rite runs each in sequence (order matters); the first one that exits non-zero aborts the task with its msg:. If all pass, cmds: run.
Preconditions stop the task chain. If deploy has a precondition failure, no dep of deploy runs, and the invocation exits non-zero. Compare to status: which only skips a task if up-to-date.
Short form
preconditions:
- sh: docker info
- sh: which kubectlWith no msg:, the default message is precondition not met: <the sh: expression>.
requires:
Preconditions handle shell checks. requires: handles variable presence and shape:
tasks:
release:
requires:
vars: [VERSION, REGISTRY]
cmds:
- docker push ${REGISTRY}/app:${VERSION}If either VERSION or REGISTRY is unset when release runs, rite aborts with a clear error naming the missing var. Set them via any precedence tier: shell env, CLI arg, entrypoint vars, etc.
requires: with enum validation
Restrict a var to a fixed set of values:
tasks:
deploy:
requires:
vars:
- name: ENV
enum: [dev, staging, prod]
cmds:
- ./deploy --env ${ENV}rite deploy ENV=qa fails with ENV must be one of [dev, staging, prod], got 'qa'.
Dynamic enum via template
vars:
ALLOWED_ENVS:
sh: cat .envs.json | jq -r '.envs | join(" ")'
tasks:
deploy:
requires:
vars:
- name: ENV
enum:
ref: .ALLOWED_ENVSThe enum values are computed from a sh: var. Useful when the valid set lives in a file or a remote source.
Preconditions vs status:
They look similar but behave differently:
preconditions: | status: | |
|---|---|---|
| All pass → | Task continues | Task is skipped (already up-to-date) |
| Any fails → | Task aborts with an error | Task runs |
Use preconditions: when "not allowed to proceed." Use status: when "no need to proceed."
Preconditions vs if:
Both gate task execution. The difference is what not running means:
preconditions: | if: | |
|---|---|---|
| When the condition fails → | Task aborts with an error message | Task silently skips, exit 0 |
| Use when | Invoking the task without the condition is a bug | Invoking the task without the condition is a valid no-op |
| Where it lives | Top of task, list form with sh: + msg: | Top of task or per-cmd, single expression |
Common pattern: combine both. Preconditions enforce hard invariants (working tree clean, required secrets present); if: controls feature-flag-style branches (deploy only when on the release branch, run cleanup only in prod). See conditional execution (if:) for full coverage of the if: family.
Interactive prompting for missing variables
When you invoke rite with -y/--yes or --interactive, missing required variables don't immediately abort the task — instead, rite prompts the user to supply them at the terminal:
tasks:
greet:
requires:
vars: [NAME]
cmds:
- echo "Hello, ${NAME}!"$ rite --interactive greet
NAME: Alice
Hello, Alice!For requires: with enum:, the prompt becomes a selection menu rather than free-form input:
tasks:
deploy:
requires:
vars:
- name: ENVIRONMENT
enum: [dev, staging, prod]
cmds:
- ./deploy --env ${ENVIRONMENT}$ rite --interactive deploy
ENVIRONMENT:
> dev
staging
prodThe prompt only fires when the var is unset across all precedence tiers — shell env, CLI args, Ritefile vars all checked first. So ENVIRONMENT=prod rite --interactive deploy runs without prompting.
For --interactive to work, rite must be running attached to a terminal. In CI (no TTY), the flag is a no-op and missing vars abort as usual. Use this for ergonomic local-dev workflows where you don't want to memorize flag names; rely on hard requires: failures in CI scripts.