pilotphp/config

Deterministic compiled configuration for the PilotPHP Agent-First framework.

Maintainers

Package info

gitlab.com/pilotphp/config

Issues

pkg:composer/pilotphp/config

Transparency log

Statistics

Installs: 27

Dependents: 1

Suggesters: 0

Stars: 0

0.1.4 2026-08-02 19:19 UTC

This package is auto-updated.

Last update: 2026-08-02 16:21:50 UTC


README

Deterministic compiled configuration for the PilotPHP Agent-First framework.

Configuration is assembled and compiled before requests are served. In the worker, reading a value is one hash lookup — no file access, no environment access, no merging.

Installation

composer require pilotphp/config

Requires PHP 8.5 and pilotphp/contracts (0.1.4 Build SPI line).

What it does

  • Registers ConfigBuildStage through ConfigPackage
  • Loads configuration from trusted PHP files, directories, and typed declarations
  • Merges ordered layers deterministically, refusing ambiguity
  • Keeps external values (secrets, environment) as unresolved references
  • Compiles to a byte-reproducible PHP artifact with a SHA-256 fingerprint
  • Serves an immutable, typed ConfigInterface at runtime

What it does not do

No DI container, kernel, runtime loop, RoadRunner, gRPC, HTTP, ORM, Blueprint, console commands, .env parsing, YAML/XML, secret-provider implementations, or Composer package scanning. Each belongs to its own package — see docs/architecture.md.

It also does not own build orchestration, the shared build fingerprint, the build cache, locks, or atomic publication. Those belong to pilotphp/build.

Lifecycle

active ConfigPackage → registration → immutable replay
  → ConfigBuildStage → config artifact → runtime loader

Production pipeline

Build tooling activates pilotphp/config and runs the universal build. ConfigBuildStage prepares from replayed declarations and writes config/compiled.php through ArtifactWriterInterface.

Worker boot

use PilotPHP\Config\Compiler\CompiledConfigLoader;
use PilotPHP\Config\Runtime\ImmutableConfig;
use PilotPHP\Config\Value\{ConfigValueResolver, EnvironmentValueResolver};

$payload = new CompiledConfigLoader()->load($explicitArtifactPath);

$resolved = new ConfigValueResolver([
    new EnvironmentValueResolver($environment),
])->resolve($payload->data());

$config = new ImmutableConfig($resolved);

The loader reads only that artifact. It does not compile, scan source directories, or resolve environment placeholders.

Development / standalone usage

use PilotPHP\Config\Build\{ConfigBuilder, ConfigLayer, ConfigLayerKind};
use PilotPHP\Config\Compiler\PhpConfigCompiler;
use PilotPHP\Config\Source\PhpFileConfigSource;

$result = new ConfigBuilder()
    ->addLayer(new ConfigLayer(
        id: 'framework',
        kind: ConfigLayerKind::FrameworkDefaults,
        data: ['app' => ['name' => 'unnamed', 'workers' => 1]],
    ))
    ->addSource(new PhpFileConfigSource(
        path: __DIR__ . '/config/app.php',
        id: 'application',
        kind: ConfigLayerKind::Application,
    ))
    ->build();

new PhpConfigCompiler()->compile($result, __DIR__ . '/var/cache/config.php');

Layers

KindValuePurpose
FrameworkDefaults100framework baseline
PackageDefaults200installed packages' defaults
Application300the application's own config
Environment400per-deployment overrides
Runtime500programmatic overrides, applied last

Sorted by kind, then order, then layer id — a total ordering, so the result never depends on the order sources were added.

Merging

Maps merge recursively; lists are replaced wholesale; a scalar replaces a scalar of the same type. Anything ambiguous is refused and must be stated explicitly via ConfigMerge::{append,prepend,replace,remove}(). Full table: docs/merge-semantics.md.

Environment references

use PilotPHP\Config\Value\{DeferredValue, DeferredValueType};

return [
    'database' => [
        'host'     => DeferredValue::environment('DB_HOST', default: 'localhost'),
        'password' => DeferredValue::environment('DB_PASSWORD', required: true),
    ],
];

These stay unresolved through merging, fingerprinting, and compilation. Values obtained by a DeferredValueResolver never reach the build result, fingerprint, or compiled artifact. Application boot injects an environment map into EnvironmentValueResolver — the package never calls getenv() / $_ENV / $_SERVER.

Package defaults

$registration->add(new ConfigDefaultsDeclaration(
    prefix: 'grpc',
    path: 'config/default.php',
));

Composition also supplies ConfigPackageRootsDeclaration so the stage can resolve those paths without discovering packages. In-memory overlays use ConfigFragmentDeclaration. See docs/package-integration.md.

Documentation

DocumentContents
architecture.mdPipeline, boundaries, trust model
public-api.mdPublic vs internal types
compatibility.mdSemVer and machine-readable contracts
merge-semantics.mdComplete merge table
deferred-values.mdProviders and secret safety
compilation.mdDeterministic artifacts
package-integration.mdPackage defaults
security.mdThreat model and secret policy
build-integration.mdConfigBuildStage and Build SPI
migration.mdConsumer migration notes
AGENTS.mdRules for changing this package

Repository

A standalone Git repository and Composer package. PilotPHP has no monorepo; every package is its own repository.