Skip to main content
WritingVideosSpeakingCodeAbout

Shipping & Tooling

Setting Up A Laptop That Isn't Mine

A new role came with a MacBook that belongs to someone else, so I started my dotfiles again, gave the work its own Obsidian vault, and let mise choose between Homebrew's PHP builds.

Nov 20268 min read

On 16 November I start as SerpApi’s PHP developer advocate, and I’ve got a MacBook Pro to do that work on, a 14-inch M5 Max with 32GB of RAM and a 2TB drive. It belongs to SerpApi, it’s only for SerpApi work, and when the engagement finishes I’ll reset it. My Framework Desktop stays my main machine and nothing about it changes.

Knowing a machine has an end date makes you set it up differently. Normally with a new computer you’re trying to get everything across as quickly as you can, but with this one I kept asking how little I could get away with bringing, and it turned out to be a lot less than I expected.

Starting the dotfiles again

The first job was to find some dotfiles to reuse, and there wasn’t really anything to find. I have a private repo on GitHub built around GNU Stow, but its README still calls it the Fedora edition, it was last touched in June, and the end of its history is a script committing “automated dotfile sync update” over and over again. After Fedora came NixOS, where everything lived in a flake that went away with the install, and now I’m on Omarchy, where my config isn’t versioned at all, so after three setups I had nothing I could actually clone onto a Mac.

I started a new repo instead, and because it only ever has to serve one machine, I dropped Stow as well:

dotfiles/
├── Brewfile
├── bootstrap.sh
├── link.sh
└── home/
├── .zshenv
└── .config/
├── ghostty/
├── git/
├── mise/
├── nvim/
├── tmux/
└── zsh/

link.sh walks home/ and symlinks each file into place. If something’s already sitting there it gets moved aside rather than overwritten, and you can run it as many times as you like. That’s about twenty lines of bash, which is a dependency I’m happy to carry on a machine with an end date.

The config itself came across from the Framework, with the Omarchy parts taken out. Most of that was uneventful, although my tmux bindings lean heavily on Alt, so Ghostty needed macos-option-as-alt = true before any of them would do anything. My name and email for commits don’t live in the repo either. The bootstrap asks for them and writes them to a local file that git includes, so neither of them ends up committed.

Should mise do all of it?

I use mise for runtimes on the Framework, so that’s where this was always going to start, but PHP is the one tool on this machine I can’t be casual about. I need to be able to test against more than one version, and the first draft of the bootstrap, which I was writing with Claude Code, had Homebrew installing the builds and a little shell function called phpv to switch between them for the current shell.

I wasn’t sure about that, so I asked whether I should stick to mise completely. When we looked into it, mise compiles PHP from source, and on macOS that needs about twenty Homebrew packages before it can even start. So going all in on mise still leaves you with Homebrew, and a compile on top of it. The phpv function had the opposite problem, because it was one more thing for me to maintain, and I’d have to remember to run it.

We ended up using both, with each one doing the part it’s actually good at. Homebrew provides the builds, and mise link registers them, so mise thinks of them as installed versions:

Terminal window
mise link --force php@8.3 "$(brew --prefix php@8.3)"
mise link --force php@8.4 "$(brew --prefix php@8.4)"
mise link --force php@8.5 "$(brew --prefix php)"
mise install

The order matters here. Those links have to exist before mise install runs, otherwise it goes off and tries to compile PHP from source. After that, a repo just pins what it wants, in the same way it would for anything else, and the version follows you as you move between directories:

[tools]
php = "8.3"

If you need PHP built with your own configure flags then compiling is exactly what you want, and mise is a good way to do it. For everyone else on a Mac who just needs a few versions side by side, this is what I’d set up.

The taps I didn’t need

The first Brewfile pulled PHP from shivammathur/php and the Symfony CLI from symfony-cli/tap, and when I ran it on the Mac, I got stuck on trusting them. Homebrew 6 made third-party taps opt-in, because a tap is Ruby code that runs on your machine, and that’s a pretty reasonable thing to be asked about on a laptop that belongs to someone else.

When I mentioned it, we checked, and neither tap was needed. Homebrew’s own repository has prebuilt php@8.3, php@8.4 and symfony-cli, so the fix was deleting two lines and shortening three others. Shivam’s tap is a great project and it’s the right answer when you need a version Homebrew has already dropped, but that isn’t where I am, and the only reason anybody looked again was that Homebrew stopped and asked.

A smaller brain

I’ve written before about how my brain works, the Obsidian vault that acts as the system of record for everything I do, and I wanted something similar for this work, just focused entirely on it.

It couldn’t be the same vault, though. Since I moved my business into it, that vault has my clients, my hours and my invoices in it, and none of that belongs on a machine I don’t own. Deleting the folder from a clone wouldn’t have helped either, because all of it is still sitting in the git history. So the new vault is a new repo with its own history, private on my own GitHub account.

It has the same shape as the original, the same note format and the same commit rules for agents, with a lot taken away. There’s no videos/, talks/, brand/ or business/, and I added a community/ section for events and maintainers, which is a big part of the role. The boundary works in both directions as well: my other clients and personal projects stay out of it, and because the repo is mine, SerpApi’s customer data, keys and internal documents stay out of it too.

One small thing I’d got wrong the first time around is that the notes in my main vault use absolute paths, so /home/steve turns up in nearly seventy files. On a Mac that’s a different path entirely, so the new vault’s notes use paths relative to the vault, which I should probably have done from the beginning.

We actually built it first with a scrubbed copy of all my existing SerpApi research and drafts, and it took a fair bit of care to get my rates and other clients out of them. Then I decided against the whole thing, and it starts as an almost empty skeleton of ten notes that’ll build its own research as the work needs it, while everything I’ve already written stays on the Framework.

The reason is that this vault is the brain of everything I do on that machine, all of it driven by an agent with its own memory, and I didn’t want anything influencing the decisions I was making when I was only just getting started. Just because I chose PHP 8.5 or PostgreSQL on previous projects doesn’t mean I’m always going to want to, especially in work that’s specific to SerpApi, so I’d rather the agent had none of that to lean on.

Running it for real

The Framework can’t run macOS, so the only test possible before the laptop was involved was Claude faking one. It put stub versions of uname, brew and mise on the PATH, so the script believed it was on a Mac, and ran the whole bootstrap in a temporary home directory, twice, to prove that a second run wouldn’t ask for anything again. That tells you the logic is right, but it can’t tell you whether Homebrew will actually do what you asked, which is exactly how the tap problem got through.

On the real machine, once the taps were gone, the bootstrap finished without errors. Then came the checks that a clean exit can’t give you: php -v showing 8.5 in one directory and 8.3 in another, a signed commit that verifies, Ghostty opening with its theme and no config error, and tmux responding to Option, and they all passed.

All of this took about a day, and most of it was deciding things, because once you start from what shouldn’t be on a machine rather than what you’d like on it, there just isn’t that much left to set up. If someone hands you a work laptop, I’d start there too, before you go looking for your old dotfiles.

Related

More in Shipping & Tooling

All posts →

Same subject

In other formats

All of Shipping & Tooling →