Chapter 7 of 14

The Terminal Follows the Project

Your sites are served by the right PHP. Your terminal is not: it still runs whatever is first on your PATH, which is how php artisan ends up on a different version from the site it belongs to. This chapter fixes that, and it is the point where the old tools can go.

The problem

There are two PHPs in your life and they are not the same one. The server PHP runs your site; chapter 5 made that per-project. The terminal PHP runs php artisan migrate, composer install, vendor/bin/pest — and it is whatever your PATH finds first, globally, regardless of which directory you are standing in.

The failure is quiet and confusing. A site served on 8.1 whose migrations run on 8.5 will mostly work, until a dependency resolves differently, or a composer install writes a lock file for the wrong platform, or a test passes locally and fails in CI. The cause is never where the symptom is.

Shims

grove path install
✓ Installed shims for php, composer, cpx, node, npm, npx, laravel.
✓ provisioned toolchain: PHP 8.5 CLI, Composer, cpx, Node 22

    echo 'export PATH="$HOME/Library/Application Support/Grove/shims:$PATH"' >> ~/.zshrc

Add the line, restart your shell, and the commands you type are Grove's. A shim is a tiny program that asks one question before it runs anything: which project am I in, and what does it pin? Then it executes that version.

cd ~/Code/legacy-client && php -v      # PHP 8.1
cd ~/Code/freddy         && php -v      # PHP 8.5

No switching, no ceremony, no remembering. The same mechanism covers composer, node, npm, npx and the laravel installer, so an npm install in a project pinned to Node 20 uses Node 20.

cpx, while we are here

Grove also installs cpx, a Composer package executor — npx for PHP. It runs a Composer package without installing it into your project:

cpx friendsofphp/php-cs-fixer fix src/

Useful for the tools you want occasionally and do not want in composer.json forever, where they will constrain your dependency resolution for years for the sake of something you ran twice.

Removing Herd and Valet

This is the moment. Everything the old tool did is now done: DNS, the proxy, certificates, PHP versions, the database, the terminal toolchain. Three chapters of evidence that the replacement works, rather than a leap.

  1. Copy the databases first if you have not — chapter 6, with the source untouched.
  2. Uninstall the old tool its own way.
  3. Run sudo grove install once more. Uninstalling Herd or Valet removes resolver files and trust-store entries on the way out, including, sometimes, ones that were not theirs. This re-asserts Grove's resolver and CA. If .test stops resolving after you remove something, this is the command.
  4. grove doctor to confirm the ports, the resolver and the CA are all where they should be.
You can run both for a week. Nothing in this course requires the old tool to be gone; the two can coexist as long as they are not fighting over ports 80, 443 and 3306. Move when you stop reaching for the old one, not before.

What you learned

  • Two PHPs: the one serving the site and the one in your terminal. Only the first was per-project until now.
  • Shims ask which project you are in before running php, composer, node, npm, npx or laravel.
  • cpx runs a Composer package without installing it, keeping occasional tools out of composer.json forever.
  • Remove the old tool after the evidence, not before — and copy the databases first.
  • Run sudo grove install after uninstalling Herd or Valet. They take resolver and trust entries with them.
Next: in Chapter 8 the processes a project needs while you work — queue workers, Vite, schedulers — started and supervised by the same thing that serves the site.