[{"data":1,"prerenderedAt":129},["ShallowReactive",2],{"project:forge":3},{"id":4,"title":5,"body":6,"demo":92,"description":93,"docs":94,"draft":95,"extension":96,"highlights":97,"image":107,"language":108,"meta":109,"navigation":110,"order":111,"path":112,"repo":113,"seo":114,"site":92,"stack":115,"stem":122,"tagline":123,"tags":124,"__hash__":128},"projects\u002Fprojects\u002Fforge.md","forge",{"type":7,"value":8,"toc":85},"minimark",[9,14,18,26,30,38,41,67,71],[10,11,13],"h2",{"id":12},"the-problem-it-solves","The problem it solves",[15,16,17],"p",{},"If your PHP toolchain lives inside a container, every mainstream hook runner\nmakes you write a wrapper script to shell into it. Husky and lint-staged assume\nNode on the host. lefthook is a single binary, but it still runs tools where it\nhappens to be, not where they are installed.",[15,19,20,21,25],{},"forge routes each tool to the container for you. Set ",[22,23,24],"code",{},"backend = \"ddev\""," (or a\ncontainer name), and it detects the running environment and executes the tool\nthere. If the container is not up, it falls back to the host rather than failing\nthe commit.",[10,27,29],{"id":28},"why-it-is-on-this-page","Why it is on this page",[15,31,32,33,37],{},"This is the project where the test suite matters most, because a hook runner\nthat misbehaves blocks every commit on the team. ",[34,35,36],"strong",{},"297 test functions across 22\ntest files"," cover config parsing, staged-file filtering, container detection,\nand the commit-message policy engine.",[15,39,40],{},"The design constraints were deliberate:",[42,43,44,55,61],"ul",{},[45,46,47,50,51,54],"li",{},[34,48,49],{},"A single static binary."," A tool that enforces quality gates cannot itself\nrequire a package manager to install. ",[22,52,53],{},"go install",", Homebrew tap, or a curl\ninstaller.",[45,56,57,60],{},[34,58,59],{},"TOML config, not shell."," The config file is data, so it can be validated\nand diffed, rather than a script that can do anything.",[45,62,63,66],{},[34,64,65],{},"Graceful degradation."," Container missing, tool missing, no staged files -\neach has a defined behavior instead of an unhandled error.",[10,68,70],{"id":69},"what-is-inside","What is inside",[42,72,73,76,79,82],{},[45,74,75],{},"Commit-message policy (conventional commits) built into the runner, so\ncommitlint and its Node dependency are not needed",[45,77,78],{},"Monorepo workspace mode, staged-file filtering, parallel execution",[45,80,81],{},"A migration path from Husky that reads the existing config",[45,83,84],{},"Documentation site, changelog automation via release-please, and a demo\nrecorded with VHS",{"title":86,"searchDepth":87,"depth":87,"links":88},"",2,[89,90,91],{"id":12,"depth":87,"text":13},{"id":28,"depth":87,"text":29},{"id":69,"depth":87,"text":70},null,"A git hook runner that executes your linters and formatters inside DDEV or Docker, where the tools actually live. One Go binary, no Node.js, no wrapper scripts.","https:\u002F\u002Fterrorsquad.github.io\u002Fforge\u002F",false,"md",[98,101,104],{"value":99,"label":100},"297","Go test functions across 22 test files",{"value":102,"label":103},"1","static binary, zero runtime dependencies",{"value":105,"label":106},"5","CI workflows, including an install smoke test","\u002Fprojects\u002Fforge.webp","Go",{},true,1,"\u002Fprojects\u002Fforge","https:\u002F\u002Fgithub.com\u002FTerrorSquad\u002Fforge",{"title":5,"description":93},[108,116,117,118,119,120,121],"Cobra","TOML","DDEV","Docker","GitHub Actions","Homebrew","projects\u002Fforge","The git hook runner for containerized dev",[125,126,108,127],"Developer Tooling","CLI","Testing","C3w1BgwjmaLfFBPKqedb_gXMWBHkI7slEWfyWq5w7Zw",1785847686085]