Core

CLI Runtime

CLI entrypoint, lifecycle CliKernelu, command registry, exit codes a cron pattern se zámkem.

Overview

CLI runtime uses the same application composition model as HTTP runtime: ApplicationContext, merged Config, shared DI Container, service providers, and explicit integer exit codes. Command execution is coordinated by CliKernel and CommandRegistry.

CLI entrypoint

Applications normally run commands through the Composer binary vendor/bin/lemonade. The package binary resolves the application base path, builds ApplicationContext from the current environment, creates CliKernel through CliKernelFactory, and delegates to CliKernel::handle($argv).

vendor/bin/lemonade
vendor/bin/lemonade list
vendor/bin/lemonade app:example

CLI flow

Runtime flow: Composer binary -> package bin/lemonade -> CliEnvironmentResolver::resolveBasePath() -> ApplicationContextFactory::fromGlobals() -> CliKernelFactory::create() -> CliKernel::handle($argv) -> CliKernel::bootstrap() -> load shared and CLI config -> apply runtime app config -> register core providers -> register ConsoleServiceProvider -> register common framework providers -> register configured app providers -> build CommandRegistry -> execute CommandInterface::run($args) -> process exit code.

Command configuration

ConfigLoader maps app/Config/Commands.php to config key commands for CLI runtime. The file returns a list of command class-strings; each class must exist and implement CommandInterface.

<?php

declare(strict_types=1);

use App\Console\ExampleCommand;

return [
    ExampleCommand::class,
];

Command contract

Each command must implement Lemonade\Framework\Cli\CommandInterface with name(), description() and run(array $args): int.

<?php

declare(strict_types=1);

namespace App\Console;

use Lemonade\Framework\Cli\CommandInterface;

final class ExampleCommand implements CommandInterface
{
    public function name(): string
    {
        return 'app:example';
    }

    public function description(): string
    {
        return 'Run an example application command.';
    }

    /**
     * @param list<string> $args
     */
    public function run(array $args): int
    {
        fwrite(STDOUT, "Done\n");

        return 0;
    }
}

Running commands

The first CLI argument is the command name and the remaining values are passed unchanged to run(array $args). Empty command, list, --help, and -h print the command list and return exit code 0.

vendor/bin/lemonade
vendor/bin/lemonade list
vendor/bin/lemonade app:example --dry-run

Dependency injection

CommandRegistry resolves commands through the container ($container->get($commandClass)), so constructor injection works the same as in HTTP services/controllers. Service providers are the preferred place to register command dependencies.

Error handling

Exit code model from CliKernel: successful list/help returns 0, command result is forwarded from run(), unknown command returns 1, and unhandled exceptions are logged via ExceptionLogger, printed to stderr and return 1 (with stack trace in debug mode).

Use cases

CLI runtime is suitable for cron jobs, imports and exports, maintenance tasks, background workers and integrations where repeatable execution and process exit codes are required.

Boundary

ConsoleServiceProvider registers the command registry infrastructure. Application commands and their dependencies remain application code, while feature-specific framework commands can be added to Commands.php when their provider/package is used.