ADR 0005: Keep runtime modules inside the root Composer package
- Status: accepted
- Date: 2026-08-21
- Decision owners: k0smos maintainers
Context
The P8 backlog asked whether every runtime module should receive its own
composer.json. Possible goals were independent publishing, explicit dependency
metadata, split-repository readiness, contributor tooling, or metadata alone.
K0smos is not published, has no external module consumer, discovers modules
from co-located Config/module.php descriptors, and deploys one application.
An executable inventory found 41 module descriptors, 18 direct module-to-module reference pairs, and 20 core-to-runtime-module reference pairs. Templates, migrations, service arrays, translations, assets, tenant activation, and root commands also assume the monorepo layout. Tax (dependency-light) and Documentation (consumer of core search/vector/template contracts) were selected as representative pilots.
Composer repositories are configured by the root package; repository entries inside dependencies are not inherited. Path repositories can symlink or mirror directories, but they would still require the root to declare and require every package. Introducing pilot packages without a consumer would therefore add a second dependency graph without proving independent installability.
Decision
Do not add per-module Composer packages now.
- Production and development use one root
composer.json, lock file,vendor/directory, and optimized autoloader. - Every discovered module namespace has an explicit root PSR-4 mapping. The evaluation corrected missing mappings for Cart, Esapi, Psapi, and Wpapi.
modules/{Name}/src/Config/module.phpremains the authoritative lightweight module manifest for identity, ordering, default state, and runtime dependencies.- Nested
composer.jsonfiles and module-localvendor/directories are not allowed until a package consumer and extraction contract exist. tools/architecture/module-boundary-inventory.phprecords current split blockers instead of pretending current module directories are independent.
No path repository or two-package install pilot is committed: the mandatory goal gate failed before package creation. The Tax/Documentation pilot instead proved both shapes remain discoverable, optional, dependency-free at runtime, and fully owned by the root autoloader.
Consequences
The root install stays deterministic across Linux, macOS, Windows, mirrors, and archives, with no duplicate class ownership or nested vendor trees. Composer metadata is not used as aspirational architecture documentation; current cross-boundary coupling remains visible and can be reduced through core contracts.
Re-evaluate only when at least one of these exists:
- a named external repository/application must install a module independently;
- a split-repository release pipeline and versioning owner are approved;
- a module needs an optional dependency that the root cannot reasonably carry;
- CI timing data shows a module package boundary materially improves a tested contributor workflow.
The future pilot must package one leaf and one core-contract consumer, define dist contents for templates/migrations/assets/translations, use root-declared path repositories, test symlink and mirror modes, install from a clean lock, and prove the package contains no reference to another runtime module unless that package is declared explicitly.
References
- Composer repositories and root-only repository declarations: https://getcomposer.org/doc/05-repositories.md
- Composer path repository options: https://getcomposer.org/doc/05-repositories.md#path
- Composer PSR-4/classmap schema: https://getcomposer.org/doc/04-schema.md#autoload
- Inventory and detailed evidence:
doc/public/en/architecture/evaluations/module-packaging.md