Commands (Pionia CLI)

This reference is for DeskFlow developers who run php pionia from the project root — same AppRealm boot as HTTP, port 8000 by default, logs under storage/logs/ when using file channels or detached RoadRunner.

What you will learn

  • Daily commands (serve, make:service, cache:clear) vs deploy-only commands (optimize, runserver)
  • The full built-in command registry and common flags
  • How to scaffold and register a custom command in commands/
Before you start
  • Introductioncomposer create-project pionia/pionia-app
  • DeskFlow app directory with bootstrap/application.php

How it works

flowchart LR CLI[php pionia …] --> Boot[bootConsole] Boot --> Realm[AppRealm] Realm --> Cmd[Command::handle] Cmd --> Out[Terminal output]

Pionia CLI is the command-line interface for your application. It boots the same AppRealm as HTTP via bootstrap/application.phpbootConsole().

New projects are created with composer create-project pionia/pionia-app — see Introduction. The CLI commands below run inside an existing app directory.

v3 uses a native console (Pionia\Console\Application). Commands extend Pionia\Console\Command; arguments and options use Pionia\Console\Input\InputArgument and InputOption. Run the CLI from your project root as php pionia … or composer run pionia -- ….

Custom commands live in commands/ (generate with make:command).

Daily workflow

Commands you run most often while building DeskFlow locally:

TaskCommand
Start dev serverphp pionia serve (port 8000 by default)
Scaffold a servicephp pionia make:service task
Scaffold middlewarephp pionia make:middleware RequestId
Clear cachephp pionia cache:clear
Interactive REPLphp pionia shell
List all commandsphp pionia list

See Introduction for install and RoadRunner when you outgrow the built-in server.

Deployment & optimization

Use these on staging and production — not on every code change:

TaskCommand
RoadRunner workersphp pionia runserver --detach
Production optimizephp pionia optimize --production
Maintenance gatephp pionia maintenance:on / maintenance:off
Tail worker logsphp pionia runserver:logs

Full checklists: Production performance and Maintainer notes (framework contributors only).

Built-in commands (v3)

Run php pionia list for the live registry in your app. Built-in commands ship with the framework; your app may add more under commands/.

Global

CommandAliasesDescription
serveserver, start, runPHP built-in dev server
runserverroadrunner, rr:serveRoadRunner persistent workers
runserver:logsrr:logs, roadrunner:logs, logs:rrTail RoadRunner logs (formatted)
stopserverroadrunner:stop, rr:stopStop detached RoadRunner
rr:setuprunserver:setupDownload ./rr binary
optimizeProduction autoload + OPcache preload + bootstrap caches
optimize:preloadRegenerate OPcache preload only
optimize:clearclear-optimizeRemove generated optimization artifacts
app:aliasesalias, aliases, list:aliasesList path aliases registered in AppRealm
shelltinker, repl, pionia:shellInteractive REPL

servephp pionia serve --port=8000 --host=127.0.0.1
Options: --port, --host, --tries=10, --no-reload
Default port: 8000 (from PORT / SERVER_PORT in .env, or [server] / [roadrunner] in settings.ini)

runserverphp pionia runserver --detach --port=8000
Options: --config=, --worker=, --host=, --port=, --detach, --log=, --raw

runserver:logsphp pionia runserver:logs --wait
Options: --log=, --lines=50, --no-follow, --wait, --raw

stopserverphp pionia stopserver --force
Options: --config=, --port=, --force

rr:setupphp pionia rr:setup (alias: composer rr:setup)
Downloads the RoadRunner binary into the app root. Option: --force

optimizephp pionia optimize --production
Opt-in production mode: installs bootstrap/preload.php, php.ini.production.example, and [performance] settings, then runs autoload + preload generation.
Options: --production, --no-scaffold, --no-preload, --no-autoload, --authoritative, --bootstrap-cache

optimize:preloadphp pionia optimize:preload --snapshot
Regenerate storage/bootstrap/preload.php only. Options: --snapshot, --from-stats, --strategy=curated|stats|hybrid

optimize:clear — removes generated artifacts. Option: --scaffold to remove opt-in files too.

app:aliases — lists built-in and custom path aliases (LOGS_DIR, SERVICES_DIR, etc.) with resolved paths and whether each maps to a directory.

API documentation

CommandAliasesDescription
api:docsmake:api-docs, docs:apiGenerate OpenAPI + Markdown from @moonlight-* tags
api:catalogdocs:catalogPrint service/action catalog JSON

