A new site has no old code, so every problem a check finds is new. An existing site is different: run phpcs or phpstan over it and you will usually get hundreds of problems nobody wrote this week. If droost judged every run on all of them, the first change that touched an old file would fail, and keep failing, on work that is not the agent's.

The fix is a baseline: a record of the problems the site has today, so a run is judged only on what it adds. Write it before the first run.

The order

Install droost the usual way first (Set up by hand or with AI), then:

  1. Commit or stash any work in progress.
  2. Pick the level.
  3. Install the tools the checks use.
  4. Measure the old problems.
  5. Write the baseline, and commit it.
  6. Start your first run.

The order matters. The baseline records only the checks the level turns on, and a later refresh can only remove problems, not add them (see Raising the level later). Set the level first.

1. Start from a clean tree

droost does not count changes it finds in your working folder when a run begins as the run's own. Leftover edits make the first run's checks look at the wrong files. Commit or stash them first.

2. Pick the level

From your own terminal:

bash
droost workflow:effort high

droost workflow:effort high --preview shows what a level turns on without writing anything. Settings has the table.

3. Install the tools

bash
composer require --dev drupal/core-dev     # phpcs, phpstan, phpunit
npm i -D @playwright/test && npx playwright install chromium

If the project already has its own phpcs.xml(.dist) or phpstan.neon, droost's checks use it, and the baseline is measured with it too.

4. Measure the old problems

bash
droost workflow:baseline --measure

This runs each check the level turns on over the whole site, so on a big site it takes as long as a code step. It writes nothing, and prints (as JSON) the level, the bill (how many problems each check would record) and skipped: each check it could not measure, and why. A tool that is missing or crashes is listed there, never recorded as clean.

Read the numbers before you write them down. A check with thousands of problems may be pointed at the wrong folders (vendor/, a contrib module copied into modules/custom/).

5. Write the baseline

From your own terminal, between runs (the agent cannot write it, since a baseline the agent could write is a problem it could hide; and it is refused while a run is open):

bash
droost workflow:baseline
git add droost/baseline/
git commit -m "droost: record the baseline"

It is written to droost/baseline/, one file per check, and committed like any other code, so the team sees what was accepted.

droost workflow:baseline --status shows what is recorded.

What a run sees now

A check that passes says how much of what it found was already there:

text
phpcs     passed: 0 new, 312 inherited
  • Only new problems fail a run.
  • For phpcs, eslint and stylelint, a problem belongs to its line's text. A line the change edited counts as new, even if its problem is old, so the agent fixes what it touches; a line that only moved, or was re-indented, stays inherited.
  • For prettier, an unformatted file stays inherited until a run touches it.
  • phpstan uses its own baseline file, which droost writes and points phpstan at.
  • The baseline is frozen when each run starts, so it cannot change under a run.

What it covers: phpcs, phpstan, eslint, stylelint, prettier, and the coverage and mutation floors. Tests are not baselined. A failing phpunit or Playwright test is broken, not old, and fails the run until it is fixed or skipped in the test itself.

Paying it off

As the team fixes old problems, record the smaller number:

bash
droost workflow:baseline --refresh

A refresh only ever shrinks the baseline: fixed problems drop out, and if it finds more than before it refuses and names them.

Raising the level later

A higher level turns on more checks, or makes one stricter (phpstan's level, for example), and those find old problems the baseline never recorded. A refresh refuses to add them unless you say why:

bash
droost workflow:baseline --refresh --grow --reason="raised to xhigh"

The reason is kept in the baseline's record for good.

Your team, alongside the agent

  • People are not blocked. The guard holds the agent, not your editor. Anyone can still edit and commit as before.
  • The agent edits custom code only inside a run. With require_run: hard (what init writes), an agent asked for a quick fix outside a run is refused. To let it, run droost workflow:bypass "<why>" in your terminal, and droost workflow:bypass --off after; or set require_run: soft in Settings.
  • Your own instructions are kept. init adds droost's section to AGENTS.md and CLAUDE.md between marker comments and leaves the rest of each file alone.
  • The wiki starts thin. On day one droost knows your modules and your code from the files, but has none of your team's notes. Each run adds what it built to droost/wiki/; you can add pages of your own there too.

When the first run still fails on old code

Read the gate's message. If the problems are in files the run did not touch, it names them. Usually that means the baseline was written at another level, or before a tool was installed; measure again and refresh. See Troubleshooting.