Plugins

Composer plugins are PHP code that hooks into Composer's own process; viv has no PHP runtime, so it can't run one as written. Instead:

The full list of which plugin falls into which category is documented separately.

Inventory

Plugins found in the lock files available on 2026-09-06 (four public projects, the Laravel benchmark lock, two test fixtures and one private WordPress project):

Plugin What it changes Portable?
composer/installers Install path per package type from extra.installer-paths Native (src/plugins/installers.rs), pure path mapping
johnpbloch/wordpress-core-installer Install path of wordpress-core packages from extra.wordpress-install-dir Native (src/plugins/wordpress_core.rs), pure path mapping
dealerdirect/phpcodesniffer-composer-installer Points phpcs's installed_paths at every installed standard Native (src/plugins/phpcs.rs); writes CodeSniffer.conf directly rather than shelling out to phpcs --config-set, so an install needs no PHP runtime (#218)
phpstan/extension-installer Writes GeneratedConfig.php listing every extra.phpstan package Native (src/plugins/phpstan.rs)
php-http/discovery Adds packages to the resolver and generates a discovery file Native (src/plugins/discovery.rs), preAutoloadDump/extra.discovery only; the resolver half (postUpdate) isn't ported
tbachert/spi Generates a service-provider map file after autoload dump Native (src/plugins/spi.rs), extra.spi only
cweagans/composer-patches Applies patches from extra.patches/a patches file Native (src/plugins/patches.rs), git-apply path only (#53)
yiisoft/yii2-composer Writes vendor/yiisoft/extensions.php listing every yii2-extension package Native (src/plugins/yii2.rs) (#92)
craftcms/plugin-installer Writes vendor/craftcms/plugins.php listing every craft-plugin package Native (src/plugins/craft.rs) (#92)
pestphp/pest-plugin Writes vendor/pest-plugins.json listing every package's extra.pest.plugins, root last Native (src/plugins/pest.rs) (#131)
ffraenz/private-composer-installer Substitutes {%NAME}/{%version} placeholders in a dist URL from the environment/.env right before download Native (src/plugins/private_installer.rs) (#98)
codeception/c3 Copies its bundled c3.php into the project root on install/update, unless an existing, edited one is there Native (src/plugins/c3.rs) (#126)
drupal/core-composer-scaffold Copies scaffold files (index.php, .htaccess, settings.php, …) from every allowed package, manages .gitignore, writes vendor/drupal/DrupalInstalled.php and points the root classmap at it Native (src/plugins/drupal_scaffold.rs) (#93)
drupal/core-project-message Prints a message to stdout after create-project/install, no filesystem effect Known inert — Composer prints a message viv does not
drupal/core-recipe-unpack Unpacks a required drupal-recipe package's own dependencies into the root composer.json Known inert for install/update — only subscribes to POST_UPDATE_CMD/POST_CREATE_PROJECT_CMD (via composer require/create-project), never plain install
symfony/runtime Writes vendor/autoload_runtime.php from a fixed template plus extra.runtime options, after autoload dump Native (src/plugins/symfony_runtime.rs) (#93)

Plugins named in issue #12 but not seen in any lock yet: symfony/flex (rewrites composer.json and recipes, not portable), bamarni/composer-bin-plugin (nested installs, portable by running viv in each vendor-bin/*).

Rule

For every package of type composer-plugin in the lock that is enabled by config.allow-plugins:

  1. Native adapter exists: viv applies the equivalent behaviour itself. Output must be byte-identical to Composer running the real plugin.
  2. Known inert: the plugin only affects Composer's own commands that viv does not implement (for example ergebnis/composer-normalize). viv ignores it silently. The list lives in code.
  3. Anything else: viv refuses with an error naming the plugin and pointing at this page. --no-plugins turns the refusal into a warning and installs as Composer would with --no-plugins. Silent wrong installs are worse than a loud stop. The refusal also says whether --no-plugins is safe: plugins in BY_DESIGN_REFUSALS (src/plugins/mod.rs) get "by design, you lose nothing" with the one-clause reason from this page; everything else gets the generic "not adapted yet, this skips real work" (#224).

Plugins that allow-plugins sets to false, or that are absent from the map, are ignored, as Composer ignores them.