Bootstrap is a declarative package bootstrapper for reproducible system provisioning.
Instead of writing an imperative shell script that decides how to install each package, you write a small manifest that describes the packages a system should have. Bootstrap parses that manifest, plans the requested package operations, resolves them through a native package-manager backend, and then either explains or executes the resulting plan.
The goal is not to replace the operating system package manager. The goal is to make bootstrap intent easier to read, review, test, and repeat.
- Plain-text package manifests.
- Comments and blank lines for human-readable manifests.
- Package version constraints such as
>=,=,==,<, and>. - Dry-run mode for reviewing planned work before changing a system.
- Explain mode for understanding how manifest entries become planned actions.
- Native package-manager delegation for APT, Alpine APK, and DNF.
- Conservative diagnostics that stop rather than guessing when input is unclear.
- A single generated
bootstrap.bashrelease artifact.
The published release artifact is a standalone Bash script.
To download the latest release with curl:
curl -fsSL \
https://github.com/wesley-dean/bootstrap/releases/latest/download/bootstrap.bash \
-o bootstrap.bash
chmod +x bootstrap.bashIf you use Bootstrap frequently, you may prefer a shell function that keeps the
latest release artifact in ~/.local/bin/bootstrap.bash and lets you provide a
small package manifest directly as command-line arguments.
For example, after defining the function below, this command:
bootstrap git curl jqis equivalent to passing this manifest to Bootstrap through standard input:
git
curl
jq
The function intentionally keeps the wrapper small. If the local copy of the
release artifact is missing, it downloads the latest published bootstrap.bash
artifact and marks it executable. It then writes each argument on its own line
and pipes that generated manifest into Bootstrap.
bootstrap() {
local bootstrap_path="${bootstrap_path:-${HOME}/.local/bin/bootstrap.bash}"
local bootstrap_url="${bootstrap_url:-https://github.com/wesley-dean/bootstrap/releases/latest/download/bootstrap.bash}"
local -a bootstrap_args=("${bootstrap_args[@]:-}")
if [[ ! -x "${bootstrap_path}" ]]; then
mkdir -p "${bootstrap_path%/*}" \
&& curl -fsSL \
"$bootstrap_url" \
-o "${bootstrap_path}" \
&& chmod +x "${bootstrap_path}"
fi
for package in "$@"; do
printf '%s\n' "${package}"
done | "${bootstrap_path}" "${bootstrap_args[@]}" -
}Create a manifest file. This example uses packages.manifest:
#------------------------------------------------------------------------------
# Bootstrap starter manifest
#
# Each logical line describes one package requirement. Blank lines and comments
# are ignored. Inline comments are also supported.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# Unconstrained packages
#
# These packages may be installed at the package manager's candidate version.
#------------------------------------------------------------------------------
git
curl
jq
# Inline comments are allowed after package requirements.
ca-certificates # useful for HTTPS package repositories and downloads
#------------------------------------------------------------------------------
# Minimum versions
#
# These entries require the package manager's candidate version to satisfy the
# lower bound before Bootstrap will plan installation.
#------------------------------------------------------------------------------
shellcheck >= 0.10
shfmt >= 3.10
bats >= 1.12
#------------------------------------------------------------------------------
# Exact versions
#
# A single equals sign and a double equals sign are both supported for exact
# version requirements.
#------------------------------------------------------------------------------
yq = 4.45.4
openssl == 3.0
#------------------------------------------------------------------------------
# Upper bounds
#
# Upper bounds can be useful when a later major version is not yet supported by
# the workstation, project, or operational environment being bootstrapped.
#------------------------------------------------------------------------------
python3 < 3.14
nodejs < 23
#------------------------------------------------------------------------------
# Greater-than constraints
#
# This form is available when the candidate version must be strictly newer than
# a known baseline.
#------------------------------------------------------------------------------
make > 4.0
Then run Bootstrap with the manifest:
./bootstrap.bash packages.manifestTo inspect the plan without making package-manager changes:
./bootstrap.bash --dry-run packages.manifestTo include a plain-language explanation of the planning boundary:
./bootstrap.bash --dry-run --explain packages.manifestTo select the package-manager backend explicitly:
./bootstrap.bash --package-manager apt packages.manifest
./bootstrap.bash --package-manager apk packages.manifest
./bootstrap.bash --package-manager dnf packages.manifestThe Bootstrap tool is distributed as a single Bash shell script with no external library dependencies. While the source for the tool is spread across multiple files, the distributed tool is a single file. Therefore, "installation" in a traditional sense isn't a hard requirement.
vet can be used as a safer replacement for
the common curl | bash pattern. It downloads the release artifact, displays
the script for review, and then runs it with the arguments you provide.
To run Bootstrap with packages.manifest through vet:
vet https://github.com/wesley-dean/bootstrap/releases/latest/download/bootstrap.bash \
packages.manifestThe same Bootstrap arguments can be passed after the release URL:
vet https://github.com/wesley-dean/bootstrap/releases/latest/download/bootstrap.bash \
--dry-run --explain packages.manifestIt is not recommended, but it's also possible to run Bootstrap by fetching it
first using curl (or wget). This is not a recommended approach; it's
included here for completeness. From a security perspective, it's an
anti-pattern to download and run a shell script -- especially one that makes
changes to the underlying system like installing packages -- without inspecting
the script first. The source for Bootstrap is openly available and can be
inspected along with the process that the bootstrap.bash script is generated.
The source is heavily commented so that it ought to be clear what every single
function in the script does, how they work, how they're invoked, and any
assumptions made when running them. The code should be as direct, obvious, and
boring as possible.
If you understand the risks and still prefer this approach, you can invoke Bootstrap directly.
Warning
Running a script directly from the Internet (for example, curl ... | bash)
executes code before you have an opportunity to inspect it. Download the
script first, or use vet, if you want to review the script before
execution.
curl https://github.com/wesley-dean/bootstrap/releases/latest/download/bootstrap.bash \
| bash -s -- --dry-run --explain packages.manifestThe README is intentionally brief. More detailed project documentation is kept in focused files:
doc/motivation.mddiscusses why this project existsdoc/cli.mddescribes the supported command-line interface.doc/manifest-format.mddescribes the manifest grammar and parser behavior.doc/adr/contains the project's Architecture Decision Records.testing.mddescribes how to test the tool during developmentROADMAP.mddescribes planned implementation phases and future work.CONTRIBUTING.mddescribes contribution expectations.SECURITY.mdexplains how to report security concerns.
Bootstrap is under active development. The current implementation focuses on a small, reviewable package-manifest workflow with APT, Alpine APK, and DNF backends. Additional package-manager backends and richer provisioning features are future work.
See LICENSE for license information.