The problem it solves
If your PHP toolchain lives inside a container, every mainstream hook runner makes you write a wrapper script to shell into it. Husky and lint-staged assume Node on the host. lefthook is a single binary, but it still runs tools where it happens to be, not where they are installed.
forge routes each tool to the container for you. Set backend = "ddev" (or a
container name), and it detects the running environment and executes the tool
there. If the container is not up, it falls back to the host rather than failing
the commit.
Why it is on this page
This is the project where the test suite matters most, because a hook runner that misbehaves blocks every commit on the team. 297 test functions across 22 test files cover config parsing, staged-file filtering, container detection, and the commit-message policy engine.
The design constraints were deliberate:
- A single static binary. A tool that enforces quality gates cannot itself
require a package manager to install.
go install, Homebrew tap, or a curl installer. - TOML config, not shell. The config file is data, so it can be validated and diffed, rather than a script that can do anything.
- Graceful degradation. Container missing, tool missing, no staged files - each has a defined behavior instead of an unhandled error.
What is inside
- Commit-message policy (conventional commits) built into the runner, so commitlint and its Node dependency are not needed
- Monorepo workspace mode, staged-file filtering, parallel execution
- A migration path from Husky that reads the existing config
- Documentation site, changelog automation via release-please, and a demo recorded with VHS
