Customizing Help Output
Every knob that shapes --help in one place: what renders where, which attribute controls it, and what wins when several apply. (Spacing simplified in the samples below.)
Where everything renders
A fully dressed --help looks like this, top to bottom:
Deploy an application <- description
Usage: deploy [OPTIONS] <artifact> <- synopsis (collapseSynopsis)
Runs the deployment pipeline. <- header
Arguments: <- argumentsSection = FIRST (or LAST: after Options:)
<artifact> The artifact to deploy
Options: <- default Options section
-h, --help Display this help and exit
--target=<target> Target environment
Environments: <- helpGroup (@Option)
--prod Deploy to production
Examples: <- provider sections
deploy app.jar Deploy the jar
Documentation: https://example.com/deploy <- helpUrl
For support, contact ops@example.com <- footerFor group commands, a <name> commands: listing (or the named helpGroup sections plus Other:) is inserted after the options and before the footer. A group-level -h behaves like the subcommand’s own: app -h run shows run’s help instead of failing on its required options. The provider’s additional sections merge into that listing: a section whose name matches a helpGroup is appended to the group instead of creating a duplicate heading.
Which knob do I need?
| I want to… | Use |
|---|---|
Collapse a long Usage: line to [OPTIONS] | collapseSynopsis = Toggle.ON |
| Show each option’s default under its description | showDefaultValues = Toggle.ON |
| Print my own options before named groups | defaultOptionsFirst = Toggle.ON |
Print the header before the Usage: line instead of after it (terminal --help only) | headerBeforeSynopsis = Toggle.ON |
| Reject a repeated single-value option | failOnDuplicateOptions = Toggle.ON |
Give positionals their own Arguments: heading, first or last | argumentsSection = ArgumentsSection.FIRST (or LAST) |
| Sort options alphabetically | sortOptions = true |
| Static brand text or examples, top or bottom | header / footer |
| Dynamic or plugin-provided sections | helpSectionProvider, or implement HelpSectionProvider on the command itself |
| One provider serving many commands | A HelpContext overload, keyed by context.fullName() |
| This command listed under a heading in the parent | helpGroup on the subcommand (it renders in the parent, not here) |
| Show a positional inside an option group | helpGroup on @Argument/@Arguments (+ order to position it) |
| A docs link at the end of help | helpUrl |
What wins
Each layer is stated once here; the individual attributes link back to this page.
- Header/footer/sections: an explicit
HelpSectionProvidervalue beats the annotationheader/footer. With no provider set, a command that implementsHelpSectionProviderprovides for itself. - Toggles: an explicit
ON/OFFbeats the parent group’s resolved value, which beats the fleet default, which beats off. The arguments section works the same way with four states (OFF/FIRST/LAST), defaulting to off instead of a toggle:
AeshCommandRegistryBuilder.<CommandInvocation>builder()
.helpDefaults(EnumSet.of(HelpFeature.SHOW_DEFAULT_VALUES))
.argumentsSectionDefault(ArgumentsSection.FIRST)
.command(MyGroup.class)
...Grouped positionals
A positional with a helpGroup leaves the positional flow and renders inside that option group, sharing the group’s order namespace with its options (lower prints first; ties keep options before positionals, positionals in index order). Ungrouped positionals are unaffected, so a command can mix both.
@Option(description = "Target environment", helpGroup = "Environments", order = 1)
String target;
@Argument(description = "The artifact to deploy", helpGroup = "Environments", order = 2)
String artifact;Help width
Help wraps to the live terminal width when one answers, so the same --help reflows on narrow and wide terminals. Resolution order: the aesh.help.width system property, then the COLUMNS environment variable, then the terminal width, then 80 columns. Anything below 40 columns clamps up to 40.
One command using several knobs
@CommandDefinition(
name = "deploy",
description = "Deploy an application",
generateHelp = true,
header = "Runs the deployment pipeline.",
footer = "For support, contact ops@example.com",
helpUrl = "https://example.com/deploy",
argumentsSection = ArgumentsSection.FIRST,
showDefaultValues = Toggle.ON
)
public class DeployCommand implements Command<CommandInvocation> {
@Option(description = "Target environment", defaultValue = "staging")
String target;
@Option(description = "Deploy to production", helpGroup = "Environments", hasValue = false)
boolean prod;
@Argument(description = "The artifact to deploy")
String artifact;
@Override
public CommandResult execute(CommandInvocation invocation) {
...
}
}Beyond the terminal
The same providers feed the generated docs (AsciiDoc, Markdown, AI skill files), where the HelpContext also carries the output format so content can differ per format. See Documentation Generation.