api:docsphp pionia api:docs --ui --check
Options: --format=openapi,markdown, --output=docs/api, --ui, --check

api:catalogphp pionia api:catalog -o docs/api/catalog.json
Options: --output= (file; default stdout)

Full tag reference, examples, and /docs setup: Documenting your API (Moonlight).

App

CommandAliasesDescription
app:aliasesalias, aliases, list:aliasesList container aliases

Cache

CommandAliasesDescription
cache:clearcache:c, c:cWipe the active cache store
cache:prunecache:p, c:pRemove expired entries
cache:delete {key}cache:d, c:d, uncacheDelete one key

See Caching.

Frontend (Vite)

CommandAliasesDescription
frontend:scaffoldf:scaffold, frontend:sCreate Vite app in frontend/
frontend:devf:devVite dev server (proxies /api)
frontend:buildf:build, frontend:bBuild and deploy to public/
frontend:cleanf:cleanRemove built assets from public/
frontend:dropf:dropDelete frontend/ and settings

frontend:scaffoldphp pionia frontend:scaffold --framework=react-ts --yes
Options: --framework=, --directory=frontend, --package-manager=, --yes

frontend:devphp pionia frontend:dev --port=5173

frontend:dropphp pionia frontend:drop --force

Maintenance

CommandAliasesDescription
maintenance:ondownEnable HTTP 503 gate
maintenance:offupDisable maintenance mode

maintenance:onphp pionia maintenance:on --message="Deploying" --retry-after=300 --bypass="$(php -r 'require "vendor/autoload.php"; echo (new Pionia\Security\Security())->randomHex(16);')"
Options: --message=, --retry-after=, --bypass= / --secret=

See Maintenance mode.

Stats

CommandAliasesDescription
stats:viewstats, viewstatsRequest metrics in the terminal

stats:viewphp pionia stats:view --json --reset
Options: --json, --top=10, --reset

See Developer stats.

Code generation (make:)

CommandAliasesDescription
make:service {name}gen:service, g:s, serviceScaffold a service class
make:switch {name}g:sw, switchScaffold an API switch (e.g. v2)
make:middleware {name}gen:middleware, g:mScaffold middleware
make:auth {name}gen:auth, g:aScaffold an authentication backend
make:command {name}gen:command, g:c, commandScaffold a custom CLI command
make:provider {name}gen:provider, g:p, providerScaffold a service provider

Examples:

php pionia make:service todo
php pionia make:switch v2
php pionia make:middleware cors
php pionia make:auth jwt
php pionia make:command reports:Generate

Help

php pionia list
php pionia help runserver
php pionia help frontend:scaffold

Adding Custom Commands

Pionia commands extend Pionia\Console\Command. Place classes in commands/ (or generate one with make:command).

To create a new command, you can run the following command:

php pionia make:command PasswordGenerator

This is an interactive command that will ask you to provide the name, title, help message, description, options, the command namespace and many more of the command.

Command Namespace

Commands are grouped into namesapces such as auth, make app and you can also create your own namespace and add your commands there. The namespace is used to group related commands together. The namespace is the first part of the command name. For example, in the command make:command, make is the namespace.

If you do not provide a namespace for your command, it will be placed in the custom namespace.

For our command above, let’s add in the security namespace. The command name will be security:PasswordGenerator.

Command Title

The title is the name of the command that will be displayed in the list of available commands. It should be a human-readable name that describes the command.

Let’s name our command Password Generator.

Command Description

The description is a brief description of what the command does. It should be a short description that explains the purpose of the command.

In our description prompt, we can write Generate a random password in Pionia.

Command Help Message

The help message is a detailed description of how to use the command. It should explain the arguments, options, and usage of the command.

In our help message prompt, we can write This command generates a random password with the specified length. You can specify the length of the password using the --length option. If no length is specified, a password of length 10 will be generated.

Command Aliases

From the command we have, writing php pionia security:PasswordGenerator is quite long. We can add aliases to the command to make it easier to run the command. You can add multiple aliases here to make it easier to run the command.

In our aliases prompt, let’s add gen-pwd as aliases. The CLI will prompt you to add more aliases if you want.

Now on, you can run the command using php pionia gen-pwd.

Command Arguments

Arguments are the values that are passed to the command when it is run. You can specify the arguments that the command accepts. You can also specify whether the argument is required or optional.

