Console Kernel
mitosis itself is a thin, frozen stub — three lines, the same in every scaffolded app:
#!/usr/bin/env php
<?php
require __DIR__ . '/config/bootstrap.php';
exit(Monad\Clarity\Services\Console::run($argv));
All the real work — argument parsing, command dispatch, loading
app/routes/cli.php, output formatting, exit codes — lives in
Services\Console::run(array $argv): int, the one symbol this stub calls. That's the
frozen, semver-locked contract; the 15 built-in command classes it dispatches to are internal and
free to be reorganized in any minor release, because nothing outside Clarity references them by
class name — only by the command name string.
The 15 built-in commands
make:controller make:model make:migration make:service
migrate migrate:status migrate:rollback
db:seed db:execute
test health serve
cache:clear logs:clear setup
Renaming or removing one of these is a semver-major change; adding a new built-in is semver-minor.
test delegates to the bundled PHPUnit — no bespoke runner. See
Testing and Deployment for
test and health in depth.
Registering your own command
app/routes/cli.php is loaded on every run(), the same way
app/routes/web.php is loaded for HTTP requests. Register a command with
Console::register() — a closure, an invokable object, or a class-string instantiated
with no constructor arguments:
use Monad\Clarity\Console\Arguments;
use Monad\Clarity\Services\Console;
Console::register('greet', function (Arguments $arguments): int {
Console::writeLine('Hello, ' . ($arguments->argument(0) ?? 'World') . '!');
return 0;
});
php mitosis greet Marshal
# Hello, Marshal!
Arguments::argument(int $index) reads a positional argument;
Arguments::option(string $name) reads a --flag/--key=value
option. Console::success()/error()/info() write colored,
prefixed output — the same helpers every built-in command uses.
Next steps
- Testing —
php mitosis testin depth. - Deployment —
php mitosis health, the deployment acceptance gate.