# Ivory
Ivory is a cross-platform CLI tool that manages local PHP runtimes and runs Composer and PHP scripts in a consistent, project-aware way.
It lets you:
~/.ivoryivory.json project configivory.json and run them easilyivory doctor)ivory.json)iv initiv installiv listiv phpiv runiv scriptsiv useiv defaultiv composeriv isolateiv scaffold:ciiv scaffold:dockeriv completioniv doctor~/.ivory/versions/<platform>/<version>~/.ivory/php-versions.json) to know where to download PHP fromiv install 8.3 etc.If a command resolves to a non-system PHP version that isn't installed yet, Ivory will install it automatically before running your command.
Project-aware PHP selection
.ivory.php-versionivory defaultFalls back to system php when appropriate
Project configuration with ivory.json
php.version, extra INI and CLI argsFramework presets (Generic, Laravel, Symfony) via ivory init
Composer integration
composer.pharCan run Composer scripts through your configured PHP toolchain
Nice DX
System.CommandLine for a clean CLIivory doctor to show what Ivory sees (PHP, Composer, config, etc.)public/index.php that tries to load vendor/autoload.php.ivory/php) to keep ini overrides localDownloads come from the latest release at https://github.com/rizwan3d/Ivory/releases/latest/download/<platform-archive>.
# Linux (x64)
bash <(curl -fsSL https://raw.githubusercontent.com/rizwan3d/Ivory/refs/heads/master/install/linux.sh)
# macOS (arm64 or x64)
bash <(curl -fsSL https://raw.githubusercontent.com/rizwan3d/Ivory/refs/heads/master/install/mac.sh)
# Windows (PowerShell 5+; AMD64 or ARM64)
powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -Command "irm https://raw.githubusercontent.com/rizwan3d/Ivory/refs/heads/master/install/windows.ps1 | iex"
The installers place ivory under a user-scoped bin directory (~/.ivory/bin on Unix, %LOCALAPPDATA%\Ivory\bin on Windows) and add it to PATH.
# Linux/macOS
bash <(curl -fsSL https://raw.githubusercontent.com/rizwan3d/Ivory/refs/heads/master/install/uninstall.sh)
# Windows (PowerShell 5+)
powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -Command "irm https://raw.githubusercontent.com/rizwan3d/Ivory/refs/heads/master/install/uninstall.ps1 | iex"
ivory.json)Ivory looks for a ivory.json starting from the current directory and walking up parent directories.
ivory.json{
"php": {
"version": "8.3",
"ini": [
"memory_limit=512M"
],
"args": [
"-d", "date.timezone=UTC"
]
},
"scripts": {
"serve": {
"description": "Run PHP built-in server",
"phpFile": "-S",
"phpArgs": [
"localhost:8000",
"public/index.php"
],
"args": []
},
"console": {
"description": "Run framework console",
"phpFile": "bin/console",
"phpArgs": [],
"args": []
}
}
}
php
version (string, optional) - preferred PHP version for this project (e.g. "8.3" or "latest").
ini (array of string) - extra -d INI settings to pass to PHP.args (array of string) - extra arguments always passed to PHP.
scripts (object)
keys = script names (e.g. "serve", "test", "console").
values = IvoryScript:
description (string, optional) – human-readable description.phpFile (string, required) – the PHP entry file or command (e.g. "public/index.php", "bin/console", "-S").phpArgs (array of string, optional) – arguments placed before the phpFile or used as raw PHP arguments.args (array of string, optional) – additional arguments appended after phpFile / phpArgs.Internally, these are represented by IvoryConfig and IvoryConfig.IvoryScript in Ivory.Domain.Config.
iv initCreate a starter ivory.json for the current project and scaffold public/index.php if it doesn’t exist.
iv init [--framework <Generic|Laravel|Symfony>] [--php <version>] [--force]
--framework – choose a preset (Generic, Laravel, Symfony).--php – default PHP version to write into ivory.json.--force – overwrite an existing ivory.json.This uses IPhpVersionResolver, IvoryConfigSerializer and IPublicIndexScaffolder under the hood.
ivory installInstall a PHP runtime for the current platform.
iv install <version>
Examples:
iv install 8.3
iv install 8.2
This calls IPhpInstaller.InstallAsync, which:
~/.ivory/php-versions.json (PhpVersionsManifest).~/.ivory/versions/<platform>/<version>.ivory list / ivory lsList installed PHP versions:
iv list
# or
iv ls
Uses IPhpInstaller.ListInstalledAsync() and prints out versions in order.
ivory phpRun php through Ivory with a specific PHP version (or project/global default).
iv php [--php <version>] [--] [args...]
Examples:
iv php -- -v
iv php --php 8.3 -- -v
iv php --php 8.3 -- -r "echo 'Hello from Ivory';"
This calls IPhpRuntimeService.RunPhpAsync with null script path and just forwards your arguments.
ivory runRun a named script from ivory.json or a direct PHP file.
iv run <script-or-file> [--php <version>] [--] [extra-args...]
Behavior:
ivory.json via IProjectConfigProvider.If <script-or-file> matches a script name in scripts, it:
Builds the PHP command from php, phpFile, phpArgs, and args.
<script-or-file> as a path to a PHP file relative to the current directory.Examples:
iv run serve
iv run console -- migrate
iv run public/index.php --php 8.3
ivory scriptsList available scripts from ivory.json:
iv scripts
Shows:
ivory useSet the project-local PHP version by writing .ivory.php-version in the current directory:
iv use <version>
Example:
iv use 8.3
Ivory will prefer this version when running commands inside this project directory.
ivory defaultSet the default / global PHP version (e.g. stored in ~/.ivory/config.json or equivalent):
iv default <version>
Example:
iv default 8.2
Used when there is no .ivory.php-version and no php.version in ivory.json.
ivory composerRun Composer through Ivory.
iv composer [--php <version>] [--] [args...]
Examples:
iv composer install
iv composer update
iv composer run-script test
iv composer --php 8.3 -- install
Internally, IComposerService:
composer.json and project root.composer.phar is available (downloading if needed).IPhpRuntimeService to run php composer.phar <args> with the chosen PHP version.ivory isolateCreate a per-project PHP home in .ivory/php/ with its own php.ini and conf.d/ directory for extension ini files.
iv isolate
After running this once in a project, Ivory will automatically set PHPRC and PHP_INI_SCAN_DIR to use your local php.ini and conf.d/ when executing PHP/Composer through Ivory, keeping settings and extensions from bleeding across projects.
ivory scaffold:ciGenerate CI templates wired to Ivory for GitHub Actions or GitLab CI.
iv scaffold:ci # GitHub by default
iv scaffold:ci --target gitlab
iv scaffold:ci --target both --force
Creates .github/workflows/ivory-ci.yml and/or .gitlab-ci.yml running dotnet build plus a Ivory doctor + PHP version check.
.ivory.php-version → ivory.json php.version → global default); when resolution is system, the workflow pins 8.3 so CI has a concrete PHP tag.--force to overwrite existing files.ivory scaffold:dockerGenerate a Dockerfile and docker-compose.yml using the resolved PHP version.
iv scaffold:docker
Produces a simple Dockerfile (php:<version>-cli) and docker-compose.yml exposing port 8000; extend to install needed PHP extensions.</version>
system, Ivory pins 8.3 for the Docker base image.--force to overwrite existing Dockerfile / docker-compose.yml.ivory completionGenerate a shell completion script (bash, zsh, fish, PowerShell) that includes commands, ivory.json script names, and PHP versions/aliases from your manifest.
iv completion bash # bash
iv completion zsh # zsh
iv completion fish # fish
iv completion powershell
Tip: source <(ivory completion bash) or add to your shell init file.
ivory doctorInspect environment and show what Ivory sees:
iv doctor
Typical output includes:
PlatformId)~/.ivory layout (versions, cache, manifest path)composer.phar and system composerivory.json was found and where.ivory/php/php.ini and conf.d if present)This uses:
IEnvironmentProbe to find system php/composerIPhpInstaller to inspect installed versionsIComposerService to locate ComposerIProjectConfigProvider to find ivory.jsonIvory stores its own data under:
~/.ivory/
php-versions.json # PhpVersionsManifest (download sources & checksums)
versions/ # Installed PHP runtimes, per platform/version
cache/php/ # Download cache for PHP archives
config.json # Global config (e.g. default PHP version)
Per-project data:
ivory.json – project configuration (PHP + scripts)..ivory.php-version – per-project PHP version pin.