# 0.9.0: Tooling, das zu deinem Projekt passt – Rollen, Ratschen, Packs

*26. Oktober 2026 · Release · geschrieben für 0.9.0*

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](#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](https://continuous-refactoring.de/de/docs/tooling.md) listet die Rollen und Packs auf,
und jedes Pack hat eine Seite mit Diagramm, zum Beispiel
[PHP](https://continuous-refactoring.de/de/docs/pack-php.md).

## 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](https://continuous-refactoring.de/de/docs/own-tool.md) hat ein durchgearbeitetes Beispiel mit
Deptrac.

Das Format der `pack.json` beschreibt ein JSON Schema,
[`pack.schema.json`](https://github.com/Art4/continuous-refactoring/blob/0.9.0/skills/continuous-refactoring/references/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](https://github.com/Art4/continuous-refactoring/blob/main/CHANGELOG.md)
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](https://continuous-refactoring.de/de/docs/faq.md) erklärt die Gründe, zum Beispiel
[warum die Suite in Rollen und Tools denkt](https://continuous-refactoring.de/de/docs/faq.md#warum-denkt-die-suite-in-rollen-und-tools-statt-nur-in-einer-liste-von-schritten)
und [warum PHPMD keine Baseline hat](https://continuous-refactoring.de/de/docs/faq.md#warum-hat-phpmd-keine-baseline).

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)](https://github.com/Art4/continuous-refactoring/discussions/categories/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](https://github.com/Art4/continuous-refactoring/releases/tag/0.9.0).

- 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.json` and 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`/`phpcbf` has 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-version` is 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 from `php-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 Stage `php-cs-fixer-rollout` takes in the rules left `Not 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 from `phpmd`) installs the tool, sets the limits, takes in the rules one merge request can carry and adds the CI job; rules left `Not yet:` no longer keep it unfulfilled. The new Guardrails Stage `phpmd-rollout` takes 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 `after` may 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.

---

Fragen oder Anmerkungen zu diesem Beitrag? Gern in den [GitHub Discussions (Q&A)](https://github.com/Art4/continuous-refactoring/discussions/categories/q-a).
