# Help

A help screen is standard for every CLI application. Cyclopts by-default adds `--help` and `-h` flags to the application:

    $ my-application --help
    Usage: my-application COMMAND

    My application short description.

    ╭─ Commands ─────────────────────────────────────────────────────────╮
    │ foo        Foo help string.                                        │
    │ bar        Bar help string.                                        │
    │ --help -h  Display this message and exit.                          │
    │ --version  Display application version.                            │
    ╰────────────────────────────────────────────────────────────────────╯

Cyclopts derives the components of the help string from a variety of sources. The source resolution order is as follows (as applicable):

1. The `help` field in the `@app.command` decorator.

       app = cyclopts.App()

       @app.command(help="This is the highest precedence help-string for 'bar'.")
       def bar():
           pass

   When registering an `App` object, supplying `help` via the `@app.command` decorator is forbidden to reduce ambiguity and will raise a `ValueError`. See (2).

2. Via `App.help`.

       app = cyclopts.App(help="This help string has highest precedence at the app-level.")

       sub_app = cyclopts.App(help="This is the help string for the 'foo' subcommand.")
       app.command(sub_app, name="foo")
       app.command(sub_app, name="foo", help="This is illegal and raises a ValueError.")

3. The `__doc__` docstring of the registered `@app.default` command. Cyclopts parses the docstring to populate short-descriptions and long-descriptions at the command-level, as well as at the parameter-level.

       app = cyclopts.App()
       app.command(cyclopts.App(), name="foo")

       @app.default
       def bar(val1: str):
           """This is the primary application docstring.

           Parameters
           ----------
           val1: str
               This will be parsed for val1 help-string.
           """

       @app["foo"].default  # You can access sub-apps like a dictionary.
       def foo_handler():
           """This will be shown for the "foo" command."""

   Note

   Docstrings should always use the Python variable name from the function signature.

       @app.default
       def main(internal_name: Annotated[str, Parameter(name="external-name")]):
           """Command description.

           Parameters
           ----------
           internal_name:            # Use the Python variable name
               Help text here.
           """

   This follows standard Python documentation conventions; the parameter will still appear as `--external-name` on the CLI.

4. This resolution order, but of the Meta App.

       app = cyclopts.App()

       @app.meta.default
       def bar():
           """This is the primary application docstring."""

## Markup Format

While the standard markup language for docstrings in Python is reStructuredText (see PEP-0287), Cyclopts defaults to Markdown for better readability and simplicity. Cyclopts mostly respects PEP-0257, but has some slight differences for developer ergonomics:

1. The "summary line" (AKA short-description) may actually be multiple lines. Cyclopts will unwrap the first block of text and interpret it as the short description. The first block of text ends at the first double-newline (i.e. a single blank line) is reached.

       def my_command():
           """
           This entire sentence
           is part of the short description and will
           have all the newlines removed.

           This is the beginning of the long description.
           """

2. If a docstring is provided with a long description, it must also have a short description.

By default, Cyclopts parses docstring descriptions as markdown and renders it appropriately. To change the markup format, set the `App.help_format` field accordingly. The different options are described below.

Subapps inherit their parent's `App.help_format` unless explicitly overridden. I.e. you only need to set `App.help_format` in your main root application for all docstrings to be parsed appropriately.

### PlainText

Do not perform any additional parsing, display supplied text as-is.

    from cyclopts import App

    app = App(help_format="plaintext")

    @app.default
    def default():
        """My application summary.

        This is a pretty standard docstring; if there's a really long sentence
        I should probably wrap it because people don't like code that is more
        than 80 columns long.

        In this new paragraph, I would like to discuss the benefits of relaxing 80 cols to 120 cols.
        More text in this paragraph.

        Some new paragraph.
        """

    app()

    Usage: default COMMAND

    My application summary.

    This is a pretty standard docstring; if there's a really long
    sentence
    I should probably wrap it because people don't like code that is
    more
    than 80 columns long.

    In this new paragraph, I would like to discuss the benefits of
    relaxing 80 cols to 120 cols.
    More text in this paragraph.

    Some new paragraph.

    ╭─ Commands ─────────────────────────────────────────────────────╮
    │ --help,-h  Display this message and exit.                      │
    │ --version  Display application version.                        │
    ╰────────────────────────────────────────────────────────────────╯

Most noteworthy, is no additional text reflow is performed; newlines are presented as-is.

### Rich

Displays text as Rich Markup.

Note

Newlines are interpreted literally.

    from cyclopts import App

    app = App(help_format="rich")

    @app.default
    def default():
       """Rich can display colors like [red]red[/red] easily.

       However, I cannot be bothered to figure out how to show that in documentation.
       """

    app()

    Usage: default COMMAND

    Rich can display colors like red easily.

    ╭─ Commands ───────────────────────────────────────────────────────╮
    │ --help -h  Display this message and exit.                        │
    │ --version  Display application version.                          │
    ╰──────────────────────────────────────────────────────────────────╯

