Changelog¶
Find below the changelog for Castor, listing all notable changes made to the project on each version.
Not released yet¶
Features¶
- Add
self-updatecommand to update Castor to the latest version - Publish a
snapshotpre-release of themainbranch on each push, installable with the installer--version=snapshotoption orcastor self-update --snapshot - Phars and static binaries built from a commit that is not a release now report a snapshot version, like
v1.7.0-14-g4531440 - Add a
withTrappedSignals()method on the context, to forward the signals received by Castor (like theSIGINTof aCTRL+C) to the process being run, instead of interrupting Castor itself - Publish a static binary for Windows and support
--os=windowsincastor:compile - Allow
mount()to mount a remote Composer package (mount('composer://org/repo')), likeimport()already did, with its own namespace prefix and working directory
Security¶
- Publish artifact attestations for the phars and static binaries, and verify them in the installer, in
self-updateand incastor:repackwhen the GitHub CLI is installed and authenticated - Restrict the file name chosen by the server in
http_download(): only the last segment of theContent-Dispositionfile name (or of the URL path) is kept, so the download always lands in the project directory - Never download the remote packages during a shell completion: the packages already installed are used, and the completion goes on without the remote imports when there is none
- Publish a
SHA256SUMSfile, attested too, with each release and the snapshot pre-release, and verify the checksum of the downloaded binary inself-update - Only accept attestations signed by the Artifacts workflow when verifying the provenance of a binary, and skip the verification with a GitHub CLI too old to know about attestations instead of failing
- Verify the SHA-256 checksum of the static-php-cli archive downloaded by
castor:compile: the checksums of the default--spc-versionare known, any other version needs the new--spc-sha256option - Verify the checksum of the binary downloaded by the installer against the
SHA256SUMSfile of the release, download it to a private temporary file removed whatever happens, and read the whole installer script before running anything - Prefer the PHP zip extension over the zip binary in
zip()when a password is given: the binary gets the password as a command line argument, readable by every user of the machine while the archive is created.zip_binary()still does, and now warns about it - Pass the script run by
run_php()to the Castor process as an argument instead of theCASTOR_PHP_REPLACEenvironment variable, which made any Castor process include an arbitrary file when set in its environment - Refuse a Castor phar without provenance attestation in
castor:repack, likeself-updatedoes, unless the new--allow-unattestedoption is passed for a release published before attestations existed - Derive the key of
encrypt_with_password()andencrypt_file_with_password()with the "moderate" limits of libsodium (Argon2id, 3 passes, 256 MiB) instead of the "interactive" ones, and store the limits in the encrypted payload. Content encrypted by previous versions is still decrypted, but content encrypted by this version needs it, or a later one, to be decrypted
Deprecations¶
-
Not defining the
CASTOR_USE_CHDIRconstant is deprecated. Adddefined('CASTOR_USE_CHDIR') || define('CASTOR_USE_CHDIR', true);at the top of yourcastor.phpto opt in (the guard keeps a mounted or importedcastor.phpfrom redefining it): Castor then changes its own current directory to the working directory of the context, sofs(),finder()and the raw PHP functions (mkdir(),unlink(),file_get_contents(), ...) resolve relative paths whererun()executes, instead of wherevercastorwas invoked from. It followswith(workingDirectory: ...)too, and is restored when the block ends. This becomes the default in Castor 2.0. Define the constant tofalseto keep the current behavior without the deprecation.Once enabled, a relative path given as a CLI argument (
castor castor:compile foo.phar, task arguments, ...) is resolved from the project root rather than from the directory you invokedcastorin, which matters when you run Castor from a subdirectory.
Fixes¶
- Resolve the remote packages of
castor.composer.jsonagainst the packages bundled with Castor, declared to Composer as metapackages standing for the versions Castor ships: a package Castor ships is not installed a second time in.castor/vendor, and a package requiring a version Castor does not ship fails at install time with an explanation, instead of Castor crashing at runtime on a mix of the two versions. Incastor.composer.lock, these packages follow the versions of the running Castor, and settingextra.castor.bundled-packagestofalseincastor.composer.jsonopts out - Quote the remote
pathofssh_run(), and reject ahost,user,jump_host,path_private_keyormultiplexing_control_pathcontaining a shell metacharacter: they end up in a local shell command line, so a value coming from user input could run a command instead of opening a connection - Pass the container name of
wait_for_docker_container()todockeras an argument instead of building a shell command with it - Extract the watcher binary used by
watch()in the phar and static builds to the user cache directory, under the Castor version, instead of a fixed path in the system temporary directory shared by all users, and replace it when its content is not the expected one - Create the cache directory readable by its owner only (mode
0700), and restrict an existing one, as the cache may hold data written by the tasks; honorXDG_CACHE_HOMEfor its default location, and fall back to a per-user directory in the system temporary directory, instead of one shared by all users, when the home directory cannot be determined - Fix architecture detection on Linux ARM64 (
aarch64), which made the watcher and the update hints pick the amd64 binaries - Fix
run()ignoring the timeout when executed insideparallel(): the process was waited for in its own fiber loop, so Symfony's timeout check never ran and the process could run forever - Fix
with()leaking its context between fibers running underparallel(): since the current context was tracked globally, a fiber resuming or callingwith()while another one was suspended inside its ownwith()block could make it resume with the wrong context, and the wrong context could even surviveparallel()itself - Fix
import()of a remote Composer package changing the working directory of the tasks it defines: only an explicitmount()should do that
1.7.0 (2026-08-03)¶
Features¶
- Add
dispatch()andevent_dispatcher()functions to dispatch events and access the event dispatcher - Add
mountPathandisRootMountproperties toFunctionsResolvedEvent, so listeners can tell the root application apart from mounted ones (the event is dispatched once per mount)
Fixes¶
- Fix
enable_strict_checkandpassword_authenticationssh options being ignored - Fix
AsArgsAfterOptionEndnot validating arguments properly: extra arguments given without a--were silently dropped instead of raising an error, and required arguments given after--were not detected as missing - Fix
-c/--contextbeing wrongly parsed from arguments passed after--, causing an unrelatedContext "..." not founderror - Prevent the
AsArgsAfterOptionEndattribute from being used on more than one parameter of the same task - Turn the
SshOptionstype alias into a@phpstan-typedeclared onSshRunner, so it resolves without any PHPStan configuration - Ship a default
ContextData: 'array<string, mixed>'PHPStan type alias inextension.neon, so projects that do not declare their own context data shape no longer getclass.notFounderrors onContext::$dataandvariable(). Declaring the alias in your ownphpstan.neonstill takes precedence, and is now documented in the context documentation - Fix watcher to use correct binary on Linux ARM64
- Fix
watch()failing when given an array of paths
1.6.1 (2026-07-02)¶
Features¶
- Display a nice message when the user is using an unsupported PHP version (8.2 or 8.3) and suggest to use the static binary instead
1.6.0 (2026-06-30)¶
Features¶
- Drop support for PHP 8.2 and 8.3, minimum supported version is now PHP 8.4
- Remove castor header and upgrade output when running inside an ai agent
- Add support for
.castor.contextfile to set the default context (lowest precedence after--contextflag andCASTOR_CONTEXTenv var)
Security¶
- Harden the security of our GitHub Actions Workflows
Fixes¶
- Fix option mode detection from Symfony command definition
Internal¶
- Upgrade to Symfony 8.1
1.5.0 (2026-05-27)¶
Features¶
- Add link to the task definition in the help of the task
Fixes¶
- Fix usage of
#[AsArgsAfterOptionEnd], CLI arguments are not mandatory anymore, and PHP parameters can be optional with default value - Fix implementation of
Context::supportsInteraction()
Security¶
- Update all PHP vendor with security issue
1.4.0 (2026-04-28)¶
Features¶
- Add
directoryandfilterparameters to#[AsPathArgument]and#[AsPathOption]attributes to improve autocomplete - Add
inputoption to Context to pass data to process stdin (useful for sensitive data like passwords) - Add
Context::supportsInteraction()/Context::withSupportsInteraction()to expose whether the surrounding environment supports interactive commands (auto-detected fromCIenv var and STDIN being a TTY);Context::toInteractive()now throws aLogicExceptionwhen called in a non-interactive environment, withtoInteractive(throwOnNonInteractiveEnv: false)to bypass
Fixes¶
- Fix installer to better handle invalid --install-dir option
Internal¶
- Update all PHP vendor
1.3.0 (2026-03-06)¶
Features¶
- Allow to compile castor with PHP 8.5
- Castor static binaries are now compiled with PHP 8.5
- Rework how repacking is done. It's no longer needed to require
jolicode/castorbefore repacking
Internal¶
- Update SPC version to v2.8.2
1.2.0 (2026-02-10)¶
Features¶
- Add a
terminal()function to get terminal properties - Add a
#[AsArgsAfterOptionEnd]attribute to get all arguments after--delimiter
Fixes¶
- Do not generate stub if no castor file, also check for completion command name
Internal¶
- Update all PHP vendor
1.1.0 (2025-11-26)¶
Features¶
- Allow to specify directory where to output repacked phar
- Do not ask confirmation when explicitly using
castor initcommand - Allow to pass a callback when using the
run_phpfunction (similar to therunfunction) - Add a new
--castor-fileoption to specify a custom root file when using thecastorcommand - Add a
slug()function to slugify strings - Display installation method/path in
castor debug - Add support for PHP 8.5 (except for static binaries which are not available yet)
Fixes¶
- Use correct working directory when using the
castor executecommand. - Fix infinite loop when executing
castorwithcastor execute jolicode/castor@castor - Fix
--castor-fileoption parsing - Fix the update instructions when using static binaries
- Fix remote composer working directory, forcing relative paths to have "../" prefix
- Allow to run Symfony commands even with the static binaries
- Force the
SCRIPT_FILENAMEenv var when usingrun_php()to avoid issues with some PHP scripts - Fix
--contextto take precedence overCASTOR_CONTEXTenv var - Fix
CASTOR_CONTEXT=defaultto work as expected
Internal¶
- Provide PHP 8.4 in the static binaries
- Update all PHP vendor
- Upgrade SPC version to v2.7.5
- Use a
PhpRunnerservice instead of static functions to run PHP files
Deprecations¶
- Deprecate
DISABLE_VERSION_CHECKenvironment variable in favor ofCASTOR_DISABLE_VERSION_CHECK
Documentation¶
- Rework the installation methods documentation
- Rework the Basic Usage documentation
- Add documentation for arguments/options of compile & repack commands
1.0.0 (2025-10-10)¶
- Remove BC-layer for Castor 0.x
0.29.0 (2025-10-09)¶
Features¶
- Add capability to repack with a custom logo from external PHP file
Internal¶
- Upgrade supported version of SPC > 2.5.0
- Upgrade GitHub action runner to MacOS 14
0.28.0 (2025-09-24)¶
Features¶
- Add version parameter to installer
- Improve init command with more clear messages
- Fill gitignore with castor stub on init
Fixes¶
- Do not use 💩 in namespace
Internal¶
- Update all PHP vendor
0.27.0 (2025-09-02)¶
Fixes¶
- Fix using
castor execwithout acastor.phpfile
Features¶
- Add
iconvextension to the static binary - Support having
--option with raw tokens which avoid interpretation of the next arguments - Allow to set
memory_limitdynamically viaCASTOR_MEMORY_LIMITenvironment variable
0.26.0 (2025-07-11)¶
Features¶
- Introduce remote execution command
- Load castor context in autocomplete mode
0.25.0 (2025-06-13)¶
Features¶
- Allows repack without Castor logo e.g.
castor repack --no-logo - Add static build for the Linux arm64 architecture
Fixes¶
- Fix context parsing, especially when using a task alias
- Do not load user files when displaying version
- Add a workaround to fix a bug in PHP 8.4, proxy object, and repacked application
Internal¶
- Update all PHP vendor
- Fix some CI issues (use github tokens)
0.24.0 (2025-04-25)¶
Features¶
- Improve
decrypt_file_with_password()with smart.encextension handling and file overwrite protection - Add
zip(),zip_binary(), andzip_php()functions to create password-protected zip archives with various compression methods and configurable compression levels
Fixes¶
- Add proper
.encextension to files encrypted withencrypt_file_with_password()
Internal¶
- Add tests for
decrypt_file_with_password()andencrypt_file_with_password()
0.23.0 (2025-03-06)¶
Features¶
- Add
$forceparameter to thecache()function to force recomputing the value - Add
getAttributes()method toTaskCommandto get all or specific attributes - Add
CASTOR_MEMORY_LIMITenvironment variable to set the memory limit when using therun_php()function - Add support for static binaries when installing castor with the installer
Fixes¶
- Ignore
nullenv variable when running process - Use an env var when using
run_php()to avoid conflict with php script reexecution - Rename
run_phar()torun_php()to express better that it can run any PHP file
Internal¶
- Update all PHP vendor
- Use Symfony 7.x
- Drop support for PHP 8.1
0.22.1 (2025-01-31)¶
Fixes¶
- Fix context name when getting it from the registry
- Fix
--contextoption ignored when another option presence
0.22.0 (2024-12-30)¶
Features¶
- Add
encrypt_with_password(),decrypt_with_password(),encrypt_file_with_password(), anddecrypt_file_with_password()functions to encrypt and decrypt data - Add
AsPathArgumentandAsPathOptionattributes to handle autocompletion of paths in arguments and options
Fixes¶
- Add more missing vendor classes into stubs
- Add support for disabling stubs generation (with
CASTOR_GENERATE_STUBS=0environment variable)
Documentation¶
- Document all the environment variables supported by Castor
0.21.0 (2024-11-19)¶
Features¶
- Better rendering of run errors
- Add
check()function to ensure requirements are met - Add
ProblemExceptionto handle problems in a more structured way - Add official support for symfony/string and symfony/var-dumper functions
Internal¶
- Rework the releasing
0.20.0 (2024-11-13)¶
Features¶
- Add support for PHP 8.4
- Force fetching the last version when guard min is used to display more information for user
- Add the ability to set a default task when calling
castorwithout any arguments
Fixes¶
- Boot the kernel even when using composer command
Vendor¶
- Update all PHP vendor
0.19.1 (2024-11-04)¶
Fixes¶
- Add GetRawTokenTrait definition in stubs
- Fix stubs to better support templates phpdoc and clean stubs file
- Fix deprecations when using ssh functions
0.19.0 (2024-10-29)¶
Features¶
- Add
Context::withVerboseArguments()method to pass verbose arguments to the underlying process when needed - Add support for custom php.ini in compile command
- Do not validate commande options/args as soon as `#[AsRawTokens] is used
- Update all PHP vendor
- Add partial support for PHP 8.4 (
ssh_()functions are not supported yet)
Fixes¶
- Re-active
static-darwin-arm64binary build - Fix stubs generation to use fully qualified class names even in phpdoc
Vendor¶
- Update SPC version to v2.3.5
0.18.2 (2024-09-03)¶
- Do not build static-darwin-arm64 binary anymore (may be temporary)
0.18.1 (2024-09-03)¶
- Fix BC layer for
fingerprint()function - Fix repack command work without .castor folder
0.18.0 (2024-08-27)¶
Features¶
- Add
Castor\CommandBuilder\CommandBuilderInterfacewhich allows to build nice API for command line software - Add
Context::toInteractive()method - Add
Castor\Event\ContextCreatedEventto allow updating the context after it is created - Add
run_phar()function to run a phar file in all contexts
Vendor¶
- Update SPC version to 2.3.0
- Update all PHP vendor
Fixes¶
- Add an id parameter to
fingerprint()to avoid bad cache hit - Fix completion when update is available
- Fix repack when there is composer dependencies to castor
- Fix wait_for_docker_container example to avoid checking previous docker logs
Deprecations¶
-
Deprecate all arguments in
run()function that are already in the context. Examples:{ - run(['composer', 'install'], workingDirectory: __DIR__); + run(['composer', 'install'], context: context()->withWorkingDirectory(__DIR__)); } -
Deprecate
suggestedValuesproperty inAsArgumentandAsOptionattributes. Useautocompleteproperty instead.
0.17.1 (2024-05-31)¶
Fixes¶
- Fix update instruction
0.17.0 (2024-05-27)¶
Features¶
- Add
Castor\Event\AfterBootEventto perform action when the application is ready - Add
Symfony\Component\Finder\SplFileInfoto the stubs
Fixes¶
- Map console verbosity level to default context, even when no context is defined
0.16.0 (2024-05-22)¶
Features¶
- Totally rework the import feature. Castor use special
castor.composer.jsonfile to handle imports. This fixes many bugs and issues with the previous - SSH
- Marked SSH features as stable
- Add
?callable $callback = nullparam tossh_*functions to manipulate output - Add support for SSH connection without specifying a user
- Add
context()function in expression language to enable a task - Add
notificationTitleproperty toContextto set the application name for notifications title - Add
http_download()function to simplify the process of downloading files
Minor¶
- Better handling of notification errors and exceptions
- Better log output in debug mode (
-vvv) - Changed the behavior of
notifyparameter inContextto be a nullable boolean.nullis now the default value (only user notifications are displayed).trueto enable notifications globally (user and Castor generated notifications)falseto disable them globally
.castor.stub.phpis now generated in same location wherecastor.phpis located
Deprecations¶
- Deprecate
Castor\GlobalHelperclass. There are no replacements. Use raw functions instead - Deprecate
AfterApplicationInitializationEventevent. UseFunctionsResolvedEventinstead - Deprecate
request()in favor ofhttp_request()for consistency with newly introducedhttp_*function
Fixes¶
- Fix root location when repacking application
0.15.0 (2024-04-03)¶
Features¶
- Add support for importing remote functions and tasks
- Add a bash installer to ease installation
- Distribute static binaries
castor.darwin-arm64automatically with the release - Add support for running Castor on Linux arm64 and distribute the binary
castor.linux-arm64.pharautomatically with the release - Add an option
ignoreValidationErrorsonAsTaskattribute to ignore parameters & options validation errors - Add support for dynamic autocomplete task arguments/options
- Add support for merging an application
box.jsonconfig file used bycastor:repackcommand - Find root directory by looking for a
.castor/castor.phpfile - Allow stub file to be in
.castor/.castor.stub.php
Fixes¶
- Fix issue with PTY on windows, it's now always disabled
- Fix issue when finding root dir on windows
- Fix issue on SymfonyTask creation
Deprecations¶
- Deprecate loading all PHP files from
[ROOT_DIR]/castor - Deprecate
Context::withPath()in favor ofContext::withWorkingDirectory() - Deprecate
pathargument incapture(),exit_code(),run(),with()in favor ofworkingDirectory - Deprecate
Castor\TaskDescriptorCollectionin favor ofCastor\Descriptor\TaskDescriptorCollection - Deprecate
Castor\HasherHelperin favor ofCastor\Castor\HasherHelper - Deprecate
Castor\PathHelperin favor ofCastor\Castor\PathHelper
0.14.0 (2024-03-08)¶
- Add a
yaml_dump()function to dump any PHP value to a YAML string - Add a
yaml_parse()function to parse a YAML string to a PHP value - Remove the default timeout of 60 seconds from the Context
- Add a
recursiveparameter to thewithData()method ofContextto allow recursive merging for nested arrays - Add an
open()function to open a file or URL in the default application - Add
boolreturn type tofingerprint()function to indicate if the callable was run
0.13.1 (2024-02-27)¶
- Fix instruction for downloading new castor version as a phar
0.13.0 (2024-02-23)¶
- Add a
compilecommand that puts together a customizable PHP binary with a repacked castor app into a static binary - Distribute static binaries
castor.linux.amd64andcastor.darwin.amd64automatically with the release - Compile watcher and phar for arm64 on macOS, and distribute them with the release
- Add
ProcessStartEventandProcessTerminateEventevents - Allow to listen to the symfony console events
- Set the process title according to the current application name and task name
- Deprecates
add_context()function, useAsContextGeneratorattribute instead - Allow to get null instead of throwing an exception when calling
task(true)without a current task - Ignore some low level env vars in runnable command showed in logs
- Fix section output to work on Windows
0.12.1 (2024-02-06)¶
- Fix issue with symfony console (color doesn't work in tmux or screen)
0.12.0 (2024-02-06)¶
- Add a
debugcommand - Add
guard_min_version()function to ensure a minimum version of Castor is used - Add
wait_for_http_response()function for a more generic response check - Add
wait_for_docker_container()function to wait for a docker container to be ready - Add
AsSymfonyTaskattribute to map Symfony Command - Add
Context->nameproperty (automatically set by the application) - Add an error handler, and wire the logger to it so display deprecation notices
- Edited the duration of update check from
60 daysto24 hours - Revise the usage of the terms
commandandtaskfor consistency through code and docs. - [BC Break] Remove
callable $responseCheckerparameter fromwait_for_http_status() - [BC Break] The event
AfterApplicationInitializationEventsecond arguments is now aTaskDescriptorCollection, and the event is emitted after the context configuration
0.11.1 (2024-01-11)¶
- Fix issue when using
ContextRegistry::getCurrentContext()without setting first a context - Calling
ContextRegistry::getCurrentContext()withoutsetCurrentContext()is deprecated. Pass a$contextinstead to the function, or set a current context before.
0.11.0 (2024-01-11)¶
- Add
AsListenerattribute to register an event listener - Add
wait_for(),wait_for_port(),wait_for_url(),wait_for_http_status()functions - Allow to override
AsTaskandAsContextattributes - Add
forceargument tofingerprint()method to force run the callable, even if fingerprint is same - Fix directory for fingerprinted test
- [BC Break] Remove almost all setters in the GlobalHelper class
- Refactor the documentation
0.10.0 (2023-11-14)¶
- Add
ssh_upload()andssh_download()functions to upload/download files via SSH - Rename
ssh()tossh_run() - Allow to set default context with an env variable
0.9.1 (2023-10-09)¶
- Fix castor application version
- Fix typo in
run()error message
0.9.0 (2023-10-09)¶
- Add
fingerprint()function to condition code execution based on some hash changes - Better handle default Symfony commands when no castor file exists yet
- Add
-coption tocastorcommand to specify a context
0.8.0 (2023-08-16)¶
- Add
request()andhttp_client()functions to make HTTP requests - Add support for disabling task dynamically
- Add a
withfunction to run logic with a specific context or parameters without passing them to eachrunor other functions - Allow to get a context by its name using
$fooContext = context('foo') - Experimental display with sections, allow better output when using parallel
function, enable it by by using
CASTOR_USE_SECTION=true castor [task] - Display more information when running a process
- Rename
get_exit_code()toexit_code() - Rename
get_context()tocontext() - Rename
get_input()toinput() - Rename
get_output()tooutput() - Rename
get_application()toapp() - Rename
get_command()totask() - Fix parallel when one of the callback fails, wait for the others to finish to throw exception
0.7.1 (2023-07-11)¶
- Fix the
castor --versioncommand when there is no.castor.phpfile
0.7.0 (2023-07-11)¶
- Add support for re-packing a castor application into a new phar file
- Fix the update command message to follow redirects with curl
0.6.0 (2023-06-30)¶
- Add support for registering
Contextprogrammatically - Add
load_dot_env()function for loading the context's environment from a dotenv file - Add support for multiple paths in
watch()function - Add
get_exit_code()function to get a process exit code, even if it failed
0.5.2 (2023-06-24)¶
- Add documentation about installation in a Github Action
- Add more classes in stubs
0.5.1 (2023-06-22)¶
- Fix curl download in installation instructions
- Fix code on initial castor.php creation
- Do not remove annotation from phar
0.5.0 (2023-06-16)¶
- Add support for signals handling
- Add a way to type Context::$data
0.4.1 (2023-06-13)¶
- Allow to use the cache in the context creator
- Add
onFailureargument to thecapture()function - Add
ExecutableFinderin stubs
0.4.0 (2023-06-12)¶
- [BC Break] replace specials helpers arguments by dedicated functions
- Add
capture()function to easily run a process and returns the output - Add
cache()andget_cache()function to easily cache something - Add
ssh()function to run commands on remote server via SSH - Display warning and update instructions when a new version is available
- Better error reporting when a call to
run()fails or whenimport()is not possible - Fix stubs generation
0.3.0 (2023-06-07)¶
- Enhance the documentation
- Enhance the first run experience
0.2.0 (2023-06-02)¶
- Add a way to get the
Commandinstance in a task - Add support for better handling of option without value
- Fix the stubs generation when castor is installed via composer
- Fix the initial
castor.phpfile generated for new projects - Fix
watch()function
0.1.0 (2023-05-21)¶
- Initial release