Hafiq Iqmal hat diese Woche einen Praxisbericht zu CPX v2 veröffentlicht, und in seinen Testergebnissen versteckt sich der Satz, der neu justieren sollte, wie wir über dieses Tool reden: Als er cpx pint in einer frischen Laravel-13-Demo laufen ließ, benutzte CPX die Pint-Version, die dieses Projekt gepinnt hatte. Nicht das neueste Release, nicht irgendeinen global gecachten Build – die Version, auf die sich das Team laut Lockfile geeinigt hat. Meine Position: Dieses eine Verhalten ist mehr wert als alles, was CPX v1 zusammengenommen konnte, und der alte Elevator-Pitch ist inzwischen aktiv irreführend.

Der alte Pitch lautete, fürs Protokoll: CPX ist für Composer, was npx für npm ist. Das war ein guter Pitch, gerade weil er null Erklärung brauchte. Aber er rahmte CPX auch als Convenience-Wrapper: ein Tool einmal ausführen, composer.json nicht zumüllen, weitermachen. Convenience-Wrapper sind nett. Sie sind aber auch genau die Sorte Ding, die deinen Workflow leise verrotten lässt, denn 'einmal ausführen, ohne es zu installieren' heißt in der Regel 'die Version ausführen, die heute zufällig aufgelöst wurde'.

Wer schon mal einen Formatierungskrieg debuggt hat, kennt das Fehlermuster. Dein lokaler Einmal-Lauf von Pint formatiert vierzig Dateien um. Die CI, die die gepinnte Version des Projekts nutzt, formatiert sie wieder zurück. Niemand hat Code geändert, aber der Diff rotiert, der Pre-Commit-Hook streitet mit der Pipeline, und irgendwann pinnt jemand das Tool aus purer Erschöpfung überall fest – was den ganzen Sinn eines ephemeren Runners zunichtemacht. Ein Einmal-Executor, der Projekt-Pins ignoriert, spart dir keine Installation; er verschiebt nur einen Merge-Konflikt nach hinten.

Das zweite v2-Verhalten, das Hafiq getestet hat, ist cpx exec, das Laravel bootet, bevor es eine Wegwerf-PHP-Datei ausführt. Das kratzt an einem echten Juckreiz: das Zehn-Zeilen-Skript, das den Container und deine Eloquent-Models braucht, aber es absolut nicht verdient hat, ein registrierter Artisan-Command zu werden – mit Signatur, Beschreibung und einem Platz in deinem Console-Kernel für alle Ewigkeit. Tinker deckt den interaktiven Fall ab; das hier deckt den Fall 'ich habe eine Datei, führ sie einfach mit geladener App aus' ab. Eine kleine Sache, die eine wirklich nervige Zeremonie beseitigt.

Nun zum ehrlichen Gegenargument, denn es ist ein starkes: implizites Kontextbewusstsein ist Magie, und Magie schneidet in beide Richtungen. Wenn sich cpx pint unterschiedlich verhält, je nachdem, in welchem Verzeichnis du gerade stehst, dann ist derselbe Befehl nicht mehr derselbe Befehl. Ein Teamkollege, der Anweisungen in einen Chat kopiert, kann nicht wissen, was dein Aufruf tatsächlich tun wird. Es gibt einen Grund, warum viele Entwickler vendor/bin/pint bevorzugen – gerade weil es langweilig und eindeutig ist: Der Pfad selbst dokumentiert, woher die Binary kommt.

Ich lande trotzdem auf der projektbewussten Seite, und zwar deshalb: Die Mehrdeutigkeit war schon vorher da. Die Wahl war nie 'explizit versus implizit'. Sie war 'implizit falsch versus implizit richtig'. Ein Runner im v1-Stil, der sich stillschweigend eine beliebige Version greift, ist genauso magisch wie einer, der dein Lockfile liest – er löst die Mehrdeutigkeit nur gegen dein Projekt auf statt für es. Standardmäßig das zu nehmen, was das Repository gepinnt hat, ist das am wenigsten überraschende Verhalten überhaupt, weil es dem entspricht, was CI, deine Kollegen und dein Deploy ohnehin schon tun. Wenn ich eine bestimmte andere Version will, sollte das der Fall sein, in dem ich es explizit sagen muss.

Es zählt auch, dass das jetzt ein Rewrite in Laravels Besitz ist und kein Side-Project mehr. Nicht weil ein Logo Code besser macht, sondern weil Workflow-Tools mit ihrer Wartung stehen und fallen: Sie sitzen im Pfad jedes Entwicklers im Team, und ein verwaister Executor ist schlimmer als gar keiner. Die Betreuung durch eine Organisation mit bezahltem Team und Release-Rhythmus verändert die Rechnung, wenn es darum geht, so etwas in gemeinsame Tooling-Docs, Makefiles und Onboarding-Guides aufzunehmen – die Orte, an denen du wirklich nicht schreiben willst: 'Installier erst mal dieses Ding, das irgendein Typ nicht mehr aktualisiert.'

Und hier würde ich wirklich gern von dir hören, denn meine Stichprobe sind nur meine eigenen Projekte: Würdest du einen kontextbewussten Runner wie cpx pint in deine CI und deine Contributor-Docs lassen, oder ziehst du die Grenze bei Scripts in composer.json und dem expliziten vendor/bin-Pfad – und falls Letzteres: Ist das eine echte Sorge um Reproduzierbarkeit oder Muskelgedächtnis aus Jahren mit Tools, die falsch geraten haben?