CLI

whity-cli

Migrations, seeding, tenants, plugins, translations and the background workers — the operational surface of a Whity deployment, from one tool.

Usage

Two entry points, same commands.

bin/whity-cli is the CLI tool. In a Docker install, most operations are run through the container against public/index.php, which dispatches the same commands — that is the form the quick start uses, because it needs no PHP on your host.

--help works at both levels: on its own for the command list, and after a command for the options that command accepts. An unknown option is rejected rather than ignored.

inside the containerbash
docker exec whity_frankenphp \
  php public/index.php migrate run
or the CLI tool directlybash
whity-cli migrate status
whity-cli --help
whity-cli seed --help
Reference

Every command.

CommandArgumentsWhat it does
migratestatus | run | rollbackManage database migrations. run also creates the bootstrap administrator.
seed--with-fixtures · --with-document-demoSeed the default tenant, roles and notification-template baseline. Idempotent — never rewrites an existing account's password.
pluginlist | enable | disable | reloadManage plugins at runtime, without a restart.
tenantlist | create | update | deleteManage tenants.
totp—TOTP secret maintenance — re-encrypt legacy secrets.
queue:work—Run the durable async job worker loop.
events:relay—Deliver durable domain events to their listeners. Run alongside queue:work, or event_outbox grows without bound.
schedule:run—Run the cron-tick scheduler, exactly once per minute across workers.
health:watch—Sample service health for the status page, from outside the app.
i18n:extract--checkRebuild the English translation catalogue from the t() calls in the source. --check verifies without writing, which is what CI runs.
i18n:sync--language · --all · --dry-runSeed catalogue keys missing from the translations table. Never overwrites an existing row, in any language.
i18n:coverage—Per-domain translated and missing counts for every committed language. Needs no database.
permissions:unheld—Report registered permissions that no role currently holds.
payments:secret—Payment provider secret maintenance.
scale:seed—Bulk-insert a deterministic, parameterised large-scale multi-tenant dataset for load testing.

Also dispatched by public/index.php

Operational commands you run inside the container.

generate:openapiRegenerate public/openapi.json from the routing layer.
update:checkCheck whether a newer core release is available.
form-uploads:sweepRemove orphaned form upload files.
revoked-tokens:cleanupPrune expired entries from the revoked-token store.
Operations

The three you must keep running.

A deployment that skips these looks healthy and quietly stops doing work in the background.

  1. queue:work

    The durable async job worker. Without it, queued jobs are recorded and never run.

  2. events:relay

    Delivers durable domain events to their listeners. Run it alongsidequeue:work — without it, asynchronously dispatched hooks record events that are never delivered and event_outbox grows without bound.

  3. schedule:run

    The cron tick, exactly once per minute across every worker.

Questions

CLI FAQ.

How do I run the Whity CLI?

Two entry points reach the same commands. bin/whity-cli is the CLI tool itself — whity-cli <command> [options]. Most operations in a Docker install are run through the container, for example docker exec whity_frankenphp php public/index.php migrate run. Use whity-cli --help for the command list and whity-cli <command> --help for one command's options.

Which background workers does Whity need running?

queue:work for durable async jobs, events:relay to deliver domain events to their listeners, and schedule:run for cron ticks. events:relay in particular must run alongside queue:work — without it, asynchronously dispatched hooks record events that are never delivered and the event_outbox table grows without bound.

Will i18n:sync overwrite existing translations?

No. The sync only ever inserts keys that are missing. It contains no UPDATE and no DELETE statement at all, and a unit test asserts that about the class's own source, so existing rows are never written to in any language or scope.

Every flag, in the docs.

The full reference — every action, option and exit code — is compiled from the repository.