Most project instructions for coding agents are copied from a template. The commands in them often don't exist in your repo, so the agent runs them, fails, and guesses. For Drupal this is worse than usual, because "a Drupal project" can mean three very different things: a full site, a single contrib module, or a distribution. This post shows how to write a CLAUDE.md (or AGENTS.md) by reading the repository first, using two real public repos:

Step 1: find out what kind of repo it is

grep -n '"type"' composer.json ls -a | head -40 

In localgov_directories, composer.json says "type": "drupal-module" and the root holds localgov_directories.info.yml. There is no web/ directory, no vendor/, no Drush. In drupal/cms there is a .ddev/ directory, a web docroot setting in .ddev/config.yaml, and drush/drush in composer.json.

That one check changes every command you write. A module repo cannot run its own tests: they need a full Drupal codebase around the module. If your instructions say vendor/bin/phpunit -c web/core ... for a module repo, the agent will fail on the first try.

Step 2: find the command runner

Don't assume DDEV. The drupal/cms AGENTS.md makes this explicit: check for a .ddev/ directory and ddev on the PATH; otherwise fall back to local Composer, and use vendor/bin/drush only if it exists. Steal that idea:

ls -d .ddev 2>/dev/null command -v ddev test -x vendor/bin/drush && echo "project drush" 

Then write the commands with the right prefix once, instead of leaving the agent to decide each time.

Step 3: list only commands you can point at

Every command in the file should come from somewhere you can name: a composer.json script, the DDEV config, the CI workflow, or the official docs. For Drupal the commands that matter are small in number:

  • Rebuild caches: drush cache:rebuild (docs)
  • Apply database updates: drush updatedb
  • See config differences between the database and the sync directory: drush config:status (docs)
  • Preview a config import as a diff: drush config:import --diff (docs)
  • Run one PHPUnit test from a site root: vendor/bin/phpunit -c web/core path/to/Test.php (docs)

Notice what is not on the list: drush config:import --yes. The drupal/cms agent file lists it as a normal workflow, which is reasonable for a fresh local site. On a site with real active config, the --yes flag applies the import without asking, so in your own file you may want "show the diff first" instead.

In the module repo, CI runs the tests through a shared workflow that installs the module at web/modules/contrib/localgov_directories inside a full site. So the honest instruction there is one sentence: "tests run inside a full Drupal site; the module path is web/modules/contrib/localgov_directories", not a made-up local command.

Step 4: write the guardrails in plain words

The part agents most need is what not to touch. A short list works better than a long one:

  • Never edit Drupal core or contributed projects in place; patch through Composer or write a custom module.
  • Custom code lives in web/modules/custom and web/themes/custom.
  • Never commit vendor/, settings.local.php, .env, or uploaded files under web/sites/*/files.

The drupal/cms file has this section too, and it is the most reusable part of it.

Step 5: keep what's already there

If a CLAUDE.md or AGENTS.md exists, add a clearly marked section instead of rewriting it. Other people (and other tools) rely on the original lines.

Check your file

Ask three questions of every line: where does this command come from, does it work from this directory, and what happens if it is wrong? If you can't answer the first, delete the line. A shorter file made of true statements beats a long one the agent has to second-guess.

Written with AI assistance. Every command and example here was run against the public repositories named above.