0.9.0: Tooling, das zu deinem Projekt passt – Rollen, Ratschen, Packs
Bei 0.9.0 geht es darum, welche Tools die Suite vorschlägt. Der Tooling-Baum ist so umgebaut, dass er Tools für dieselbe Aufgabe, andere Sprachen und deine eigenen Tools versteht. Es ist kein Breaking Release. Ein Projekt auf 0.7 oder 0.8 muss nichts tun, bevor es die Suite wieder aufruft; was dir auffallen wird, steht am Ende unter Was sich für dein Projekt ändert.
Warum sich der Tooling-Baum ändern musste
Bis 0.8 war der Tooling-Baum ein Graph aus Einführungsschritten, gebaut für PHP. Der Einsatz in echten Projekten zeigte, wo er nicht trug:
- Ein eigener Tooling-Baum war schwer zu bauen. Ein neues Tool hieß Änderungen an mehreren Stellen, manchmal am Parser selbst. Ein Projekt konnte keine eigenen Tools mitbringen, ohne die Suite zu ändern.
- Ein Tool ließ sich später nicht nachziehen. Ein Tool kam mit dem Safety Net, und ab dann war sein Knoten erledigt oder nicht. Es gab keinen Weg, es früh einzuführen und danach Schritt für Schritt anzuziehen. Genau das tut eine Ratsche: keine neuen Verstöße, die alten schrumpfen, nur in eine Richtung.
Der zweite Punkt führte zu einem Widerspruch. Strukturelle Arbeit, der Track Investigation, wartet immer auf das Safety Net. Manche Ratschen ließen sich aber nur mit einem Umbau anziehen. Also wartete das Safety Net auf strukturelle Arbeit, und strukturelle Arbeit wartete auf das Safety Net.
Dazu kamen zwei kleinere Probleme:
- Tools für dieselbe Aufgabe. PHPStan oder Psalm brauchten mehrere Hilfsknoten und Sonderfälle, und Laravel Pint hatte gar keinen Platz.
- Alles, was nicht PHP ist. Auf einem Projekt in einer anderen Sprache ließ sich das Safety Net nie erfüllen, weil fast alle seine Tools PHP-Tools waren.
Rollen, Tools, Stufen und Packs
0.9.0 ersetzt den Graphen durch vier Begriffe:
- Eine Rolle ist, wofür ein Tool da ist: Static Analysis, Code Style, Testing.
- Ein Tool spielt eine oder mehrere Rollen. Es ist entweder empfohlen (wird vorgeschlagen, wenn seine Rolle leer ist) oder erkannt (zählt, wenn es da ist, wird nie vorgeschlagen).
- Eine Stufe ist ein Schritt eines Tools, etwa ein PHPStan-Level oder ein Rector-Set. Tickets werden pro Stufe angelegt, wie vorher pro Knoten, und ihre Namen bleiben gleich.
- Ein Pack ist eine Menge von Tools mit einem Satz, wann es gilt. Es gibt ein generisches Pack, ein PHP-Pack und, neu, ein Twig-Pack.
Daneben ist die Ratsche jetzt eine Eigenschaft eines Tools: die PHPStan-Baseline, die Untergrenze der Testabdeckung, die Limits von PHPMD.
Den Graphen selbst gibt es nicht mehr. Mit jeder Stufe als Knoten und jeder
Abhängigkeit als Kante wäre er zu kompliziert geworden, um ihn zu
verstehen. Jedes Pack ist jetzt eine JSON-Datei, pack.json, die die Suite
liest, und der Text zu jedem Tool steht daneben in einer Markdown-Datei.
Was das in der Praxis ändert:
- Früh einführen, später anziehen. Ein Tool kommt mit dem Safety Net; es anzuziehen ist eine spätere Stufe in Guardrails, die strukturelle Arbeit brauchen darf und das Safety Net nicht mehr aufhält. Psalm Taint Analysis ist genau aus diesem Grund nach Guardrails gewandert: Ihre Befunde können einen Umbau brauchen. PHP CS Fixer und PHPMD wurden auf dieselbe Weise in zwei Stufen geteilt (siehe unten).
- Eine besetzte Rolle wird respektiert. Ein Projekt mit Psalm hat Static Analysis besetzt und bekommt PHPStan nicht angeboten. Ein Projekt mit Laravel Pint, Easy Coding Standard oder PHP_CodeSniffer hat Code Style besetzt und bekommt PHP CS Fixer nicht angeboten.
- Du kannst genauer ablehnen. Eine Ablehnung kann eine einzelne Stufe, ein ganzes Tool oder eine ganze Rolle nennen. Ein abgelehntes Tool lässt seine Rolle für ein anderes offen.
- Ein Projekt, das nicht PHP ist, kann jetzt ein erfülltes Safety Net
aus den generischen Tools haben: einer CI-Pipeline und
.editorconfig. - Twig-Templates in einem PHP-Projekt bekommen eigene Tools: Twig-CS-Fixer für den Code Style und TwigStan für die statische Analyse. Sie stehen neben den PHP-Tools, weil eine Rolle pro Sprache besetzt wird: Ein Code-Style-Tool für Twig tritt nicht an die Stelle von einem für PHP.
Für Menschen werden aus den Packs Seiten erzeugt: Die Tooling-Übersicht listet die Rollen und Packs auf, und jedes Pack hat eine Seite mit Diagramm, zum Beispiel PHP.
Ein eigenes Pack
Ein Tool, das die Suite nicht kennt, braucht keine Änderung an der Suite
mehr. Dein Projekt kann ein eigenes Pack haben: eine pack.json mit
dem Tool und seinen Stufen und eine Markdown-Datei pro Tool, die sagt, wann
eine Stufe erfüllt ist. Nenne seinen Ordner in einem neuen, optionalen
Punkt Tooling Pack in deinem Abschnitt ## Refactoring operations,
und die Suite schlägt deine Stufen vor wie ihre eigenen.
Dein Pack kann Tools, Stufen und Rollen hinzufügen und auf Stufen der Suite warten. Es kann sie nicht umdefinieren: Ein Konflikt beendet den Tooling-Schritt des Runs mit einem Fehler, der beide Stellen nennt. Ein Tool von dir, das die Aufgabe eines Tools der Suite erledigt, steht daneben; lehne das der Suite ab, wenn dir deins lieber ist. Das Playbook hat ein durchgearbeitetes Beispiel mit Deptrac.
Das Format der pack.json beschreibt ein JSON Schema,
pack.schema.json,
das mit der Suite ausgeliefert wird. Lass die "$schema"-Zeile deiner
Datei darauf in deinen installierten Skills zeigen, dann prüft und
vervollständigt dein Editor die Datei beim Schreiben.
Beachte, dass das Pack-Format noch in Entwicklung ist und sich ändern wird. Ein eigenes Pack muss nach einem späteren Release vielleicht angepasst werden; der Changelog wird sagen, was sich ändert.
Große Projekte: PHP CS Fixer und PHPMD in zwei Stufen
Auf einem Projekt mit tausenden Dateien ist ein einziger Formatierungsdurchgang ein Merge Request, den niemand reviewen kann. Deshalb kommt PHP CS Fixer jetzt in zwei Stufen:
- Die Adoption legt eine Version des PER Coding Style fest, schlägt zusätzliche Regeln vor, die du ablehnen kannst, und nimmt so viele Regeln auf, wie ein Merge Request tragen kann. Die anderen werden mit einer Markierung abgeschaltet. Rector wartet nur auf diese erste Stufe.
- Der Rollout, eine Guardrails-Stufe, nimmt die restlichen Regeln eine nach der anderen auf, Pfad für Pfad, über eine zweite Konfigurationsdatei.
PHPMD bekommt dieselbe Teilung und verliert seine Baseline. Eine Baseline listet nur Regel, Datei und Methode, ohne Wert und ohne Grund, also bleibt eine Methode still, die schlechter wird, nachdem sie in die Baseline kam. Stattdessen wird jedes Limit einer Metrik auf den schlechtesten Wert gesetzt, den der Code heute hat, mit einem Kommentar, und gesenkt, sobald die Arbeit diesen Wert beseitigt. Die Limits selbst sind der Nachweis der Schulden. Eine gewollte Ausnahme wird am Code unterdrückt, mit ihrer Begründung daneben.
Andere Agenten, und ein Ticket als bereit markieren
- Die Suite nennt nicht mehr das Fragen-Tool von Claude Code. Sie verlangt das Multiple-Choice-Fragen-Tool des Agenten, der sie gerade ausführt, und weicht auf nummerierte Optionen im Chat aus. Damit erscheinen Fragen jetzt auch in Cursor und OpenCode richtig.
- Ein neuer, optionaler Punkt Ready after plan in deiner Tracker-Datei sagt, wie dein Projekt ein Ticket als bereit zur Umsetzung markiert, etwa mit einem Label oder einer Board-Spalte. Die Suite führt ihn direkt aus, nachdem sie einen Plan gepostet hat. Ohne den Punkt ändert sich nichts. Einen Status, wenn die Arbeit beginnt, setzt die Suite weiterhin nie.
Was sich für dein Projekt ändert
Du musst nichts tun. Was dir auffallen wird:
- Deine bestehenden Tickets und Ablehnungen bleiben gültig. Die Stufen behalten die Namen der alten Knoten.
- Der nächste Scan schlägt vielleicht Neues vor: Stufen, die er auf deinem Projekt noch nicht beurteilt hat, etwa die Rollouts von PHP CS Fixer und PHPMD, oder die Twig-Tools, wenn dein Projekt Twig nutzt.
- Einem Projekt mit Psalm, Pint, ECS oder PHP_CodeSniffer wird das konkurrierende Tool nicht mehr angeboten.
- Ein Projekt mit PHPMD-Baseline bekommt einen Merge Request, der sie durch Limits und Unterdrückungen ersetzt.
Optional, wenn du sie willst: ein Tooling Pack für deine eigenen Tools und Ready after plan für den Ablauf in deinem Tracker.
Die FAQ erklärt die Gründe, zum Beispiel warum die Suite in Rollen und Tools denkt und warum PHPMD keine Baseline hat.
Wenn du ein eigenes Pack baust oder mit dem, was 0.9 möglich macht, etwas verbesserst, würde ich mich freuen, davon in den GitHub Discussions (Show and tell) zu lesen.
Changelog 0.9.0
Die Einträge aus dem Upstream-Changelog zu 0.9.0, unverändert auf Englisch. Auch auf GitHub: Release 0.9.0.
Changelog-Einträge anzeigen
- The tooling tree is now Roles, Tools and Stages delivered in Packs: a project on Psalm is no longer offered PHPStan, a project that is not PHP can have a fulfilled Safety Net from the language-neutral tools, a rejection can name a whole tool or role, and a tool the suite learns about later is picked up on the next run.
- The tools the suite knows are now drawn for humans:
docs/tooling/lists the Roles and, per Pack, the Tools and Stages with a diagram of what requires what. The pages are generated from the Packs, and the validator now fails on a Pack that breaks its schema, is not in the fixed form, has two recommended tools for one Role, names a missing details file, or whose page is out of date. - The prose for a tool now sits beside its Pack: the generic Pack's tools, the suite's two prerequisites and the smaller PHP tools moved to
packs/<pack>/<tool>.md, without the history of how they used to be wired. The PHP Pack also knows Laravel Pint and Easy Coding Standard now: a project on either has its code style settled, and PHP CS Fixer is not proposed to it. - The last tool files (PHPStan, Psalm, Rector) moved into the PHP Pack and lost the description of how the tools used to be wired; the two tooling-tree documents are gone. Every tool now has one file beside its Pack, and the Pack pages under
docs/tooling/link to it. - A project can keep a Pack of its own for tools the suite does not know: a
pack.jsonand a file per tool, named in a new optional Tooling Pack operation of its tracker file. Its steps are proposed like the suite's own; it can add tools, steps and roles, never redefine the suite's, and a clash ends the run's tooling step with an error that names both places. A Pack now names a scope (PHP, Twig, …): tools take each other's place only within a scope, so a code-style tool for Twig no longer competes with one for PHP. See the new playbook on adding a tool of your own. - A new Pack for Twig in PHP projects: it applies when the PHP project requires
twig/twig(the file extension of the templates does not decide) and brings Twig-CS-Fixer for the Code Style of the templates and TwigStan for their Static Analysis. Both stand beside the PHP Tools and do not take their place. - PHP_CodeSniffer is now a recognized Tool for the Role Code Style: a target that runs
phpcs/phpcbfhas the Role filled, so PHP CS Fixer is no longer proposed on top of it. - The PHP Pack Stage "PHP Minimum Version" is now called "PHP Version Floor", matching its Role Runtime Floor and the terms Floor correction and Floor raise; its slug
php-minimal-versionis unchanged. - Psalm Taint Analysis is now a Guardrails Stage instead of a Safety Net one: its findings can need a restructuring to fix, and that restructuring waits for the Safety Net, so the Stage no longer holds the Safety Net back and no longer has to be skipped to pass it.
- Twig-CS-Fixer is now a Guardrails Stage instead of a Safety Net one: a style pass over Twig templates no longer holds the Safety Net, and with it every PHP Guardrails Stage, back. TwigStan still waits for it.
- In the PHP Pack diagram, the Static Analysis Role now sits inside the Safety Net group instead of outside it.
- PHP CS Fixer now comes in two Stages, so a project with thousands of files gets its code style in merge requests a person can review. The adoption (
php-cs-fixer-adoption, renamed fromphp-cs-fixer) pins a PER Coding Style version, proposes a list of extra rules you may decline, checks the project's lowest PHP version, and takes in as many rules as one merge request can carry; it alone releases Rector. The new Guardrails Stagephp-cs-fixer-rollouttakes in the rules leftNot yet:one at a time, path by path, through a second config file, as the ticket "PHP CS Fixer: take in the remaining rules". A Housekeeping line looks for a newer PER Coding Style version. - PHPMD no longer starts with a baseline: the limits of its metric rules are set to the worst value the code has today, with a comment, and fall whenever a refactoring removes that worst value. Deliberate exceptions are suppressed at the code with a reason, the five rule sets (now with
design) are the default, and a project that already has a PHPMD baseline gets one merge request that replaces it. - PHPMD now comes in two Stages, like PHP CS Fixer. The adoption (
phpmd-adoption, renamed fromphpmd) installs the tool, sets the limits, takes in the rules one merge request can carry and adds the CI job; rules leftNot yet:no longer keep it unfulfilled. The new Guardrails Stagephpmd-rollouttakes in those rules one at a time, as the ticket "PHPMD: take in the remaining rules". A rule too large for one merge request is taken in directory by directory through a second ruleset,phpmd.rollout.xml, which CI runs over the directories already done, so they cannot slip back before the rule is in everywhere. - A Stage's
aftermay now name a Role as well as a Stage. The Rector Stages wait for the Role Code Style instead of PHP CS Fixer's adoption, so the tooling diagram shows PHP CS Fixer, Laravel Pint, Easy Coding Standard and PHP_CodeSniffer feeding one Code Style node that Rector waits on. When Rector is released does not change: a Role counts as decided once it is filled, or once every Tool that could fill it is decided. A target's own Pack can use the same form. - The suite no longer names one agent's question tool: it asks for the environment's multiple-choice question tool (Claude Code, Cursor and OpenCode each have one under a different name) and falls back to numbered options in chat when there is none, so questions are shown in Cursor and OpenCode too. A tool reply that no human gave counts as unanswered.
- A new optional operation, Ready after plan, lets a target mark a ticket ready for implementation (for example a label or a board column) right after the suite posts a plan on it. Without the bullet nothing changes.