FAQ

Why does composer dev-tools docs fail in a new package?

Because the command requires a docs/ directory. Create at least docs/index.rst before running docs or reports .

Why did my composer.json change after installing the package?

The Composer plugin runs dev-tools:sync after install and update. That command adds the dev-tools scripts and updates extra.grumphp.config-default-path in the consumer project.

Do I always need to run dev-tools:sync manually?

Usually no. The plugin already runs it after composer install and composer update . Manual sync is most useful when plugins were disabled or after upgrading fast-forward/dev-tools and wanting to refresh consumer automation. That flow also runs skills so packaged skill links are kept up to date.

When should I run composer dev-tools skills manually?

Run it when you want to refresh .agents/skills without rerunning the full consumer sync flow, especially after upgrading fast-forward/dev-tools or after deleting a packaged skill link locally.

Why does code-style touch composer.lock ?

Because FastForward\DevTools\Command\CodeStyleCommand always runs composer update --lock --quiet before Composer Normalize and ECS.

Where did .docheader come from?

FastForward\DevTools\Command\PhpDocCommand creates it automatically when it is missing. The template comes from the packaged file and is rewritten with the current package name when possible.

How do I run only one test class or method?

Use the tests command with --filter :

composer dev-tools tests -- --filter=SyncCommandTest

Why can my tests double final classes?

The packaged PHPUnit extension enables DG\BypassFinals at suite start through ByPassfinalsStartedSubscriber .

Why did desktop notifications stop appearing after I customized PHPUnit?

If you replaced the packaged phpunit.xml , you may also have removed FastForward\DevTools\PhpUnit\Runner\Extension\DevToolsExtension . Re-add the extension if you want the notification behavior back.

Is AddMissingClassPhpDocRector enabled by default?

No. The class is shipped and tested, but the packaged rector.php enables only AddMissingMethodPhpDocRector and RemoveEmptyDocBlockRector .

What happens if .github/wiki already exists?

dev-tools:sync leaves it alone. The wiki submodule is only created when the directory is missing.

What happens if .agents/skills/my-skill already exists?

If that path is a real directory instead of a symlink, the skills command preserves it and skips link creation. Broken symlinks are repaired, but consumer-owned directories are not overwritten automatically.

How do I override only one tool without forking the whole package?

Create only the local configuration file you want to customize, such as rector.php or phpunit.xml . DevTools will prefer that file and keep the rest on the packaged defaults.

How do I extend the ECS configuration without copying the whole file?

Use the ECSConfig class to extend instead of replace:

<?php

use FastForward\DevTools\Config\ECSConfig;

$config = ECSConfig::configure();
$config->withRules([CustomRule::class]);

return $config;

This approach automatically receives upstream updates while allowing additive customization.

How do I extend the Rector configuration without copying the whole file?

Use the RectorConfig class to extend instead of replace:

<?php

use FastForward\DevTools\Config\RectorConfig;

return RectorConfig::configure(
    static function (\Rector\Config\RectorConfig $rectorConfig): void {
        $rectorConfig->rules([CustomRule::class]);
    }
);

This approach automatically receives upstream updates while allowing additive customization.

Can I generate coverage without running the full standards pipeline?

Yes. Run vendor/bin/dev-tools tests --coverage=public/coverage to generate coverage directly.