Sesh Console
Sesh is the command-line interface to your application. Inside a project, run it through the maat shim or directly:
maat listmaat make:controller PostController --apidart run bin/maat.dart listRunning Sesh with no arguments lists every available command with its description.
Available Commands
| Command | Description |
|---|---|
serve |
Run the development server with file watching. |
route:list |
Show every registered route. |
channel:list |
Show every registered channel pattern. |
key:generate |
Generate and store the application key. |
about |
Show application name, environment, debug state, Dart and Maat versions, and base path. |
make:controller |
Create a controller. --api (or --resource) scaffolds the five resource actions; --invokable scaffolds a single-action controller. |
make:middleware |
Create a middleware class. |
make:request |
Create a form request. |
make:provider |
Create a service provider. |
make:command |
Create a console command. |
make:event |
Create a dispatchable event. |
make:channel |
Create a channel authorization stub. |
make:listener |
Create an event listener. --event=PostPublished types and imports the event. |
make:mail |
Create a mailable under lib/app/mail. |
make:notification |
Create a notification under lib/app/notifications. |
tailwind |
Compile the application CSS with Tailwind. --watch, --minify, --input=, --output=. |
thoth:start |
Start the Thoth WebSocket server. --host=, --port=. |
thoth:ping |
Check the Thoth health endpoint. --host=, --port=. |
tailwind comes from khnum_maat and is only present when a project depends on it — the standard preset does, --api does not. See Frontend.
make:mail comes from amarna. The standard and --api presets both
register it because either kind of application may send mail.
make:notification comes from sistrum and is registered by both
presets for the same reason.
thoth:start and thoth:ping come from thoth_realtime. Register them in the
console
kernel when the application provides realtime WebSockets. See
WebSockets with Thoth.
Generating Application Code
Every generator accepts --force to overwrite an existing file, and supports nested names:
maat make:controller Admin/UserController --api# lib/app/http/controllers/admin/user_controller.dart, class UserControllerWithout --force, a generator refuses to overwrite and exits with a non-zero status, so it will not silently destroy work.
Generated files land already formatted: after writing a file, a generator runs dart format over it, so the output matches what your editor and CI would produce and never shows up as noise in the next diff. If dart format cannot be run, the generator says so and keeps the file — the code is valid Dart either way, just untidy.
Get help for any command:
maat help make:controllerWriting Commands
class SendEmails extends Command { @override String get name => 'mail:send';
@override String get description => 'Send the queued mail';
@override String get signature => '{user} {--queue=default} {--D|dry-run}';
@override Future<int> handle() async { final user = argument('user'); final queue = option('queue');
if (flag('dry-run')) { warn('Dry run — nothing will be sent.'); return 0; }
info('Sending mail for $user on $queue.'); return 0; }}Generate the skeleton with:
maat make:command SendEmailsRegister it in lib/app/console/kernel.dart, and it appears in maat list alongside the built-ins.
The return value of handle is the process exit code. Return 0 for success and a non-zero value for failure, so scripts and CI can react.
Signature Syntax
| Form | Meaning |
|---|---|
{name} |
Required argument. |
{name?} |
Optional argument. |
{name=default} |
Optional argument with a default. |
{--flag} |
Boolean flag, false unless passed. |
{--opt=} |
Option that takes a value. |
{--opt=default} |
Option with a default value. |
{--o|opt} |
Short alias, so -o works too. |
Read them back with argument(name), option(name) and flag(name). Anything left over is available as rest.
The signature parser does not reject malformed tokens. A typo such as a missing closing brace produces an argument with a garbled name, and the matching
option()orflag()call then quietly returns nothing. If a new command’s options do not seem to arrive, check the signature string first.
Bad arguments print the command’s usage and exit with status 1.
Writing Output
| Method | Goes to | Notes |
|---|---|---|
info(msg) |
stdout | |
line(msg) |
stdout | |
warn(msg) |
stdout | Prefixed with WARNING:. |
error(msg) |
stderr | |
table(headers, rows) |
stdout | Columns are aligned to their widest cell. |
Always write through these rather than print. They target the sinks Sesh injects, which is what makes commands testable:
final out = StringBuffer();final maat = Sesh(app, out: out, commands: [SendEmails()]);
expect(await maat.run(['mail:send', 'ada']), 0);expect(out.toString(), contains('Sending mail for ada'));Keep rows the same width as your headers — extra cells in a row are dropped.
Accessing the Application
Every command has app, the running application, so the container and configuration are available:
@overrideFuture<int> handle() async { final repo = this.app.make<PostRepository>(); line('Posts: ${repo.count()}'); return 0;}