Overriding Defaults

Local override files let a consumer project keep the Fast Forward baseline without forking the whole package.

Resolution Order

Commands use Symfony\Component\Config\FileLocatorInterface to locate configuration files. The locator resolves configuration in this order:

  1. Check whether the file exists in the current working directory.
  2. Use the local file when it exists.
  3. Otherwise fall back to the packaged file inside fast-forward/dev-tools .

This behavior is consistent across all commands through the DI container and FileLocatorInterface .

Commands and Their Configuration Files

Command Local file Fallback behavior
code-style ecs.php Falls back to the packaged ECS configuration.
refactor rector.php Falls back to the packaged Rector configuration.
tests phpunit.xml Falls back to the packaged PHPUnit configuration.
dependencies composer-dependency-analyser.php Falls back to the packaged Composer Dependency Analyser configuration.
phpdoc .php-cs-fixer.dist.php and rector.php Falls back to the packaged files; .docheader is created locally when missing.
docs docs/ or another path passed with --source The selected guide source must exist locally.
skills .agents/skills/ Creates missing local links to packaged skills and preserves existing non-symlink directories.
agents .agents/agents/ Creates missing local links to packaged project agents and preserves existing non-symlink directories.
dev-tools:sync Consumer repository files Works directly against local project files such as composer.json and .github/* .

A Practical Example

To customize Rector for one library, create rector.php in the consumer project root. The refactor command and the Rector phase inside phpdoc will use that file instead of the packaged default.

Extending ECS Configuration

Instead of copying the entire ecs.php file, consumers can extend the default configuration using the ECSConfig class:

<?php

use FastForward\DevTools\Config\ECSConfig;
use PhpCsFixer\Fixer\Phpdoc\PhpdocAlignFixer;

$config = ECSConfig::configure();
$config->withRules([CustomRule::class]);
$config->withConfiguredRule(PhpdocAlignFixer::class, ['align' => 'right']);

return $config;

Extending Rector Configuration

Instead of copying the entire rector.php file, consumers can extend the default configuration using the RectorConfig class:

<?php

use FastForward\DevTools\Config\RectorConfig;

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

        $rectorConfig->skip([
            // custom skips
        ]);
    }
);

This approach:

  • Eliminates duplication of the base configuration
  • Automatically receives upstream updates
  • Only requires overriding what is needed

Extending Composer Dependency Analyser Configuration

Instead of copying the entire composer-dependency-analyser.php file, consumers can extend the default configuration using the ComposerDependencyAnalyserConfig class:

<?php

use FastForward\DevTools\Config\ComposerDependencyAnalyserConfig;
use ShipMonk\ComposerDependencyAnalyser\Config\Configuration;
use ShipMonk\ComposerDependencyAnalyser\Config\ErrorType;

return ComposerDependencyAnalyserConfig::configure(
    static function (Configuration $configuration): void {
        $configuration->ignoreErrorsOnPackage(
            'vendor/package',
            [ErrorType::UNUSED_DEPENDENCY],
        );
    }
);

This approach keeps the Fast Forward baseline while letting consumer repositories add project-specific ignores or scan rules.

What Is Not Overwritten Automatically

  • existing workflow files in .github/workflows/ ;
  • an existing .editorconfig ;
  • an existing .github/dependabot.yml ;
  • an existing non-symlink directory inside .agents/skills/ ;
  • an existing non-symlink directory inside .agents/agents/ ;
  • an existing .github/wiki directory or submodule.