### ReStructuredText

ReStructuredText can be enabled by setting help_format to "restructuredtext" or "rst".

    app = App(help_format="restructuredtext")  # or "rst"

    @app.default
    def default():
        """My application summary.

        We can do RST things like have **bold text**.
        More words in this paragraph.

        This is a new paragraph with some bulletpoints below:

        * bullet point 1.
        * bullet point 2.
        """

    app()

Resulting help:

    Usage: default COMMAND

    My application summary.

    We can do RST things like have bold text. More words in this
    paragraph.

    This is a new paragraph with some bulletpoints below:

    1. bullet point 1.
    2. bullet point 2.

    ╭─ Commands ──────────────────────────────────────────────────────────╮
    │ --help -h  Display this message and exit.                           │
    │ --version  Display application version.                             │
    ╰─────────────────────────────────────────────────────────────────────╯

Under most circumstances, plaintext (without any additional markup) looks prettier and reflows better when interpreted as restructuredtext (or markdown, for that matter).

### Markdown

Markdown is the default parsing behavior of Cyclopts, so help_format won't need to be explicitly set. It's another popular markup language that Cyclopts can render.

    app = App(help_format="markdown")  # or "md"
    # or don't supply help_format at all; markdown is default.

    @app.default
    def default():
        """My application summary.

        We can do markdown things like have **bold text**.
        [Hyperlinks work as well.](https://cyclopts.readthedocs.io)
        """

Resulting help:

    Usage: default COMMAND

    My application summary.

    We can do markdown things like have bold text. Hyperlinks work as well.

    ╭─ Commands ──────────────────────────────────────────────────────────╮
    │ --help -h  Display this message and exit.                           │
    │ --version  Display application version.                             │
    ╰─────────────────────────────────────────────────────────────────────╯

## Help Flags

The default `--help` flags can be changed to different name(s) via the `help_flags` parameter.

    app = cyclopts.App(help_flags="--show-help")
    app = cyclopts.App(help_flags=["--send-help", "--send-help-plz", "-h"])

To disable the help-page entirely, set `help_flags` to an empty string or iterable.

    app = cyclopts.App(help_flags="")
    app = cyclopts.App(help_flags=[])

## Help Prologue and Epilogue

An epilogue is text displayed at the end of the help screen, after all command and parameter panels. A prologue is text display at the beginning of the help screen, before the usage section. This is commonly used for version information, support contact details, or additional notes.

The epilogue is set via the `App.help_epilogue` attribute:

    from cyclopts import App

    app = App(
        name="myapp",
        help="My application description.",
        help_epilogue="Support: support@example.com"
    )

    @app.default
    def main():
        """Main command."""
        pass

    app()

    $ myapp --help
    Usage: myapp [ARGS]

    My application description.

    ╭─ Commands ────────────────────────────────────────────────────────────╮
    │ --help -h  Display this message and exit.                             │
    │ --version  Display application version.                               │
    ╰───────────────────────────────────────────────────────────────────────╯

    Support: support@example.com

The prologue is set via the `App.help_prologue` attribute:

    from cyclopts import App

    app = App(
        name="myapp",
        help="My application help.",
        help_prologue=f"myapp, v1.0.0 (http://example.myapp.com)"
    )
    app()

    $ my-script --help
    myapp, v1.0.0 (http://example.myapp.com)

    Usage: myapp COMMAND

    My application help.

    ╭─ Commands ────────────────────────────────────────────────────────────╮
    │ --help -h  Display this message and exit.                             │
    │ --version  Display application version.                               │
    ╰───────────────────────────────────────────────────────────────────────╯

Like `App.help_format`, epilogues and prologues inherit from parent to child apps. This allows you to set a single epilogue or prologue that applies across your entire application:

    parent = App(
        name="myapp",
        help_epilogue="Version 1.0.0 | support@example.com"
    )

    # Child inherits parent's epilogue
    child = App(name="process", help="Process data files.")
    parent.command(child)

    # Another child overrides with its own epilogue
    admin = App(
        name="admin",
        help="Admin commands.",
        help_epilogue="Admin Tools v2.0 | USE WITH CAUTION"
    )
    parent.command(admin)

    parent()

    $ myapp process --help
    Usage: myapp process

    Process data files.

    Version 1.0.0 | support@example.com    # Inherited from parent

    $ myapp admin --help
    Usage: myapp admin

    Admin commands.

    Admin Tools v2.0 | USE WITH CAUTION    # Overridden by child

To disable the epilogue or prologue for a specific subcommand, set it to an empty string:

    no_epilogue = App(name="internal", help_epilogue="")
    parent.command(no_epilogue)

    no_prologue = App(name="internal", help_prologue="")
    parent.command(no_prologue)

## Help Customization

For advanced customization of help screen appearance, including custom formatters, styled panels, and dynamic column layouts, see Help Customization.