Skip to content

State & ownership

~/.local/state/bedouin/state.json, mode 0600.

{
"schema_version": 1,
"items": {
"package/zellij": {
"kind": "package",
"owner": "bedouin",
"status": "complete",
"version": "0.40.1",
"method": "cargo",
"path": ["/home/you/.cargo/bin"],
"resolved_from": { "version": "macos-arm64" }
},
"language/rust": {
"kind": "language", "owner": "bedouin", "status": "complete",
"bin_dirs": ["/home/you/.cargo/bin"]
}
}
}

owner: bedouin means Bedouin installed it and may remove it. owner: preexisting means it was already there — adopted, never owned, and it survives being dropped from the config. A jq that predates Bedouin is yours.

bin_dirs is what each step’s PATH is assembled from. It is recorded from the installer’s own recipe, never from your config — you should not have to tell Bedouin where rustup puts cargo.

method is recorded rather than assumed, so a package that moves from apt to cargo is removed and reinstalled rather than installed twice.

resolved_from records which arm won for each conditional field. It costs almost nothing and it is what lets doctor say this resolved differently than last apply — the failure a conditional config otherwise makes invisible.

status distinguishes a finished step from one that started and did not. An incomplete item re-diffs as needing work.

Four rules, and each of them, absent, degrades to treat state as empty — which re-adopts everything Bedouin installed as pre-existing and disables uninstall permanently.

  • An advisory lock for the length of an apply. A second apply waits rather than interleaving writes. A lock left by a killed run is taken over, not honoured.
  • Written to a temporary file and renamed, so a crash mid-write leaves the previous state.
  • Mode 0600.
  • An unreadable or newer state file is a hard error, never an empty state. A missing file is an empty state, because that is a first run — and it is the only case that means it.