PHPackages                             infocyph/phpforge - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Testing &amp; Quality](/categories/testing)
4. /
5. infocyph/phpforge

ActiveComposer-plugin[Testing &amp; Quality](/categories/testing)

infocyph/phpforge
=================

Shared QA, refactoring, benchmark and release tooling for Infocyph PHP projects.

02.8k↓32.9%19PHPCI passing

Since Jul 10Pushed 1w agoCompare

[ Source](https://github.com/infocyph/PHPForge)[ Packagist](https://packagist.org/packages/infocyph/phpforge)[ RSS](/packages/infocyph-phpforge/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependenciesVersions (2)Used By (19)

PHPForge
========

[](#phpforge)

[![PHPForge](https://github.com/infocyph/PHPForge/actions/workflows/phpforge.yml/badge.svg)](https://github.com/infocyph/PHPForge/actions/workflows/phpforge.yml)[![Packagist Downloads](https://camo.githubusercontent.com/90f272374229847fdc391dbae6a3b1a8df10b47bd53d59262bc9438b8424130d/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f696e666f637970682f504850466f7267653f636f6c6f723d677265656e266c696e6b3d68747470732533412532462532467061636b61676973742e6f72672532467061636b61676573253246696e666f63797068253246504850466f726765)](https://camo.githubusercontent.com/90f272374229847fdc391dbae6a3b1a8df10b47bd53d59262bc9438b8424130d/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f696e666f637970682f504850466f7267653f636f6c6f723d677265656e266c696e6b3d68747470732533412532462532467061636b61676973742e6f72672532467061636b61676573253246696e666f63797068253246504850466f726765)[![License: MIT](https://camo.githubusercontent.com/784362b26e4b3546254f1893e778ba64616e362bd6ac791991d2c9e880a3a64e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d677265656e2e737667)](https://opensource.org/licenses/MIT)[![GitHub Code Size](https://camo.githubusercontent.com/d267e086865c2987f6640c583d164fe8a0bf596acbbdf55006dbb0227eca3508/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c616e6775616765732f636f64652d73697a652f696e666f637970682f504850466f726765)](https://camo.githubusercontent.com/d267e086865c2987f6640c583d164fe8a0bf596acbbdf55006dbb0227eca3508/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c616e6775616765732f636f64652d73697a652f696e666f637970682f504850466f726765)

Shared Composer-powered QA, refactoring, benchmark, release, hook and CI tooling for Infocyph PHP projects.

PHPForge is installed as a dev dependency in PHP libraries and packages. It provides Composer commands under the `ic:*` namespace, ships default tool configuration, installs CaptainHook hooks, exposes a reusable GitHub Actions workflow and includes starter templates for GitLab CI, Bitbucket Pipelines and Forgejo Actions.

What It Includes
----------------

[](#what-it-includes)

PHPForge brings these tools through one package:

ToolUsed ForCaptainHookGit hook installation and pre-commit checksPestTest executionLaravel PintCode style checks and fixesPHP\_CodeSniffer / PHPCBFSemantic sniffing and fixable sniff repairsPHPProbeGit-aware PHP syntax validation and duplicate detectionDeptracArchitecture boundary checksPHPStanStatic analysis and cognitive complexityPsalmSecurity and taint analysisRectorRefactor checks and automated refactorsPHPBenchBenchmarksComposer Normalize`composer.json` normalizationComposer auditRelease/security audit guardInstall
-------

[](#install)

Install in the consuming project (you will go through some series of approval, check and allow):

```
composer require --dev infocyph/phpforge:dev-main
```

If approval is needed (if not allowed in primary run or missed somehow), run:

```
composer config allow-plugins.infocyph/phpforge true
composer config allow-plugins.ergebnis/composer-normalize true
composer config allow-plugins.pestphp/pest-plugin true
composer install
```

Inspect the detected setup:

```
composer ic:doctor
```

JSON diagnostics are available for automation:

```
composer ic:doctor --json
```

Quick Start
-----------

[](#quick-start)

Common daily commands:

```
composer ic:tests
composer ic:process
composer ic:benchmark
composer ic:release:guard
```

Initialize optional project files:

```
composer ic:init
```

`ic:init` is interactive by default. It uses selector prompts for common choices and keeps a custom option for project-specific values:

```
Install CaptainHook pre-commit config (validate, audit, parallel CI)?
Install GitHub Actions workflow wrapper (parallel CI, SARIF, SVG report)?
Install GitLab CI pipeline (.gitlab-ci.yml)?
Install Bitbucket pipeline (bitbucket-pipelines.yml)?
Install Forgejo workflow (.forgejo/workflows/security-standards.yml)?
Install generic contributing, issue, and pull request templates?
PHPForge workflow ref
PHP version matrix
Dependency matrix
PHP extensions
Extra Composer flags
PHPStan memory limit
Psalm threads
Enable SARIF code-scanning analysis job?
Generate SVG security and quality report artifacts?
Enable Redis service container in workflow run job?
Enable Valkey service container in workflow run job?
Enable Memcached service container in workflow run job?
Enable PostgreSQL service container in workflow run job?
Enable MySQL service container in workflow run job?
Enable ScyllaDB Alternator service container in workflow run job?
Enable Elasticsearch service container in workflow run job?
Enable MongoDB service container in workflow run job?
Shared service database name:
Shared service username:
Shared service password:

```

`service_db_*` prompts are always shown once workflow setup is selected so one credential set can be reused across services.

Selector presets include:

PromptBuilt-in ChoicesPHPForge workflow ref`main`, configured ref, or customPHP version matrix`supported`, `current`, `stable`, or custom JSON. Presets resolve live with fallback to `["8.2","8.3","8.4","8.5"]`.Dependency matrix`full` =&gt; `["prefer-lowest","prefer-stable"]`, `stable` =&gt; `["prefer-stable"]`, or custom JSON. Prompt shows resolved JSON beside each option.PHP extensions`none` =&gt; `""`, `detected` (from project `composer.json` `ext-*` entries in `require`, `require-dev`, and `suggest`), `common`, `mysql`, `pgsql`, `mysql+pgsql`, or customExtra Composer flags`none` =&gt; `""`, `with-all-dependencies` =&gt; `--with-all-dependencies`, `ignore-ext-redis` =&gt; `--ignore-platform-req=ext-redis`, or custom. Prompt explains each option effect.PHPStan memory limit`1G`, `2G`, `4G`, or customPsalm threads`1`, `2`, `4`, or custom`supported` includes non-EOL PHP minor cycles (&gt;= `8.2`), `current` uses the latest two supported cycles, and `stable` uses the latest supported cycle. When detected `ext-*` entries exist in `composer.json`, the PHP extensions selector defaults to the detected preset. PHP version, dependency matrix, PHP extensions, and Composer flags selectors show resolved values in the prompt and print the final resolved value after selection.

Depending on your selections, `ic:init` can generate:

```
captainhook.json
.github/workflows/security-standards.yml
.gitlab-ci.yml
bitbucket-pipelines.yml
.forgejo/workflows/security-standards.yml
CONTRIBUTING.md
CODE_OF_CONDUCT.md
SECURITY.md
.github/ISSUE_TEMPLATE/bug_report.yml
.github/ISSUE_TEMPLATE/regression_report.yml
.github/ISSUE_TEMPLATE/ci_failure.yml
.github/ISSUE_TEMPLATE/feature_request.yml
.github/ISSUE_TEMPLATE/question.yml
.github/ISSUE_TEMPLATE/docs_improvement.yml
.github/ISSUE_TEMPLATE/config.yml
.github/PULL_REQUEST_TEMPLATE.md

```

`ic:init` sets up hook/workflow wrappers and optional community template files. Publish checker or architecture config separately with `composer ic:publish-config phpprobe.json deptrac.yaml` when customization is needed.

After `ic:init`, run:

```
composer ic:ci
```

`composer ic:ci` is the same path used by the generated workflow and bundled pre-commit hook; it runs syntax first, then the remaining normal quality checks with bounded parallelism.

If `captainhook.json` was installed, hooks auto-install on the next `composer install` or `composer update`. Use `composer ic:hooks` only when you want to install/update hooks immediately.

Use targeted or non-interactive init commands when needed:

```
composer ic:init --captainhook
composer ic:init --workflow --workflow-ref=main
composer ic:init --gitlab-ci
composer ic:init --bitbucket-ci
composer ic:init --forgejo-workflow
composer ic:init --community-templates
composer ic:init --no-interaction-defaults
composer ic:init --force
composer ic:int
```

Command Reference
-----------------

[](#command-reference)

### AI Mod

[](#ai-mod)

- `vendor/infocyph/phpforge/resources/engineering-principles.md`Brief engineering principles for AI-assisted implementation decisions, code quality, performance, security, and scope control.
- `vendor/infocyph/phpforge/resources/AGENTS.md`Task execution workflow for agents, including which PHPForge commands to run first, validation flow, and automation expectations.

### Test Commands

[](#test-commands)

CommandPurpose`composer ic:tests`Full project quality suite: syntax, Pest parallel tests, Pint check, PHPCS summary, duplicate detection, API snapshot checks, comment policy checks, Deptrac, PHPStan, Psalm security analysis, and Rector dry run.`composer ic:tests:all`Alias of `ic:tests`.`composer ic:tests:parallel`Runs syntax first, then executes the remaining quality checks with bounded parallelism and a buffered PASS/FAIL summary.`composer ic:tests:details`Runs detailed checks without the parallel Pest shortcut.`composer ic:test:syntax`Runs the PHP syntax checker using `phpprobe.json`, Git ignores, and configured excludes.`composer ic:test:code`Runs Pest.`composer ic:test:lint`Runs Pint in check mode.`composer ic:test:sniff`Runs PHPCS with a full report against the project root and bundled/project excludes.`composer ic:test:duplicates`Runs duplicate detection using `phpprobe.json`.`composer ic:test:probe`Runs aggregate PHPProbe checks (syntax, duplicates, api, comments) using `phpprobe.json`.`composer ic:test:api`Runs API snapshot checks using `phpprobe.json`.`composer ic:test:comments`Runs comment policy checks using `phpprobe.json`.`composer ic:test:architecture`Runs Deptrac architecture checks using `deptrac.yaml`.`composer ic:test:static`Runs PHPStan.`composer ic:test:security`Runs Psalm security analysis.`composer ic:test:refactor`Runs Rector in dry-run mode.`composer ic:test:bench`Runs PHPBench aggregate benchmarks.Syntax, duplicates, API snapshot, and comments settings live in `phpprobe.json`, with the bundled default used when a project-local file is not present. PHPForge delegates these checks to `vendor/bin/phpprobe`; the `phpforge syntax`, `phpforge duplicates`, `phpforge api`, `phpforge comments`, and `phpforge check` commands are thin compatibility gateways that pass the same config to PHPProbe. By default the bundled config uses preset-based behavior, so defaults come from the selected PHPProbe preset and can still be overridden per section in `phpprobe.json`. Use the lower-level binary for custom scans; CLI paths override configured paths, while CLI excludes are added to configured excludes:

```
php vendor/bin/phpprobe syntax --config=phpprobe.json --exclude=storage
php vendor/bin/phpprobe check --config=phpprobe.json
php vendor/bin/phpprobe duplicates --config=phpprobe.json --min-lines=5 --min-tokens=70
php vendor/bin/phpprobe duplicates --config=phpprobe.json --mode=audit --near-miss --json --exclude=tests
php vendor/bin/phpprobe api --config=phpprobe.json --baseline=.phpprobe-api-baseline.json
php vendor/bin/phpprobe comments --config=phpprobe.json --fail-on=warning
php vendor/bin/phpprobe comments --config=phpprobe.json --ci
php vendor/bin/phpprobe duplicates --config=phpprobe.json --write-baseline=.phpprobe-duplicates-baseline.json
php vendor/bin/phpprobe duplicates --config=phpprobe.json --baseline=.phpprobe-duplicates-baseline.json
```

Useful checker options:

OptionApplies ToPurpose`--config=FILE`Syntax, duplicates, api, comments, checkReads checker settings from a custom `phpprobe.json` file.`--preset=NAME`Syntax, duplicates, api, comments, checkApplies a runtime preset (`default`, `standard`, `ci`, `strict`).`--exclude=PATH`Syntax, duplicates, api, commentsExcludes one path; repeat it for multiple one-off exclusions.`--exact`DuplicatesDisables variable/literal normalization.`--fuzzy`DuplicatesAlso normalizes identifiers and calls for renamed-code scans.`--mode=audit`DuplicatesEnables statement-window matching in addition to token matching.`--near-miss`DuplicatesEnables bounded statement/shape similarity for edited clones.`--min-lines=N`DuplicatesSets the minimum duplicated line span.`--min-tokens=N`DuplicatesSets the token fingerprint window size.`--min-statements=N`DuplicatesSets the structural statement window size for audit matching.`--min-similarity=0.85`DuplicatesSets the near-miss similarity threshold.`--baseline=FILE`Duplicates, apiSuppresses known clone groups or compares API snapshots against a baseline.`--write-baseline[=FILE]`Duplicates, apiWrites duplicate-clone or API snapshot baselines and exits successfully.`--strict`CommentsEscalates commented-out-code policy severities.`--ci`CommentsEmits only error-level findings (clean CI logs).`--json`DuplicatesEmits machine-readable JSON.### CI Commands

[](#ci-commands)

CommandPurpose`composer ic:ci`Runs the normal CI suite through the same bounded parallel runner as `ic:tests:parallel`.`composer ic:ci --prefer-lowest`Runs the CI set without PHPStan and Psalm for prefer-lowest dependency jobs.### Process Commands

[](#process-commands)

CommandPurpose`composer ic:process`Runs Composer Normalize, Rector, Pint, and PHPCBF fixes.`composer ic:process:all`Alias of `ic:process`.`composer ic:process:refactor`Runs Rector fixes.`composer ic:process:lint`Runs Pint fixes.`composer ic:process:sniff`Runs PHPCBF fixes.`composer ic:process:sniff:fix`Alias of `ic:process:sniff`.### Benchmark Commands

[](#benchmark-commands)

CommandPurpose`composer ic:benchmark`Runs PHPBench aggregate benchmarks.`composer ic:bench:run`Alias of `ic:benchmark`.`composer ic:bench:quick`Runs a shorter PHPBench pass.`composer ic:bench:chart`Runs PHPBench chart report.### Release Commands

[](#release-commands)

CommandPurpose`composer ic:release:audit`Runs Composer audit. Security advisories fail; abandoned packages warn.`composer ic:release:guard`Runs Composer validation, audit, and the full test suite.### Config And Utility Commands

[](#config-and-utility-commands)

CommandPurpose`composer ic:init`Interactively sets up CaptainHook pre-commit and workflow wrappers.`composer ic:init --captainhook`Copies only the CaptainHook pre-commit config.`composer ic:init --workflow --workflow-ref=main`Copies only the GitHub Actions wrapper and points it at the given PHPForge ref.`composer ic:init --gitlab-ci`Copies `.gitlab-ci.yml` starter pipeline.`composer ic:init --bitbucket-ci`Copies `bitbucket-pipelines.yml` starter pipeline.`composer ic:init --forgejo-workflow`Copies `.forgejo/workflows/security-standards.yml` starter workflow.`composer ic:init --community-templates`Copies generic `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, `SECURITY.md`, issue forms/config, and PR template files.`composer ic:init --no-interaction-defaults`Copies default init files without prompting.`composer ic:init --force`Overwrites existing copied files.`composer ic:int`Alias of `composer ic:init`.`composer ic:hooks`Installs enabled CaptainHook hooks.`composer ic:doctor`Shows detected configs, vendor-dir, plugin permissions, hook status, and workflow wrapper validation warnings.`composer ic:doctor --json`Outputs doctor diagnostics as JSON, including workflow wrapper validation details.`composer ic:list-config`Lists config files and their resolution source.`composer ic:list-config --json`Outputs config resolution as JSON.`composer ic:active-config [file...]`Shows the active configs for supported tools, with file selection similar to `ic:publish-config`.`composer ic:active-config --json`Outputs all active config summaries as JSON.`composer ic:active-config phpstan.neon.dist --parameter=cognitive_complexity --json`Filters to one active config file and one parameter/effective key.`composer ic:publish-config [file...]`Copies selected bundled config files into the project.`composer ic:publish-config phpprobe.json --phpprobe-preset=strict`Publishes `phpprobe.json` with a named PHPProbe preset (`default`, `standard`, `ci`, `strict`).`composer ic:publish-config --all`Copies every bundled config file into the project.`composer ic:publish-config --all --force`Overwrites all project config files with bundled defaults.`composer ic:community`Copies generic `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, `SECURITY.md`, issue forms/config, and PR template files into the project.`composer ic:community --force`Overwrites existing community template files with bundled defaults.`composer ic:publish-community-templates`Alias of `composer ic:community`.`composer ic:publish-community-templates --force`Alias of `composer ic:community --force`.`composer ic:clean`Removes known PHPForge output files and cache directories.`composer ic:version`Shows PHPForge, PHP, PHP binary, and vendor-dir information.`composer ic:phpstan:sarif input.json output.sarif`Converts PHPStan JSON output to SARIF 2.1.0.Configuration
-------------

[](#configuration)

Project config files always have priority over PHPForge bundled defaults. For every bundled PHPForge config in `resources/`, lookup is:

1. Project root config, for example `pint.json` or `phpstan.neon.dist`.
2. Installed package config under `vendor/infocyph/phpforge/resources`.
3. PHPForge source-tree `resources/` only when the current project itself is `infocyph/phpforge`.

If none of those exists outside the PHPForge source project, PHPForge fails instead of silently inventing a config path.

ToolLookup OrderPest / PHPUnit`pest.xml`, then `phpunit.xml`, then `pest.xml.dist`, then `phpunit.xml.dist`, then bundled `pest.xml`PHPBench`phpbench.json`, then bundled `phpbench.json`PHPProbe checker tasks`phpprobe.json`, then bundled `phpprobe.json`Deptrac`deptrac.yaml`, then bundled `deptrac.yaml`PHPCS / PHPCBF`phpcs.xml.dist`, then bundled `phpcs.xml.dist`PHPStan`phpstan.neon.dist`, then bundled `phpstan.neon.dist`Pint`pint.json`, then bundled `pint.json`Psalm`psalm.xml`, then bundled `psalm.xml`Rector`rector.php`, then bundled `rector.php`CaptainHook`captainhook.json`, then bundled `captainhook.json`### PHPProbe Checker Config

[](#phpprobe-checker-config)

`phpprobe.json` configures PHPProbe syntax, duplicate-code, API snapshot, and comments checks. PHPProbe 0.3 is preset-first, and PHPForge now follows that model.

Bundled default:

```
{
  "preset": "standard"
}
```

You can still add section overrides (`syntax`, `duplicates`, `api`, `comments`, `commented_out_code`) when a project needs custom thresholds or exclusions.

Presets for `phpprobe.json` publishing:

PresetSummary`default`Raw engine defaults.`standard`Recommended balanced preset.`ci`Quieter CI gate with stricter duplicate thresholds.`strict`Sensitive audit preset across duplicates and comments.`phpstorm`Legacy alias resolved to `standard`.`legacy-standard`Legacy alias resolved to `ci`.```
composer ic:publish-config phpprobe.json --phpprobe-preset=standard
```

### Deptrac Architecture Config

[](#deptrac-architecture-config)

`deptrac.yaml` configures architecture dependency boundaries. The bundled default scans from the project root, excludes the same noisy/generated paths as the other PHPForge configs, and collects project classes through a generic `Project` layer instead of hard-coding a package namespace. Publish it when a project is ready to split that baseline into real domain, package, or framework layers.

```
composer ic:test:architecture
composer ic:publish-config deptrac.yaml
```

Check active config sources:

```
composer ic:list-config
composer ic:list-config --json
composer ic:active-config
composer ic:active-config --json
composer ic:active-config phpcs.xml.dist
composer ic:active-config phpstan.neon.dist --parameter=cognitive_complexity --json
```

When selecting a file, pass the filename directly, for example `composer ic:active-config phpcs.xml.dist`. If you insist on a leading `--` token, Composer requires a separator first: `composer ic:active-config -- --phpcs.xml.dist`.

Publish config only when a project needs custom rules:

```
composer ic:publish-config phpprobe.json pint.json phpstan.neon.dist
composer ic:publish-config --all
```

Supported publishable config files:

```
captainhook.json
deptrac.yaml
pest.xml
phpunit.xml
phpbench.json
phpcs.xml.dist
phpprobe.json
phpstan.neon.dist
pint.json
psalm.xml
rector.php

```

Use `--force` to overwrite existing files:

```
composer ic:publish-config psalm.xml --force
```

Environment Variables
---------------------

[](#environment-variables)

VariableDefaultPurpose`IC_PEST_PROCESSES``10`Controls Pest parallel processes for `ic:tests`.`IC_TEST_CONCURRENCY``3`Controls the maximum concurrently running tools for `ic:tests:parallel`.`PHPFORGE_PARALLEL``3`Alias for `IC_TEST_CONCURRENCY`; useful in generic CI parallelism settings.`PHPFORGE_QUALITY_SUMMARY`noneWrites an aggregate per-tool quality result JSON file for `ic:ci`, `ic:tests`, and `ic:tests:parallel`.`IC_QUALITY_SUMMARY`noneAlias for `PHPFORGE_QUALITY_SUMMARY`.`IC_PHPSTAN_MEMORY_LIMIT``1G`Controls PHPStan memory limit.`IC_PSALM_THREADS``1`Controls Psalm thread count.`IC_HOOKS_STRICT``1`Fails Composer when automatic CaptainHook install fails. Set to `0` for best-effort hook installation.Example:

```
IC_PEST_PROCESSES=4 composer ic:tests
IC_TEST_CONCURRENCY=4 composer ic:tests:parallel
PHPFORGE_QUALITY_SUMMARY=var/quality.json composer ic:ci
IC_PHPSTAN_MEMORY_LIMIT=2G composer ic:test:static
IC_HOOKS_STRICT=0 composer install
```

Git Hooks
---------

[](#git-hooks)

Install the bundled CaptainHook configuration:

```
composer ic:init --captainhook
composer ic:hooks
```

The bundled pre-commit hook runs:

```
composer validate --strict
composer normalize --dry-run
composer ic:release:audit
composer ic:ci
```

This package also has a root `post-autoload-dump` script:

```
"post-autoload-dump": "@php bin/install-captainhook.php"
```

That helper keeps hooks installed for this repository. Consuming projects get automatic hook installation from the PHPForge Composer plugin: it uses project `captainhook.json` when present, otherwise it copies the bundled `captainhook.json` into project root and installs hooks from there.

GitHub Actions
--------------

[](#github-actions)

PHPForge publishes a reusable workflow:

```
uses: infocyph/phpforge/.github/workflows/security-standards.yml@main
```

Install a wrapper workflow into a consuming project:

```
composer ic:init
```

For automated setup, skip prompts and choose the reusable workflow ref:

```
composer ic:init --workflow --workflow-ref=main --no-interaction-defaults
```

Generated wrapper shape:

```
name: "Security & Standards"

on:
  schedule:
    - cron: "0 0 * * 0"
  push:
    branches: [ "main", "master" ]
  pull_request:
    branches: [ "main", "master", "develop", "development" ]

jobs:
  phpforge:
    uses: infocyph/phpforge/.github/workflows/security-standards.yml@main
    permissions:
      security-events: write
      actions: read
      contents: read
    with:
      php_versions: '["8.2","8.3","8.4","8.5"]'
      dependency_versions: '["prefer-lowest","prefer-stable"]'
      php_extensions: ""
      composer_flags: ""
      phpstan_memory_limit: "1G"
      psalm_threads: "1"
      run_analysis: true
      run_svg_report: true
      fail_on_skipped_tests: false
      enable_redis_service: false
      enable_valkey_service: false
      enable_memcached_service: false
      enable_postgres_service: false
      enable_mysql_service: false
      enable_scylladb_service: false
      enable_elasticsearch_service: false
      enable_mongodb_service: false
      service_db_name: "phpforge"
      service_db_user: "phpforge"
      service_db_password: "phpforge"
      artifact_retention_days: 61
```

Workflow inputs:

InputDefaultPurpose`php_versions``["8.2","8.3","8.4","8.5"]`PHP matrix as a JSON array string.`dependency_versions``["prefer-lowest","prefer-stable"]`Composer dependency modes as a JSON array string.`php_extensions``""`Comma-separated PHP extensions passed to `shivammathur/setup-php`.`composer_flags``""`Extra flags appended to Composer install/update commands.`phpstan_memory_limit``1G`PHPStan memory limit used by workflow analysis.`psalm_threads``1`Psalm thread count used by workflow analysis.`run_analysis``true`Runs SARIF upload jobs for PHPStan and Psalm. Set to `false` for CI-only runs.`run_svg_report``true`Generates `security-report.svg` and `security-summary.json` with per-version matrix results, per-version benchmark timings/trends, and tool versions.`fail_on_skipped_tests``false`Adds `--fail-on-skipped` to Pest execution so skipped tests fail the CI test job.`enable_redis_service``false`Starts a Redis service container and waits for readiness before running test commands.`enable_valkey_service``false`Starts a Valkey service container and waits for readiness before running test commands.`enable_memcached_service``false`Starts a Memcached service container and waits for readiness before running test commands.`enable_postgres_service``false`Starts a PostgreSQL service container and waits for readiness before running test commands.`enable_mysql_service``false`Starts a MySQL service container and waits for readiness before running test commands.`enable_scylladb_service``false`Starts a ScyllaDB Alternator service container and waits for readiness before running test commands.`enable_elasticsearch_service``false`Starts an Elasticsearch service container and waits for readiness before running test commands.`enable_mongodb_service``false`Starts a MongoDB service container and waits for readiness before running test commands.`service_db_name``phpforge`Shared database name for PostgreSQL/MySQL/MongoDB service containers.`service_db_user``phpforge`Shared username reused across service containers and exported client env vars.`service_db_password``phpforge`Shared password reused across service containers and exported client env vars.`artifact_retention_days``61`Artifact retention days for uploaded `security-report` artifacts.### Workflow Input Details

[](#workflow-input-details)

`php_versions` must be a JSON array string because reusable workflow inputs are strings:

```
with:
  php_versions: '["8.2","8.3","8.4","8.5"]'
```

Use a smaller matrix for faster daily CI, or the full supported range for release confidence.

`dependency_versions` controls Composer update mode:

```
with:
  dependency_versions: '["prefer-stable"]'
```

For release confidence, keep both modes:

```
with:
  dependency_versions: '["prefer-lowest","prefer-stable"]'
```

Normal workflow workers run `composer ic:ci`, which delegates to the same bounded parallel runner as `ic:tests:parallel`. The CI path uses `phpprobe comments --ci`, so comment-policy output stays error-focused in workflow logs. When the matrix entry is `prefer-lowest`, PHPForge still runs `composer ic:ci --prefer-lowest`, skipping heavyweight PHPStan and Psalm checks for that dependency edge.

`php_extensions` is passed to `shivammathur/setup-php`:

```
with:
  php_extensions: "mbstring, intl, bcmath, pdo_mysql, pdo_pgsql"
```

When `apcu` is included in `php_extensions`, the reusable workflow automatically enables APCu for CLI (`apc.enable_cli=1`, `apcu.enable_cli=1`) so APCu-backed tests can run in CI.

Leave it empty when no extra extensions are needed:

```
with:
  php_extensions: ""
```

`composer_flags` appends extra flags to Composer install/update:

```
with:
  composer_flags: "--ignore-platform-req=ext-redis"
```

Multiple flags can be passed as one string:

```
with:
  composer_flags: "--ignore-platform-req=ext-redis --with-all-dependencies"
```

`phpstan_memory_limit` controls PHPStan memory in both quality gates and SARIF generation:

```
with:
  phpstan_memory_limit: "2G"
```

`psalm_threads` controls Psalm parallelism:

```
with:
  psalm_threads: "2"
```

Optional integration services are disabled by default:

```
with:
  enable_redis_service: true
  enable_valkey_service: false
  enable_memcached_service: true
  enable_postgres_service: true
  enable_mysql_service: false
  enable_scylladb_service: true
  enable_elasticsearch_service: true
  enable_mongodb_service: true
  service_db_name: "cachelayer"
  service_db_user: "phpforge"
  service_db_password: "phpforge"
```

When a service is enabled, the workflow exports these environment variables in the `run` job:

- `IC_REDIS_HOST`, `IC_REDIS_PORT`, `IC_REDIS_PASSWORD`
- `IC_VALKEY_HOST`, `IC_VALKEY_PORT`, `IC_VALKEY_PASSWORD`
- `IC_SERVICE_DATABASE`, `IC_SERVICE_USERNAME`, `IC_SERVICE_PASSWORD`
- `IC_MEMCACHED_HOST`, `IC_MEMCACHED_PORT`
- `IC_POSTGRES_DSN`, `IC_POSTGRES_USER`, `IC_POSTGRES_PASSWORD`
- `IC_MYSQL_DSN`, `IC_MYSQL_USER`, `IC_MYSQL_PASSWORD`
- `IC_SCYLLADB_HOST`, `IC_SCYLLADB_PORT`, `IC_SCYLLADB_ENDPOINT`, `IC_SCYLLADB_REGION`, `IC_SCYLLADB_ACCESS_KEY_ID`, `IC_SCYLLADB_SECRET_ACCESS_KEY`
- `IC_ELASTICSEARCH_HOST`, `IC_ELASTICSEARCH_PORT`, `IC_ELASTICSEARCH_URL`
- `IC_MONGODB_HOST`, `IC_MONGODB_PORT`, `IC_MONGODB_DSN`

`run_analysis` controls the SARIF upload job:

```
with:
  run_analysis: false
```

Set it to `false` when the repository does not use GitHub code scanning, does not grant `security-events: write`, or wants CI-only runs.

`run_svg_report` controls the SVG reporting artifact job:

```
with:
  run_svg_report: true
```

`fail_on_skipped_tests` makes skipped Pest tests fail CI:

```
with:
  fail_on_skipped_tests: true
```

`artifact_retention_days` controls how long uploaded report artifacts are kept:

```
with:
  artifact_retention_days: 61
```

Set a shorter value for active development branches or a longer value for scheduled/release runs.

When enabled on `main` or `master`, the workflow uploads one artifact:

- `security-report` (contains `security-report.svg` and `security-summary.json`)

`security-summary.json` includes:

- `tested_php_versions`
- `matrix_results` (per PHP version: `code_analysis_prefer_lowest`, `code_analysis_prefer_stable`, `security_analysis`)
- `check_results` (flat per-check rows with `test`, `dependency_mode`, `php_version`, `status`, `source_job`, `generated_by`)
- `benchmark_results` (per PHP version benchmark rows with `duration_ms`, `delta_ms`, `trend`, `status`, source job metadata, and metric provenance via `benchmark_metric_ns` / `benchmark_metric_source`)
- `rollup` (aggregated status for `code_analysis_prefer_lowest`, `code_analysis_prefer_stable`, `security_analysis`, `benchmark`)
- `benchmark_command`
- `benchmark_job_result`
- `tools` (tool `name`, package, resolved version)

`security-report.svg` renders the same high-level status, per-version matrix check results, rollup quality gates (`Code Lowest`, `Code Stable`, `Security`, `Benchmark`), a benchmark-by-version chart with upgrade/degrade trend labels, and resolved tool versions.

### Workflow Examples

[](#workflow-examples)

Fast CI for active development:

```
jobs:
  phpforge:
    uses: infocyph/phpforge/.github/workflows/security-standards.yml@main
    with:
      php_versions: '["8.4","8.5"]'
      dependency_versions: '["prefer-stable"]'
      run_analysis: false
      run_svg_report: true
```

Release confidence matrix:

```
jobs:
  phpforge:
    uses: infocyph/phpforge/.github/workflows/security-standards.yml@main
    permissions:
      security-events: write
      actions: read
      contents: read
    with:
      php_versions: '["8.2","8.3","8.4","8.5"]'
      dependency_versions: '["prefer-lowest","prefer-stable"]'
      run_analysis: true
```

Project with extensions and no SARIF upload:

```
jobs:
  phpforge:
    uses: infocyph/phpforge/.github/workflows/security-standards.yml@main
    with:
      php_versions: '["8.2","8.3"]'
      php_extensions: "mbstring, intl, pdo_mysql"
      composer_flags: "--ignore-platform-req=ext-redis"
      run_analysis: false
      run_svg_report: true
```

Project with cache/database service containers for integration tests:

```
jobs:
  phpforge:
    uses: infocyph/phpforge/.github/workflows/security-standards.yml@main
    with:
      php_versions: '["8.4","8.5"]'
      dependency_versions: '["prefer-lowest","prefer-stable"]'
      php_extensions: "mbstring, redis, memcached, pdo_pgsql, pdo_mysql, mongodb"
      enable_redis_service: true
      enable_valkey_service: false
      enable_memcached_service: true
      enable_postgres_service: true
      enable_mysql_service: true
      enable_scylladb_service: true
      enable_elasticsearch_service: true
      enable_mongodb_service: true
      service_db_name: "cachelayer"
      service_db_user: "phpforge"
      service_db_password: "phpforge"
```

Project with extensions and larger analysis limits:

```
jobs:
  phpforge:
    uses: infocyph/phpforge/.github/workflows/security-standards.yml@main
    permissions:
      security-events: write
      actions: read
      contents: read
    with:
      php_versions: '["8.2","8.3"]'
      dependency_versions: '["prefer-stable"]'
      php_extensions: "mbstring, intl, bcmath, pdo_mysql"
      composer_flags: "--ignore-platform-req=ext-redis"
      phpstan_memory_limit: "2G"
      psalm_threads: "2"
      run_analysis: true
```

For code scanning, project-local PHPStan configs (`phpstan.neon`, then `phpstan.neon.dist`) and Psalm configs (`psalm.xml`, then `psalm.xml.dist`) are used when present; otherwise the workflow falls back to PHPForge defaults.

Other CI Platforms
------------------

[](#other-ci-platforms)

Generate starter CI files with `ic:init`:

```
composer ic:init --gitlab-ci
composer ic:init --bitbucket-ci
composer ic:init --forgejo-workflow
```

Generated files:

- `.gitlab-ci.yml` (GitLab CI)
- `bitbucket-pipelines.yml` (Bitbucket Pipelines)
- `.forgejo/workflows/security-standards.yml` (Forgejo Actions)

Each template installs dependencies and runs:

```
composer ic:ci
```

Generate community templates for contributing and issue triage:

```
composer ic:community
```

Generated files:

- `CONTRIBUTING.md`
- `CODE_OF_CONDUCT.md`
- `SECURITY.md`
- `.github/ISSUE_TEMPLATE/bug_report.yml`
- `.github/ISSUE_TEMPLATE/regression_report.yml`
- `.github/ISSUE_TEMPLATE/ci_failure.yml`
- `.github/ISSUE_TEMPLATE/feature_request.yml`
- `.github/ISSUE_TEMPLATE/question.yml`
- `.github/ISSUE_TEMPLATE/docs_improvement.yml`
- `.github/ISSUE_TEMPLATE/config.yml`
- `.github/PULL_REQUEST_TEMPLATE.md`

Migration Guide
---------------

[](#migration-guide)

Replace individual QA dependencies with PHPForge.

Before:

```
"require-dev": {
    "captainhook/captainhook": "^5.29.2",
    "ergebnis/composer-normalize": "^2.51",
    "laravel/pint": "^1.29",
    "pestphp/pest": "^4.6.3",
    "pestphp/pest-plugin-drift": "^4.1",
    "phpbench/phpbench": "^1.6.1",
    "phpstan/phpstan": "^2.1.50",
    "rector/rector": "^2.4.2",
    "squizlabs/php_codesniffer": "^4.0.1",
    "symfony/var-dumper": "^7.3 || ^8.0.8",
    "tomasvotruba/cognitive-complexity": "^1.1",
    "vimeo/psalm": "^6.16.1"
}
```

After:

```
"require-dev": {
    "infocyph/phpforge": "dev-main"
}
```

Remove old local QA scripts such as:

```
test:*
process:*
bench:*
tests
process
benchmark
release:audit
release:guard
post-autoload-dump

```

Replace commands:

Old commandNew command`composer tests` / `composer test:all``composer ic:tests``composer test:details``composer ic:tests:details``composer test:syntax``composer ic:test:syntax``composer test:code``composer ic:test:code``composer test:lint``composer ic:test:lint``composer test:sniff``composer ic:test:sniff``composer test:duplicates``composer ic:test:duplicates``composer test:static``composer ic:test:static``composer test:security``composer ic:test:security``composer test:refactor``composer ic:test:refactor``composer process` / `composer process:all``composer ic:process``composer process:lint``composer ic:process:lint``composer process:sniff:fix``composer ic:process:sniff:fix``composer process:refactor``composer ic:process:refactor``composer benchmark` / `composer bench:run``composer ic:benchmark``composer bench:quick``composer ic:bench:quick``composer bench:chart``composer ic:bench:chart``composer release:audit``composer ic:release:audit``composer release:guard``composer ic:release:guard`Old helper scripts are no longer needed:

```
.github/scripts/syntax.php
.github/scripts/composer-audit-guard.php
.github/scripts/phpstan-sarif.php

```

PHPForge provides those through:

```
composer ic:test:syntax
composer ic:test:duplicates
composer ic:release:audit
composer ic:phpstan:sarif phpstan-results.json phpstan-results.sarif
```

Troubleshooting
---------------

[](#troubleshooting)

### `There are no commands defined in the "ic" namespace`

[](#there-are-no-commands-defined-in-the-ic-namespace)

The plugin is not active. Enable plugin permissions and reinstall:

```
composer config allow-plugins.infocyph/phpforge true
composer install
```

### CaptainHook install fails during Composer install

[](#captainhook-install-fails-during-composer-install)

By default hook installation is strict. To make it best-effort:

```
IC_HOOKS_STRICT=0 composer install
```

Then inspect manually:

```
composer ic:doctor
composer ic:hooks
```

### GitHub code scanning upload fails

[](#github-code-scanning-upload-fails)

Set `run_analysis: false` in the workflow wrapper if the repository does not have SARIF upload permission:

```
with:
  run_analysis: false
```

### SVG report artifact is missing

[](#svg-report-artifact-is-missing)

Ensure `run_svg_report: true` is present in the workflow wrapper:

```
with:
  run_svg_report: true
```

Then open the workflow run and download `security-report`.

### A bundled rule is too strict

[](#a-bundled-rule-is-too-strict)

Publish the relevant config and edit it in the project:

```
composer ic:publish-config phpprobe.json
composer ic:publish-config phpstan.neon.dist
composer ic:publish-config psalm.xml
```

Project config files always take priority over bundled defaults. For syntax or duplicate detector noise, adjust `phpprobe.json` paths/excludes or duplicate thresholds first.

###  Health Score

29

—

LowBetter than 57% of packages

Maintenance64

Regular maintenance activity

Popularity22

Limited adoption so far

Community17

Small or concentrated contributor base

Maturity13

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://www.gravatar.com/avatar/33b750b84ab22f2038ef9b90ee48f2fcdaab6b5698e9f956a89a152466200b63?d=identicon)[abmmhasan](/maintainers/abmmhasan)

---

Top Contributors

[![abmmhasan](https://avatars.githubusercontent.com/u/7711128?v=4)](https://github.com/abmmhasan "abmmhasan (346 commits)")

### Embed Badge

![Health badge](/badges/infocyph-phpforge/health.svg)

```
[![Health](https://phpackages.com/badges/infocyph-phpforge/health.svg)](https://phpackages.com/packages/infocyph-phpforge)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