In our case, we might not need any arguments, so we can skip this step. However, any arguments identified will be prompted to you when you run the command.

Arguments can also be shortened by passing the short argument which implies that you can pass the argument by a single character instead of writing the entire string.

Arguments must be described too. A description of the argument helps the user to understand what the argument is used for.

Command Options

Options are the flags that can be passed to the command when it is run. You can specify the options that the command accepts. You can also specify whether the option is required or optional.

For our case, we can add an option for the length of the password. The argument should be named length and should be optional. The CLI will prompt you to add more arguments if you want.

Options can also be shortened by passing the short option which implies that you can pass the option using -l instead of --length.

Options must be described too. For our case, we can write The length of the password to generate, defaults to 10

Optional arguments and options can have default values. If the user does not provide a value for the argument or option, the default value will be used.

For our case, we can set the default value for the length option to 10.

On complete setup, the command will generate a new command class in the commands directory. The class will look like below:

commands/PasswordGeneratorCommand.php

<?php

  /**
   * This command is auto-generated from pionia cli.
   */

  namespace Application\Commands;

  use Pionia\Console\Command;
  use Pionia\Console\Input\InputOption;

  class PasswordGeneratorCommand extends Command
  {
    /** The aliases for the command. */
    protected array $aliases = ['gen-pwd'];

    /** The help message for the command. */
    protected string $help = 'This command generates a random password with the specified length. You can specify the length of the password using the --length option. If no length is specified, a password of length 10 will be generated.';

    /** The description of the command. */
   protected string $description = 'Generate a random password in Pionia';

    /** The title of the command. */
    protected string $title = 'Password Generator';

    /** The name of the command. */
    protected string $name = 'security:PasswordGenerator';


    /**
     * Get the console command arguments.
     */
    public function getArguments(): array
    {
      return [
      ];
    }


    /**
     * Get the console command options.
     */
    public function getOptions(): array
    {
      return [
          ['length', 'l', InputOption::VALUE_OPTIONAL, 'The length of the password to generate, defaults to 10', '10']
      ];
    }


    /**
     * Execute the console command.
     */
    public function handle(): int
    {
      $length = $this->option('length');
      // Add your logic here
      return Command::SUCCESS;
    }
  }

handle() Method

This where your command logic sits, if you defined any arguments or options, you can access them using $this->argument('argument_name') or $this->option('option_name').

In our case, we can access the length option using $this->option('length').

You can create other helper methods in the command class to help you with the command logic.

For our case, let’s add the folllowing code to generate a random password

  /**
   * @throws RandomException
   */
  function generateRandomString($length = 10): string
  {
      $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
      $charactersLength = strlen($characters);
      $randomString = '';

      for ($i = 0; $i < $length; $i++) {
          $randomString .= $characters[random_int(0, $charactersLength - 1)];
      }

      return $randomString;
  }

We can now complete our handle method as follows:


  /**
     * Execute the console command.
     * @throws RandomException
     */
  public function handle(): int
  {
    $length = $this->argument('length');
    // Add your logic here
    $string = $this->generateRandomString($length);
    $this->info($string);
    return Command::SUCCESS;
  }

Registering the Command

Commands must be registered under the [commands] section in any of the .ini files. However, if your command was generated via the cli automatically, it will be registered automatically in the generated.ini.

[commands]
security:PasswordGenerator = "Application\Commands\PasswordGeneratorCommand"

To see our command, we can now run the following command:

php pionia list

This command will display all the available commands in Pionia CLI. You should see your command listed there.

Available Commands:
  ...
  security
    security:PasswordGenerator  Generate a random password in Pionia
  ...

You can now run your command using the following command:

php pionia gen-pwd

This will generate a random string in your terminal.

To pass the length of the password, you can use the --length option:

php pionia gen-pwd --length=20

The sections below walk through building this command step by step. For the full built-in command reference, see Built-in commands (v3) above.

Common mistakes

  • Running CLI from outside the app rootphp pionia must run where bootstrap/application.php lives.
  • Using composer run pionia without -- — pass command args after --: composer run pionia -- list.
  • Expecting serve to enable jobs or HTTP/2 — use runserver for RoadRunner; see RoadRunner.
  • Editing generated.ini only for custom commands — copy [commands] entries to settings.ini for all environments.

What’s next

RoadRunner

runserver, rr:setup, worker logs.

Background work

defer() after API responses.

Production performance

optimize --production on deploy.