plan & apply
bedouin plan
Section titled “bedouin plan”Resolves facts, resolves the config for this machine, diffs against what is recorded and what is on disk, and prints the result. It changes nothing.
Bedouin will make the following changes:
+ manager brew not installed ~ package zellij 0.39.2 -> 0.40.1 cargo - package ripgrep was: apt, owner: bedouin
Plan: 1 to add, 1 to change, 1 to remove.Exit codes are made for scripting: 0 nothing pending, 2 changes pending, 1 error. A CI drift check just reads the status.
-v annotates each conditional value with the arm that won, and lists what
only: pruned:
+ package neovim latest apt from = nobleThat is the one visible trace of arm selection, and it is what you reach for when a config resolves differently than you expected.
bedouin apply
Section titled “bedouin apply”Shows the plan, asks, then executes. -y skips the question.
It is not transactional, and does not pretend to be — rolling back a package manager is not something anything can do honestly. Instead:
- A step records its intent before it begins and marks it complete after. A run interrupted between installing and recording leaves an honest record, not a package that looks like it was always there.
- On failure it stops, prints the failed step, its output, and what it did not attempt. A half-configured machine reporting success is worse than one reporting where it broke.
- Re-running resumes, because
planre-diffs. There is no separate resume.
--skip
Section titled “--skip”Stopping is right when the failure is a surprise. When it is not — a package from an apt repository this machine has not been given yet — halting the other fifty steps helps nobody:
bedouin apply --skip 1password-cli,caddybedouin apply --skip package/1password-cli # the full id works tooTakes the id a failure prints (package/jq) or just the name (jq). Skipped
steps are named in the report, never silently dropped: a run that quietly
did less than the plan promised is the thing this tool exists not to do. They
stay in the next plan, because nothing about the config changed.
Output
Section titled “Output”Each step gets a heading, its command output is dimmed beneath it, and the plan colours its sigils — green to add, amber to change, red to remove:
:: [7/57] package/ripgrep Setting up ripgrep (14.1.0-1) ...:: [8/57] language/rust info: syncing channel updates for stableColour is decided once, from whether stdout is a terminal, NO_COLOR, and
TERM. A pipe, a CI log and a redirect to a file all get plain text without
being asked, which is also what makes the output safe to paste into a bug
report.
Reviewing a plan, applying it later
Section titled “Reviewing a plan, applying it later”bedouin plan -o plan.json# read it, commit it, hand it to someonebedouin apply -f plan.jsonThe artifact freezes the resolved facts including the environment variables your config reads — only those, at mode 0600. Without that, a plan reviewed in one terminal could mean something else in another, since the environment is process-scoped and otherwise unrecorded.
apply -f re-checks the machine state and facts and refuses a stale plan. It
does not re-check the environment: that is the thing the artifact exists to
carry forward.