CLI
Introduction
Section titled “Introduction”Warden ships a batteries-included command-line tool that handles the repetitive parts of building a Discord bot — spinning up a new project, generating class files, registering commands with Discord. It’s distributed as @warden/console, a dev dependency that installs the warden binary into your project. If you scaffolded your project with create-@warden it’s already there; if not, pnpm add -D @warden/console drops it in.
The first thing to know is what you’ve got:
pnpm warden --helpThat prints every console command the binary knows about, including the make:* generators, sync, sync:clean, and anything your project or your plugins have contributed.
Two kinds of commands
Section titled “Two kinds of commands”Before we go any further, a moment on vocabulary — because Warden has two different things called “commands” and you’ll want to keep them straight as you read through the rest of these docs.
| Console commands | Slash commands | |
|---|---|---|
| Run from | Your terminal | Discord client |
| Looks like | warden sync, warden make:command Warn | /warn @user reason, /mod ban @user |
| Authored with | @cli + ConsoleCommand | @command + Command interface |
| Lives in | src/console/ or @warden/console | src/commands/ |
| This section | ✓ | — (see Commands) |
Everything in this section of the docs is about console commands — the warden binary, the generators it exposes, the sync and sync:clean commands, and how to write your own. When we say “the CLI”, we mean the whole console-command surface.
What ships in the box
Section titled “What ships in the box”Database commands
Section titled “Database commands”Ship with @warden/drizzle. Warden owns the DB workflow end-to-end
— drizzle-kit stays out of sight.
| Command | Does |
|---|---|
warden db:migrate | Apply pending migrations. Shows a preview; confirms in prod (use --force in CI). |
warden db:migrate:status | Print applied + pending migrations. Never prompts. |
warden db:migrate:fresh [--seed] | Drop all tables, re-apply migrations. Optionally run seeders after. Destructive; confirmation rules apply. |
warden db:wipe | Drop all tables. No re-apply. Destructive. |
warden db:seed [--class=Name] | Run registered seeders (classes decorated with @seeder() in src/db/seeders/). Explicit only — never runs implicitly. |
warden make:migration <name> [--no-framework-schemas] | Generate a new migration. Auto-includes schemas from installed @warden/* packages (audit, cache, permissions) — prints what it included. |
warden make:seeder <name> | Scaffold a seeder class. |
Design principles
Section titled “Design principles”Three ideas show up throughout the CLI, and once you’ve seen them in one place you’ll see them everywhere.
Declarative authoring
Section titled “Declarative authoring”The authoring surface — single-string signature declarations, this.* helpers on a base class, inline markup tags, auto-registered convention flags like --force and --dry-run — is built around one idea: the shape of a command should be visible at a glance. You declare what your command takes; the runtime handles parsing, validation, and dispatch. If you’ve never written CLI tooling this way, you’re about to learn a lovely pattern for it.
One framework, one authoring model
Section titled “One framework, one authoring model”The same @cli decorator and ConsoleCommand base class power Warden’s built-in make:* and sync commands, your project’s own src/console/ commands, and the commands any plugin ships in its node_modules/@warden/*/dist/commands/ directory. There’s no first-party/third-party distinction here — plugins get exactly the same primitives the framework uses for itself.
Every built-in flag comes with every command
Section titled “Every built-in flag comes with every command”--force, --dry-run, --verbose, and --no-interaction are registered automatically on every ConsoleCommand. You consume them via this.isForce() / this.isDryRun() / this.isVerbose() / this.isInteractive() — no per-command boilerplate. That means your users get a consistent experience regardless of which console command they’re running: --force always skips the confirmation, --dry-run always prints the plan without executing, and so on.
A typical workflow
Section titled “A typical workflow”A normal day working with Warden looks roughly like this:
# Start a new projectpnpm create @warden my-mod-botcd my-mod-bot
# Generate the slash-command boilerplatepnpm warden make:command Warnpnpm warden make:event MemberJoinLog --event guildMemberAddpnpm warden make:middleware IsModerator
# Run the bot in devpnpm dev
# Ship the commands to Discord when you're readypnpm warden sync --guild $DEV_GUILD_IDEverything beyond that — a project-local seed command, a plugin-contributed make:migration, a custom deploy:prod wrapper you run before shipping — is just another @cli class. Keep reading to see how to write them.