Running commands
Grind Console accepts the same shape of input whether you type it in a terminal, forward it through kona grind, or call Grind.call from application code or tests.
From the project
Section titled “From the project”./grind list./grind mail:digest 42 --queue=high./grind mail:digest --help./grind -v schedule:run./grind -q list./grind --base=/path/to/app list| Flag | Effect |
|---|---|
-v / --verbose |
Verbose diagnostics (GrindIO.verbose) |
-q / --quiet |
Suppress normal stdout (errors still print) |
--help / -h |
Empty argv / global help, or on a custom command: print signature help |
--base= |
App root for discovery / loaders (and many built-ins) |
--bootstrap= |
Bootstrap class for in-process boots (default bootstrap.App) |
--isolated |
With isolatable custom commands: single-process lock |
Option parsing rules (parseOptions):
-v,-q,-hsetverbose,quiet, andhelp.--namesetsname=true.--name=valuesetsnametovalue.- Anything else is positional.
Exit code 0 means success. 1 (and other non-zero values) means failure — missing args, unknown command, generator conflicts, Cadence errors surfaced as grind errors, and so on. Unknown built-in-style names print an error, show the help catalog, and exit 1.
Empty argv and help
Section titled “Empty argv and help”./grind./grind help./grind --help./grind -hThese discover custom commands, print the boxed “grind” usage catalog (built-ins + discovered customs), and exit 0.
list and per-command help
Section titled “list and per-command help”./grind list./grind mail:digest --helplist prints a two-column catalog: built-in names from ListCommand.BUILTIN, then registered custom commands (description, or signature when description is empty). Duplicate names are shown once.
For one custom command, --help / -h prints a box with the name/description, the rendered signature, and argument/option help lines — then exits 0 without running handle(). Built-in commands generally use their own usage/GrindException messages rather than the custom-command help renderer.
kona grind proxy
Section titled “kona grind proxy”When you are not already invoking ./grind directly, the global CLI can forward to the nearest project’s grind script:
kona grind servekona grind migratekona grind mail:digest 42kona grind --helpBehavior (org.konaframework.cli.GrindCommand):
- Walk upward from the current directory until a Gradle settings/build script is found (same markers as
serve). - Require
./grindorgrind.batin that root (apps fromkona new). - Run that script with your remaining arguments and propagate the exit code.
If no Gradle project is found, or the project has no grind script (for example a monorepo sample), the proxy fails with a clear error pointing at kona new. Prefer ./grind when you are already inside the app.
See Installation for installing the global kona CLI.
Calling commands from code
Section titled “Calling commands from code”Use org.konaframework.grind.Grind to run a command name with argument tokens (the same strings you would type after the command name on the CLI):
import org.konaframework.grind.CommandRegistryimport org.konaframework.grind.Grind
val registry = CommandRegistry().register(SendDigestCommand::class.java)
val code = Grind.call("mail:digest", listOf("42", "--queue=default"), registry)val quiet = Grind.callSilently("schedule:run", listOf("--base=$root"))val listed = Grind.call("list")import org.konaframework.grind.CommandRegistry;import org.konaframework.grind.Grind;import java.util.List;
CommandRegistry registry = new CommandRegistry().register(SendDigestCommand.class);
int code = Grind.call("mail:digest", List.of("42", "--queue=default"), registry);int quiet = Grind.callSilently("schedule:run", List.of("--base=" + root));int listed = Grind.call("list");Grind.call resolution
Section titled “Grind.call resolution”Overloads accept combinations of name, args, optional CommandRegistry, basePath, and ClassLoader (all @JvmStatic).
- Merge the optional registry with
CommandDiscovery.registerAllon the given loader. - If the merged registry has the name, run it through
CommandExecutor(custom-command path: signature bind,--help,--isolated). - Otherwise fall through to
GrindApplication.run(name + args)so built-ins (serve,migrate,list, …) still work.
callSilently temporarily replaces System.out with a buffer so normal stdout is suppressed; stderr still surfaces errors from GrindIO.error / ConsoleIO.error.
Default basePath is the current working directory (absolute, normalized). Default loader is Grind’s class loader.
Scheduling hooks
Section titled “Scheduling hooks”Register work on the application Schedule, then run due tasks with Grind Console:
./grind schedule:run./grind schedule:list./grind schedule:work --sleep=60 --max=1Those commands boot the app in-process (via the same loader path as migrate) and require ScheduleServiceProvider so a Schedule is bound.
Custom Grind Console commands are ordinary processes: point a scheduled callback at a shell invocation of ./grind your:command, or call Grind.call from code the scheduler already runs. For isolatable cron-style commands, combine schedule with --isolated.
Full guide: Task scheduling.
Testing
Section titled “Testing”Capture stdout and exit codes with ConsoleTester:
ConsoleTester() .run("list") .assertOk() .assertSee("schedule:run")See HTTP & console tests. For custom commands, compile the app first so discovery can see META-INF/kona/commands and build/classes.
Lifecycle cheat sheet
Section titled “Lifecycle cheat sheet”| Step | What runs |
|---|---|
| Parse argv | Positionals + options map; build GrindIO.fromOptions |
| Discover | CommandDiscovery on grind’s loader + optional app build/ outputs |
| Dispatch | Built-in when branches, else CommandRegistry.create + CommandExecutor |
| Custom bind | Signature → CommandInput; optional isolation lock |
| Finish | Exit code from built-in run / handle() / help / errors |
Pitfalls
Section titled “Pitfalls”- Wrong directory — many generators use
--baseas-is;serve/key:generate/kona grindwalk upward to a Gradle root. - Silent stdout ≠ silent errors —
-qandcallSilentlydo not hideerror(...). - Registry-only names in
Grind.call— if you pass a registry without putting the command on the class loader’sMETA-INF, that is fine; if you rely only onMETA-INF, ensure the loader can see resources. - Built-in vs custom help —
--helpon a custom command is rich; on many built-ins you get usage via exceptions or dedicated output instead.