strap: the bootstrap script GitHub wrote to replace Boxen
👢 Bootstrap your macOS development system.
At a glance
- What is it?
- A shell script that turns a fresh Mac into a working development machine, with a security-hardening pass, Homebrew, and an explicit list of what it refuses to do.
- Who is it for?
- strap is unusually honest for a bootstrap script, mostly because its README contains an out-of-scope section that says what it will not install and why. That list is the strongest argument for it: a machine setup script that refuses to enable network services or disable security features is easier to hand to a new hire than one that quietly changes everything.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 4 days ago.
- What is it written in?
- Mainly Shell, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 7, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What the script actually does to a fresh Mac
The README's motivation section is the most useful part of the whole document. Strap exists to replace Boxen inside GitHub, and it links to a 2016 post laying out what was wrong with Boxen and what the replacement had to do. Read that framing before the feature list, because the feature list reads like a list of security settings rather than a list of developer conveniences.
The script enables TouchID for sudo, which means authentication happens with a fingerprint instead of a password prompt. It enables the screensaver password immediately rather than after the idle delay. It turns on the application firewall. It adds a `Found this computer?` message to the login screen so a lost machine can be traced.
The two with real consequences are FileVault and Xcode. Full-disk encryption is enabled and the FileVault recovery key is saved to the Desktop, which is a deliberate convenience that trades some of FileVault's benefit for a machine you can actually recover. The Xcode Command Line Tools are installed, and the Xcode license is accepted so that a compiler never stops to prompt.
After that comes software: Homebrew, then the latest macOS updates. Everything is described as idempotent, so re-running the script is safe.
The out-of-scope list is the actual design document
Most bootstrap scripts have an implicit policy. Strap writes its policy down, and the list is more informative than the feature list.
It will not enable any network services by default, on the reasoning that you should enable them when you need them. It will not install Homebrew formulae for an entire organisation by default, and the reasoning is good: formulae belong in Brewfiles inside project repositories, so a whole-company list becomes a thing nobody dares remove. It will not let you opt out of macOS updates. It will not disable security features, since the ones it enables are described as a minimal set of best practices.
The last item is the most revealing. It will not add a phone number to the security screen message, explicitly to avoid prompting users for personal information during installation. That is a small decision, but it is the kind of thing that tells you the author thought about the person running the script, not just the machine.
The combination is coherent: it does the setup an individual developer needs, it does not impose a fleet policy on you, and it does not ask for personal data. If any of the defaults is wrong for your environment, you are better off editing them yourself than arguing with a script that has taken a position.
Customization lives in your own repositories
The personalization model is worth understanding before you run anything, because it determines whether strap stays a 4,000-line script or becomes your configuration system.
If you have a repository at `https://github.com/username/dotfiles`, strap will install it. If the files in it are executable, it runs `script/setup` to configure the dotfiles, and then `script/strap-after-setup` after everything else is done. That second hook name is deliberate: it runs last, so your dotfiles can assume Homebrew exists, the command line tools are installed and the machine is otherwise ready.
Software goes through the same mechanism. Strap looks for a `Brewfile` in `https://github.com/username/homebrew-brewfile`, or for a `.Brewfile` in your home directory. Either one works, and the local file is the escape hatch for when you do not want a remote repository involved.
Git identity and GitHub access are configured from optional local GitHub CLI login or from environment variables. That last part matters for provisioning: a script that can read credentials from the environment can run unattended, and a script that requires an interactive login cannot.
The net effect is that most of the work strap does for you is delegated to two repositories you own. That is a much better maintenance story than forking the script.
Running it locally, and every flag worth knowing
The documented path is to open strap.mikemcquaid.com in a browser, which is a hosted web application that hands you the script. To run the script from a clone instead:
git clone https://github.com/MikeMcQuaid/strap
cd strap
bash bin/strap.shThe README notes that `bash bin/strap.sh --debug` produces more debugging output, and given how many things the script touches, that is the variant you want on first run.
To run the web application locally, there is a separate pair of commands:
git clone https://github.com/MikeMcQuaid/strap
cd strap
./script/bootstrap
./script/serverThe environment variables are the part to read carefully. `STRAP_GIT_NAME` and `STRAP_GIT_EMAIL` override Git's identity and the values written into the login-screen recovery message, and empty values are ignored rather than treated as a clear. `STRAP_GITHUB_USER` overrides the username used to find the dotfiles and Brewfile repositories. `GH_TOKEN` or `GITHUB_TOKEN` supply GitHub CLI credentials, with `GH_TOKEN` taking precedence, and the default is an existing local login.
Two of the flags matter for automation. `STRAP_NONINTERACTIVE=1`, `CI=1` or `--non-interactive` runs without interactive prompts, and it is automatic when there is no TTY. Crucially, that mode never starts a GitHub login and it requires sudo access without a password prompt, so a machine without passwordless sudo will fail rather than hang. And `--help` prints usage without changing the machine, which is a small courtesy that tells you the script is careful.
A website, a shell script and a container image in one repository
The tree shows something more layered than a single script, and GitHub reporting the language as Shell is only half the picture.
There is `bin/` for the script, `script/` for the build and server commands, `tests/` for tests, and `config/` plus `css/`, `images/`, `index.html` and `_config.yml` for the website. That last group is a Jekyll site, which is consistent with `Gemfile`, `Gemfile.lock` and `.ruby-version` all being present. So the repository contains both the bootstrap script and the web application that serves it, and the two are versioned together.
Two files in the tree are worth noting because they explain the delivery model. `strap.sh.txt` is the script itself as plain text, and `strap.sh.html` is a page that renders it with syntax highlighting. That is how a script gets served from a website without being executable there.
There is also a `Dockerfile`, and strap is published as an image on Docker Hub and GitHub Packages. The container serves the built Jekyll site rather than running the bootstrap, and it enforces that ordering:
FROM busybox:1.37.0-musl
WORKDIR /srv
COPY . ./
RUN test -f _site/index.html || \
{ echo "Run script/build before building the Docker image." >&2; exit 1; }The build fails if `_site/index.html` is missing, which means the site must be built before the image is built. The rest of the file switches to an unprivileged user, declares a health check against the local port, and serves `_site` through BusyBox httpd with a config file from `config/`. The repository's own `Brewfile` sits at the root as well, so the script's own dependencies are managed the same way it asks you to manage yours.
Where the documentation stops
The README describes strap's own configuration thoroughly: every environment variable, every flag, the feature list, the out-of-scope list, the dotfiles convention, the Brewfile locations, non-interactive mode and the container images. For a shell script, that is close to complete documentation of its interface.
What it does not cover is what happens when something fails. There is no troubleshooting section, no list of common failure modes, and no guidance on what to do if a FileVault key was written to the Desktop on a machine you did not intend to encrypt, or if the dotfiles hook exits non-zero and leaves the machine half-configured. In practice you would fall back on `--debug` output and the linked 2016 post.
The status line says stable and in active development, and the repository's last push was 2026-09-25, which is consistent with that claim. There are no GitHub releases, so there is no version history to consult and the script is effectively always at whatever `main` currently holds. For a script that changes system security settings, that is a genuine consideration: you get the fixes, and you get the surprises.
The license is MIT, consistent between the README's statement and `LICENSE.txt` in the tree. One small licensing detail is called out honestly in the README itself: the `images/` directory vendors fork-me-on-GitHub ribbon graphics from another author, which are separately MIT licensed.
Editorial conclusion
strap is unusually honest for a bootstrap script, mostly because its README contains an out-of-scope section that says what it will not install and why. That list is the strongest argument for it: a machine setup script that refuses to enable network services or disable security features is easier to hand to a new hire than one that quietly changes everything. The tradeoff is that it configures security settings you may not want on a laptop that travels, notably TouchID for sudo, FileVault with the recovery key written to the Desktop, and a login window message. Read those four lines before you run it on hardware you care about. The `--non-interactive` mode is there for fleet provisioning, and the dotfiles and Brewfile hooks mean most customization happens in your own repositories rather than in the script, which is the right split. Start with `bash bin/strap.sh --debug` on a machine you can rebuild.
Frequently asked questions
What is strap used for?
It bootstraps a macOS machine for development: it installs the Xcode Command Line Tools, accepts the Xcode license, installs Homebrew and the latest macOS updates, and enables a set of security settings including the firewall, full-disk encryption and TouchID for sudo. It was written to replace Boxen inside GitHub.
How do I customize what strap installs?
Two repositories of your own. A `dotfiles` repository at your GitHub username is cloned, and if it is executable its `script/setup` runs, followed by `script/strap-after-setup` once everything else is done. Software comes from a `Brewfile` in a `homebrew-brewfile` repository or from a `.Brewfile` in your home directory.
Can strap run without any manual input?
Yes. Setting `STRAP_NONINTERACTIVE=1`, `CI=1` or passing `--non-interactive` runs it without prompts, and it happens automatically when there is no TTY. That mode never starts a GitHub login and needs sudo access without a password prompt, so it fails rather than hanging on a machine without passwordless sudo.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/mikemcquaid-strap)