Install on macOS
The installer brings grim and the tools around it, but not the shared plumbing every project leans on. That is a second command, and its last line says "ready" whatever happened. So the procedure ends with the one command that tells the truth about the machine.
Before you start
Docker has to be installed and running. The installer does not bring it, and everything after the installer talks to it. Docker Desktop and OrbStack both do, as long as docker is on your PATH.
PHP you do not need, nor Composer. grim is a PHP program that runs on your machine, not in a container, and it brings its own PHP: one self-contained PHP 8.5 binary in ~/.grim/runtime, pinned by grim's release and checked against its sha256, off your PATH. The grim command is a small script that runs grim on that PHP. A php you already have is neither used nor touched, and every project runs its own PHP, and Composer, in Docker.
$ docker info --format '{{.ServerVersion}}'Homebrew is not required, but have it. With Homebrew the installer adds mkcert, MariaDB and Node by itself. Without it, MariaDB is left to you.
You will be asked for a classic GitHub token. The installer prints a link with the scopes already selected. A fine-grained token is accepted by GitHub and still cannot pull images.
The ritual, in order
Five steps. The first and the third change the machine, the other three only look.
Run the installer
One line downloads grim and its PHP into
~/.grim, puts thegrimcommand into~/.local/binand fills in what is missing around it: mkcert and its certificate authority, MariaDB, Node and pnpm. Expect the macOS password prompt once, when the authority goes into your keychain.It starts with a checklist of the three parts you can leave out: MariaDB, Node.js + pnpm and mkcert. All are ticked; arrows move, space unticks, Enter goes on. Whatever you leave out is listed at the end with what that means.
Components to set up (arrows move, space toggles, Enter confirms): > [x] MariaDB [x] Node.js + pnpm [x] mkcertWithout a terminal (CI, a provisioning script,
GRIM_NONINTERACTIVE=1) there is no checklist and everything is installed. The options--skip-mariadb,--skip-nodeand--skip-mkcertanswer the checklist up front; they go afterbash -s --, and each has an environment twin,GRIM_SKIP_MARIADB=1and so on.--dry-runshows the choice and stops.A database of your own elsewhere, or none yet? Leave MariaDB out. Projects still install without a database:
grim installskips migrations and the admin, says so in yellow, and a secondgrim installfinishes them once.envnames a login that works.$ curl -sS https://grim.grimoiry.com/install.sh | bash -s -- --skip-mariadb$ curl -sS https://grim.grimoiry.com/install.sh | bash GRIM CLI Installer … Downloading grim's own PHP 8.5.8 (macos-aarch64, one self-contained binary, ~15 MB)... PHP runtime 8.5.8 installed to ~/.grim/runtime … Generate the token on GitHub, then paste it here (it stays visible — keep it out of screenshots). Token: … Next steps: grim doctor Check system dependenciesGreen lines are things that were found or installed. Yellow lines are things the installer could not do, each with the command to run yourself. It goes on past them, so read them now. The pasted token stays visible on screen, so keep it off a shared screen and out of screenshots. The token is saved to
~/.grim/config.json, and the installer finishes by runninggrim auth:loginwith it, which writes it to Composer's globalauth.jsonand logs Docker in toghcr.io.Open a fresh terminal
The
grimcommand lives in~/.local/bin, grim itself and its PHP in~/.grim. When~/.local/binwas not on yourPATH, the installer added it to the profile of your login shell —~/.zshrcfor zsh,~/.bash_profilefor bash — in a block marked# >>> grim-cli PATH, and said so in a yellow line at the end. It cannot change the shell it was piped into, so in that onegrimis stillcommand not found. Open a new terminal and ask who grim thinks you are.$ grim auth:whoamiAuthenticated asand your GitHub name mean the token arrived.command not foundin a new terminal means your shell reads a different profile than the one named at the end of the install; copy the marked block there.Prepare the machine
Every project answers at
https://<name>.test. One Traefik routes all of them and one rule sends.testto your own machine.grim setupputs both in place, once per machine. It asks forsudoonce, to write/etc/resolver/test.$ grim setup Setting up local dev environment... Creating traefik-public network... OK Checking mkcert... installed Installing mkcert CA... OK SSL certs will be generated per-project on grim up Setting up Traefik... running Setting up *.test DNS... needs sudo Creating /etc/resolver/test (routes *.test to 127.0.0.1) DNS configured Local dev environment ready.Read the indented lines, not the last one.
Local dev environment ready.is printed, with exit code 0, even when a line above it saysfailed. The reason is on the line under the failed one.Laravel Herd's nginx holds ports 80 and 443. While it does, the Traefik line says
failedand names Herd. Rungrim setup --stop-herdto have setup stop it, orherd stopyourself.grim upbehaves the same later, with the same flag. Nothing stops Herd without being asked. Your Herd sites are down until you start Herd again, and then grim's are.Check that a .test name resolves
The resolver file sends every
.testlookup to127.0.0.1. grim starts nothing that answers DNS there. On a Mac that has Herd, Valet or dnsmasq, something already does. On a clean Mac, nothing does. Find out now, not in the browser.$ dscacheutil -q host -a name shop.test name: shop.test ip_address: 127.0.0.1An address means something on the Mac answers for
.test. No output means nothing does. That is fine too:grim create-projectandgrim upthen add the project's line to/etc/hoststhemselves, andsudoasks for your password when they do.Ask the doctor
grim doctorchecks the tools, the Docker daemon, the ports, the database login and the token, and gives one verdict.$ grim doctor … Docker daemon ✓ running Traefik ports ✓ 80, 443 bound Composer ✓ 2.8.4 MySQL/MariaDB ✓ 11.4.2 (root@127.0.0.1, no password) … GitHub auth ✓ (anna) grim.json - (not found — not in a GRIM project directory) All checks passed!A
-is something absent, not something wrong. Outside a project the two manifest lines are always-. TheMySQL/MariaDBline matters more than its mark suggests: a-there does not fail the run, but the first project will get no database. Settle it before you go on.
What you have now
~/.local/bin/grim, grim.phar the tool, updated in place by grim self-update
~/.grim/config.json your token and the telemetry choice
~/.grim/install.log what the installer did, for when you ask for help
~/.grim/traefik/ the shared proxy and, later, one certificate per project
/etc/resolver/test .test goes to 127.0.0.1There is also a MariaDB on the machine, outside Docker, that accepts root without a password so the containers can reach it. Keep port 3306 closed to any network you do not trust.
No project yet. That is the next recipe, Create a project. To take a newer grim later, run grim self-update.
When it does not work
“The PHP runtime download does not match its pin”
The PHP that grim's release names came down different from what the release pinned, so nothing was installed. A proxy that rewrites downloads does that, and so would a changed file at dl.static-php.dev. Run the installer again on another network; if it says the same, report it, because every install is affected until a new grim pins the new file. A download that fails outright (no network to dl.static-php.dev) says Failed to download the PHP runtime, and running the installer again is all it takes. It is safe to repeat: everything it finds in place is left alone.
“GitHub token is required. Installation cannot continue without it.”
The prompt offers Press Enter to skip, and skipping ends the install with this message. Every package is private, so there is no install without a token. Create the classic token from the printed link and run the installer again.
“MariaDB/MySQL not reachable on 127.0.0.1:3306 and Homebrew is not installed.”
Without Homebrew the installer has no way to install a database server. Install Homebrew and run the installer again, or point any MySQL or MariaDB you already run at port 3306 with a passwordless root. To finish the install first and sort the database later, run it with --skip-mariadb. The check doctor makes is this one:
$ mysql -u root -h 127.0.0.1 -e "SELECT 1"Doctor runs the mysql client from your machine. A server without the client on your PATH still shows as not reachable.
A .test name does not resolve
The resolver rule is in place, nothing on the Mac answers it, and the hosts line is missing: the sudo prompt was declined, or the run had no terminal. Add the project's names to /etc/hosts, which is read first, or run grim up again in a terminal.
$ echo '127.0.0.1 shop.test mail.shop.test' | sudo tee -a /etc/hosts“Port(s) 80, 443 are held by a non-Docker process.”
It appears under Setting up Traefik... failed. A local nginx or Apache is listening. Stop it, run grim setup again, and read the Traefik line.
The keychain prompt was dismissed
mkcert -install failed. Re-run manually later: mkcert -install means the authority was never trusted, and browsers will warn on every .test page. Run mkcert -install, answer the prompt, and restart the browser.
Next recipe
Install on Windows
Run one installer in PowerShell, let it seed the Windows certificate authority and hand the rest to the WSL2 distro, then keep the distro's hosts file from being rewritten and finish on a clean grim doctor.
Read itSpells used here
grim setup
Prepare the machine
Put the shared pieces of local development in place, once per machine: the Traefik proxy, a trusted local certificate authority and .test name resolution.
grim doctor
Check your circle
Check every tool grim expects on this machine, and the project you are standing in, and say what to do about what is missing.
grim auth:login
Log grim in to GitHub
Give grim a GitHub token, from your gh login or a personal access token, and hand the same token to Composer and Docker.
grim auth:whoami
See who grim acts as
Show the GitHub user and the masked token grim holds on this machine.
grim self-update
Update grim itself
Replace the grim phar with the newest release. Projects are not touched.