Skip to documentation

Specialized Commands

Use the standalone commands when you want one tool instead of the full standards pipeline.

External Changelog CLI

Run the latest published independent Fast Forward Changelog CLI through cpx --skip-local . CPX and PHP 8.5 must be available on its execution path; the consumer's PHP 8.3 requirement stays unchanged.

cpx --skip-local fast-forward/changelog add "Fixes release-note rendering." --category=fixed --no-interaction
cpx --skip-local fast-forward/changelog check --no-interaction
cpx --skip-local fast-forward/changelog status --source=tags --no-interaction

Contributions use independent .changelog/*.md files. Inspect external command help for its options and output contracts. See External Fast Forward Changelog for runtime requirements and release-preview boundaries.

tests

Runs PHPUnit with the resolved phpunit.xml .

cpx --skip-local "fast-forward/dev-tools:$DEV_TOOLS_VERSION" tests
cpx --skip-local "fast-forward/dev-tools:$DEV_TOOLS_VERSION" tests --filter=EventTracerTest

Important details:

  • local phpunit.xml is preferred over the packaged default;
  • --coverage=<path> creates HTML, Testdox, Clover, and raw coverage output;
  • --coverage-summary keeps coverage text output to PHPUnit's summary;
  • cache stays enabled by default; --cache forces it on and --no-cache forces it off for a single run;
  • when --cache-dir is omitted, PHPUnit keeps its default cache directory;
  • --cache-dir only affects PHPUnit's result cache when caching is enabled;
  • progress output is disabled by default;
  • --progress re-enables PHPUnit progress output in text mode;
  • --json and --pretty-json still suppress PHPUnit progress output automatically;
  • --pretty-json stays valid JSON and does not add ANSI color escapes;
  • in agent-driven runs, the command also captures PHPUnit output in structured mode automatically and stores the bundled PHPUnit agent-reporter payload in output . --json and --pretty-json therefore keep the same structured shape, with raw_output preserved under output when PHPUnit writes extra text before the final JSON;
  • the packaged configuration registers the DevTools PHPUnit extension.

dependencies

Analyzes missing, unused, misplaced, and outdated Composer dependencies.

cpx --skip-local "fast-forward/dev-tools:$DEV_TOOLS_VERSION" dependencies
cpx --skip-local "fast-forward/dev-tools:$DEV_TOOLS_VERSION" dependencies --max-outdated=10
cpx --skip-local "fast-forward/dev-tools:$DEV_TOOLS_VERSION" dependencies --max-outdated=-1
cpx --skip-local "fast-forward/dev-tools:$DEV_TOOLS_VERSION" dependencies --dev
cpx --skip-local "fast-forward/dev-tools:$DEV_TOOLS_VERSION" dependencies --dump-usage=symfony/console
cpx --skip-local "fast-forward/dev-tools:$DEV_TOOLS_VERSION" dependencies --show-shadow-dependencies
cpx --skip-local "fast-forward/dev-tools:$DEV_TOOLS_VERSION" dependencies --upgrade --dev

Important details:

  • it ships shipmonk/composer-dependency-analyser and rector/swiss-knife as direct dependencies of fast-forward/dev-tools ;
  • it uses composer-dependency-analyser for missing, unused, and misplaced dependency checks, with a packaged config that consumer repositories can override locally;
  • --dump-usage=<package> forwards to composer-dependency-analyser --dump-usages <package> --show-all-usages ;
  • --show-shadow-dependencies keeps shadow dependency findings visible for audits; without it, DevTools hides intentional Fast Forward dependency-group shadows so CI does not fail on ecosystem or meta packages that deliberately install related dependencies for consumers;
  • it uses swiss-knife breakpoint --limit=<max-outdated> to fail when too many outdated dependencies accumulate;
  • --max-outdated=-1 keeps the Rector Swiss Knife outdated report in the output but ignores Rector Swiss Knife's failure so only dependency-analyser findings fail the command;
  • the packaged tests.yml workflow uses --max-outdated=-1 by default, so dependency health stays required in CI while outdated-package counts are reported without failing the workflow on their own;
  • it previews swiss-knife raise-to-installed and swiss-knife open-versions before the analyzers;
  • --upgrade runs swiss-knife raise-to-installed , swiss-knife open-versions , composer update -W , and composer normalize before the analyzers;
  • it returns a non-zero exit code when missing, unused, misplaced, or too many outdated dependencies are found.

metrics

Analyzes code metrics with PhpMetrics.

cpx --skip-local "fast-forward/dev-tools:$DEV_TOOLS_VERSION" metrics
cpx --skip-local "fast-forward/dev-tools:$DEV_TOOLS_VERSION" metrics --target=.dev-tools/metrics
FAST_FORWARD_WORKSPACE_DIR=.artifacts cpx --skip-local "fast-forward/dev-tools:$DEV_TOOLS_VERSION" metrics
cpx --skip-local "fast-forward/dev-tools:$DEV_TOOLS_VERSION" --working-dir=packages/example metrics

Important details:

  • it ships phpmetrics/phpmetrics as a direct dependency of fast-forward/dev-tools ;
  • when invoked through Composer, you MAY use Composer's inherited --working-dir option to analyze another checkout without changing directories first;
  • --target stores the HTML report plus report.json and report-summary.json in the same directory for CI artifacts or manual review;
  • when --target is omitted, metrics output is written under the selected DevTools workspace, usually .dev-tools/metrics ;
  • --json and --pretty-json keep the top-level DevTools response structured while forwarding JSON or quieter modes to the wrapped tools where available;
  • it suppresses deprecation notices emitted by the PhpMetrics dependency itself so the command output stays readable;
  • it keeps PhpMetrics' Composer analysis enabled so report generation includes root package metadata, while default exclusions keep nested fixture projects out of that Composer scan;
  • it limits PhpMetrics' per-package Packagist socket wait so package freshness enrichment cannot leave report generation stuck indefinitely.

code-style

Runs Composer Normalize and ECS.

cpx --skip-local "fast-forward/dev-tools:$DEV_TOOLS_VERSION" code-style
cpx --skip-local "fast-forward/dev-tools:$DEV_TOOLS_VERSION" code-style --fix

Important details:

  • it does not refresh the lockfile or run dependency updates first;
  • without --fix , Composer Normalize runs in --dry-run mode;
  • ECS uses local ecs.php when present, otherwise the packaged fallback;
  • progress output is disabled by default; --progress re-enables it for text mode;
  • --json and --pretty-json forward JSON mode to ECS and suppress its progress bar.

refactor

Runs Rector against the current project.

cpx --skip-local "fast-forward/dev-tools:$DEV_TOOLS_VERSION" refactor --fix

Important details:

  • without --fix , Rector runs in dry-run mode;
  • local rector.php is preferred when present;
  • the packaged default includes Fast Forward custom Rector rules plus shared Rector sets;
  • progress output is disabled by default; --progress re-enables it for text mode;
  • --json and --pretty-json forward --output-format json to Rector and disable its progress bar.

phpdoc

Coordinates PHP-CS-Fixer and a focused Rector pass for missing method PHPDoc.

cpx --skip-local "fast-forward/dev-tools:$DEV_TOOLS_VERSION" phpdoc
cpx --skip-local "fast-forward/dev-tools:$DEV_TOOLS_VERSION" phpdoc --fix

Important details:

  • it creates .docheader from the packaged template when the file is missing;
  • it uses .php-cs-fixer.dist.php and rector.php through the same local-first fallback logic;
  • the Rector phase explicitly runs FastForward\DevTools\Rector\AddMissingMethodPhpDocRector ;
  • cache stays enabled by default; --cache forces it on and --no-cache forces it off for the PHP-CS-Fixer phase;
  • when --cache-dir is omitted, PHP-CS-Fixer keeps its default cache directory;
  • --cache-dir only affects PHP-CS-Fixer when caching is enabled;
  • progress output is disabled by default; --progress re-enables it for text mode;
  • --json and --pretty-json switch PHP-CS-Fixer to JSON output with progress disabled and run the Rector phase in JSON mode without its progress bar.

docs

Builds the HTML documentation site with phpDocumentor.

cpx --skip-local "fast-forward/dev-tools:$DEV_TOOLS_VERSION" docs --source=docs --target=.dev-tools

Important details:

  • docs/ must exist unless you pass another --source directory;
  • API pages are built from the PSR-4 paths declared in composer.json ;
  • guide pages are built from the selected source directory;
  • --template defaults to vendor/fast-forward/phpdoc-bootstrap-template ;
  • cache stays enabled by default; --cache forces it on and --no-cache forces it off for a single run;
  • when --cache-dir is omitted, phpDocumentor keeps its default cache directory;
  • --cache-dir only affects phpDocumentor when caching is enabled;
  • progress output is disabled by default; --progress re-enables it for text mode;
  • --json and --pretty-json also disable phpDocumentor's progress output.

wiki

Builds Markdown API pages for a GitHub wiki.

cpx --skip-local "fast-forward/dev-tools:$DEV_TOOLS_VERSION" wiki

Important details:

  • the default output directory is .github/wiki ;
  • normal dev-tools:sync and the direct Wiki workflow explicitly use .dev-tools/wiki-generated without initializing a submodule;
  • --init remains an explicit legacy option for submodule users;
  • it uses the Markdown template from vendor/saggre/phpdocumentor-markdown/themes/markdown ;
  • cache stays enabled by default; --cache forces it on and --no-cache forces it off for a single run;
  • when --cache-dir is omitted, phpDocumentor keeps its default cache directory;
  • --cache-dir only affects phpDocumentor when caching is enabled;
  • it is especially useful together with the reusable wiki workflow.

reports

Runs the documentation and test-report pipeline used by GitHub Pages.

cpx --skip-local "fast-forward/dev-tools:$DEV_TOOLS_VERSION" reports

Important details:

  • it calls docs , tests --coverage , and metrics with defaults rooted in the selected DevTools workspace;
  • with the default workspace, that is equivalent to docs --target .dev-tools , tests --coverage .dev-tools/coverage --coverage-summary , and metrics --target .dev-tools/metrics --junit .dev-tools/coverage/junit.xml ;
  • docs remains detached, while tests and metrics run in sequence so PhpMetrics can reuse the JUnit report generated by PHPUnit;
  • cache stays enabled by default for the nested docs and tests steps; --cache forces that explicit intent on and --no-cache forces it off;
  • when --cache-dir is omitted, nested tools keep their own default cache directories;
  • progress output stays disabled by default across the nested steps, and --progress re-enables it for human-readable runs;
  • --json and --pretty-json are propagated to each subprocess, while their progress output is suppressed where supported;
  • human-readable runs keep nested command output grouped with concise local section boundaries, pass color-friendly environment variables to subprocesses, and forward explicit ANSI flags to Symfony Console tools;
  • queued subprocesses run with XDEBUG_MODE=off when Xdebug is loaded but the command does not need Xdebug for coverage, or when PCOV can provide coverage instead;
  • it is the reporting stage used by standards .

Skill installation

Use LLM Skills; see Installing Packaged Skills. DevTools no longer installs skill or agent links.

funding

Synchronizes supported funding metadata between Composer and GitHub formats.

cpx --skip-local "fast-forward/dev-tools:$DEV_TOOLS_VERSION" funding
cpx --skip-local "fast-forward/dev-tools:$DEV_TOOLS_VERSION" funding --dry-run
cpx --skip-local "fast-forward/dev-tools:$DEV_TOOLS_VERSION" funding --check

Important details:

  • it keeps composer.json funding entries and .github/FUNDING.yml in sync for GitHub Sponsors and custom URLs;
  • it preserves unsupported Composer funding providers and unsupported YAML keys instead of rewriting them;
  • it creates .github/FUNDING.yml when Composer already declares supported funding metadata;
  • it supports --dry-run , --check , and --interactive so funding drift can be surfaced in CI and reviewed locally.

codeowners

Generates managed CODEOWNERS files from repository metadata.

cpx --skip-local "fast-forward/dev-tools:$DEV_TOOLS_VERSION" codeowners
cpx --skip-local "fast-forward/dev-tools:$DEV_TOOLS_VERSION" codeowners --dry-run
cpx --skip-local "fast-forward/dev-tools:$DEV_TOOLS_VERSION" codeowners --interactive

Important details:

  • it inspects composer.json author homepages to infer GitHub handles for .github/CODEOWNERS ;
  • when direct ownership cannot be inferred, it renders a commented fallback instead of copying hard-coded owners into the consumer repository;
  • --interactive lets maintainers provide explicit owners before writing the catch-all * rule;
  • dev-tools:sync runs codeowners automatically alongside the other consumer bootstrap steps.

dev-tools:sync

Synchronizes consumer-facing automation and defaults.

cpx --skip-local "fast-forward/dev-tools:$DEV_TOOLS_VERSION" dev-tools:sync

Important details:

  • it updates composer.json scripts and removes only deprecated DevTools-managed extra.grumphp.config-default-path values;
  • it calls funding so supported funding metadata stays aligned between composer.json and .github/FUNDING.yml ;
  • it copies missing workflow stubs, .editorconfig , and dependabot.yml ;
  • it calls codeowners to generate .github/CODEOWNERS from local metadata;
  • in normal mode it generates local API Markdown in .dev-tools/wiki-generated without creating a Git submodule;
  • it calls gitignore to merge the canonical .gitignore with the project's .gitignore;
  • it calls gitattributes to manage export-ignore rules in .gitattributes;
  • it copies a missing local grumphp.yml and refreshes hooks that prefer local GrumPHP, otherwise CPX phpro/grumphp-shim:2.26.0 ; temporary runtime/cache paths are not stored in hooks;

gitattributes

Manages .gitattributes export-ignore rules for leaner Composer package archives.

cpx --skip-local "fast-forward/dev-tools:$DEV_TOOLS_VERSION" gitattributes

Important details:

  • it adds export-ignore entries for repository-only files and directories;
  • it only adds entries for paths that actually exist in the repository;
  • it respects the extra.gitattributes.keep-in-export configuration to keep specific paths in exported archives;
  • it preserves existing custom .gitattributes rules;
  • it deduplicates equivalent entries and sorts them with directories before files, then alphabetically;
  • it uses CandidateProvider, ExistenceChecker, ExportIgnoreFilter, Merger, Reader, and Writer components from the GitAttributes namespace.

gitignore

Merges and synchronizes .gitignore files.

cpx --skip-local "fast-forward/dev-tools:$DEV_TOOLS_VERSION" gitignore --source=/path/to/source/.gitignore --target=/path/to/target/.gitignore

Important details:

  • it reads the canonical .gitignore from dev-tools and merges with the project's existing .gitignore;
  • by default, the source is the packaged .gitignore and the target is the project's root .gitignore;
  • duplicates are removed and entries are sorted alphabetically;
  • it uses the Reader, Merger, and Writer components from the GitIgnore namespace.

license

Generates a LICENSE file from composer.json license information.

cpx --skip-local "fast-forward/dev-tools:$DEV_TOOLS_VERSION" license

Important details:

  • it reads the license field from composer.json ;
  • it supports common open-source licenses (MIT, Apache-2.0, BSD-2-Clause, BSD-3-Clause, GPL-3.0, LGPL-3.0, and MPL-2.0);
  • it resolves placeholders such as [year] , [author] , and [project] using information from composer.json ;
  • it uses template files from resources/license-templates/ ;
  • it skips generation if a LICENSE file already exists.

copy-resource

Copies packaged or local resources into the consumer repository.

cpx --skip-local "fast-forward/dev-tools:$DEV_TOOLS_VERSION" copy-resource --source <path> --target <path> --overwrite

Important details:

  • source is resolved using FileLocatorInterface ;
  • target is resolved to an absolute path using FilesystemInterface ;
  • both --source and --target are required options;
  • without --overwrite , existing target files are skipped;
  • supports both files and directories as sources.

git-hooks

Installs packaged Fast Forward Git hooks.

cpx --skip-local "fast-forward/dev-tools:$DEV_TOOLS_VERSION" git-hooks

Important details:

  • copies hook files from source to target directory;
  • sets executable permissions on copied hooks with 0o755 ;
  • removes an existing drifted hook before recopying it so stale target permissions do not block replacements;
  • --source defaults to resources/git-hooks ;
  • --target defaults to .git/hooks ;
  • --no-overwrite preserves existing hook files.

update-composer-json

Updates composer.json with Fast Forward dev-tools scripts and metadata.

cpx --skip-local "fast-forward/dev-tools:$DEV_TOOLS_VERSION" update-composer-json --file=composer.json

Important details:

  • adds dev-tools script entrypoint to composer.json;
  • adds dev-tools:fix script for automated fixing;
  • removes only deprecated DevTools-managed extra.grumphp.config-default-path values;
  • if the target file does not exist, exits silently with code 0;
  • existing scripts with the same name are overwritten;
  • preserves consumer-owned GrumPHP settings.

Normalization runtime

Composer Normalize executes as a plugin from the isolated runtime root against the consumer's absolute manifest path with --no-update-lock . The consumer does not need that plugin installed. An explicitly requested dependency upgrade may still update its Composer lockfile; normalization itself does not.

Search results