Sphinx Integration

Cyclopts provides builtin Sphinx support.

Quick Start

  1. Add the extension to your Sphinx configuration (docs/conf.py):

    extensions = [
        'cyclopts.sphinx_ext',  # Add this line
        # ... your other extensions
    ]
    
  2. Use the directive in your RST files:

    .. cyclopts:: mypackage.cli:app
    

Directive Usage

Basic Syntax

The cyclopts directive accepts a module path to your Cyclopts App object:

.. cyclopts:: mypackage.cli:app

Module Path Formats

The directive accepts two module path formats:

  1. Explicit format (module.path:app_name):

    .. cyclopts:: mypackage.cli:app
    .. cyclopts:: myapp.commands:main_app
    .. cyclopts:: src.cli:cli
    

    This explicitly specifies which App object to document.

  2. Automatic discovery (module.path):

    .. cyclopts:: mypackage.cli
    .. cyclopts:: myapp.main
    

    The extension will search the module for an App instance, looking for common names like app, cli, or main.

Directive Options

The directive supports several options to customize the generated documentation:

:heading-level: - Heading Level

Set the starting heading level for the generated documentation (1-6, default: 2):

.. cyclopts:: mypackage.cli:app
   :heading-level: 3

This is useful when you need to adjust the heading hierarchy. The default of 2 works well for most cases where the directive is placed under a page title.

:max-heading-level: - Maximum Heading Level

Set the maximum heading level to use (1-6, default: 6):

.. cyclopts:: mypackage.cli:app
   :max-heading-level: 4

Headings deeper than this level will be capped at this value. This is useful for deeply nested command hierarchies where you want to prevent headings from becoming too small.

:no-recursive: - Exclude Subcommands

Disable recursive documentation of subcommands (by default, subcommands are included):

.. cyclopts:: mypackage.cli:app
   :no-recursive:

When this flag is present, only the top-level commands are documented.

:include-hidden: - Show Hidden Commands

Include commands marked with show=False in the documentation:

.. cyclopts:: mypackage.cli:app
   :include-hidden: true

By default, hidden commands are not included in the generated documentation.

:flatten-commands: - Generate Flat Command Hierarchy

Generate all commands at the same heading level instead of nested hierarchy:

.. cyclopts:: mypackage.cli:app
   :flatten-commands:

This creates distinct, equally-weighted headings for each command and subcommand, making them easier to reference and navigate in the documentation. Without this option, subcommands are nested with incrementing heading levels.

:code-block-title: - Render Titles as Inline Code

Render command titles with inline code formatting instead of plain text:

.. cyclopts:: mypackage.cli:app
   :code-block-title:

When this flag is present, command titles are rendered with monospace formatting, which can be useful for certain documentation themes or to make command names stand out visually.

:commands: - Filter Specific Commands

Document only specific commands from your CLI application:

.. cyclopts:: mypackage.cli:app
   :commands: init, build, deploy

This will only document the specified commands. You can also use nested command paths with dot notation:

.. cyclopts:: mypackage.cli:app
   :commands: db.migrate, db.backup, api
  • db.migrate - Documents only the migrate subcommand under db

  • db.backup - Documents only the backup subcommand under db

  • api - Documents the api command and all its subcommands

You can use either underscore or dash notation in command names - they will be normalized automatically.

:exclude-commands: - Exclude Specific Commands

Exclude specific commands from the documentation:

.. cyclopts:: mypackage.cli:app
   :exclude-commands: debug, internal-test

This is useful for hiding internal or debug commands from user-facing documentation. Like :commands:, this also supports nested command paths with dot notation.

:skip-preamble: - Skip Description and Usage

Skip the description and usage sections for the target command when filtering to a single command:

.. cyclopts:: mypackage.cli:app
   :commands: deploy
   :skip-preamble:

When you filter to a single command using :commands: and provide your own section heading in the RST, you may not want the directive to generate the command's description and usage block. Adding :skip-preamble: suppresses these sections while still generating the command's parameters and subcommands.

This is useful when you want to write your own introduction for a command section:

Deployment
==========

Deploy your application to production with these commands.

.. cyclopts:: mypackage.cli:app
   :commands: deploy
   :skip-preamble:

Without :skip-preamble:, the output would include both your introduction and the command's docstring description, which can be redundant.

:usage-name: - Override the Command Shown in Usage Lines

Replace the app name shown in Usage: lines of the generated documentation with a custom invocation string:

.. cyclopts:: mypackage.cli:app
   :usage-name: uv run cli

This is useful when the documented invocation differs from the app's configured name. For example, an App(name="cli", ...) installed as a project entry point might typically be invoked as uv run cli; setting :usage-name: uv run cli renders that in every Usage: block while section headings, anchors, and the table of contents continue to reference the plain cli name.

Automatic Reference Labels

The Sphinx directive automatically generates RST reference labels for all commands, enabling cross-referencing throughout your documentation. The anchor format is cyclopts-{app-name}-{command-path}, which prevents naming conflicts when documenting multiple CLIs.

For example: - Root application: cyclopts-myapp - Subcommand: cyclopts-myapp-deploy - Nested subcommand: cyclopts-myapp-deploy-production

You can reference these commands elsewhere in your documentation using :ref:`cyclopts-myapp-deploy`.

Complete Example

Here's a complete example showing a CLI application and its Sphinx documentation:

CLI Application (myapp/cli.py):

from pathlib import Path
from typing import Optional
from cyclopts import App

app = App(
    name="myapp",
    help="My awesome CLI application",
    version="1.0.0"
)

@app.command
def init(path: Path = Path("."), template: str = "default"):
    """Initialize a new project.

    Parameters
    ----------
    path : Path
        Directory where the project will be created
    template : str
        Project template to use
    """
    print(f"Initializing project at {path}")

@app.command
def build(source: Path, output: Optional[Path] = None, *, minify: bool = False):
    """Build the project.

    Parameters
    ----------
    source : Path
        Source directory
    output : Path, optional
        Output directory (defaults to source/dist)
    minify : bool
        Minify the output files
    """
    output = output or source / "dist"
    print(f"Building from {source} to {output}")

if __name__ == "__main__":
    app()

Sphinx Configuration (docs/conf.py):

import sys
from pathlib import Path

# Add your package to the path
sys.path.insert(0, str(Path(__file__).parent.parent))

# Extensions
extensions = [
    'cyclopts.sphinx_ext',
    'sphinx.ext.autodoc',  # For API docs
    'sphinx.ext.napoleon',  # For NumPy-style docstrings
]

# Project info
project = 'MyApp'
author = 'Your Name'
version = '1.0.0'

# HTML theme
html_theme = 'sphinx_rtd_theme'

Documentation File (docs/cli.rst):

CLI Reference
=============

This section documents all available CLI commands.

.. cyclopts:: myapp.cli:app

The above directive will automatically generate documentation for all
commands, including their parameters, types, defaults, and help text.

Advanced Usage

Using Distinct Command Headings

When you want each command to have its own distinct heading for better navigation and referencing:

CLI Command Reference
=====================

.. cyclopts:: myapp.cli:app
   :flatten-commands:
   :code-block-title:

This generates:

- All commands at the same heading level (not nested)
- Command titles with monospace formatting
- Automatic reference labels for cross-linking

You can then reference specific commands:

See :ref:`cyclopts-myapp-deploy` for deployment options.
The :ref:`cyclopts-myapp-init` command sets up your project.

Selective Command Documentation

Split your CLI documentation across multiple sections or pages:

Database Commands
=================

The following commands manage database operations:

.. cyclopts:: myapp.cli:app
   :commands: db

API Management
==============

Commands for controlling the API server:

.. cyclopts:: myapp.cli:app
   :commands: api

Development Tools
=================

Utilities for development (excluding internal debug commands):

.. cyclopts:: myapp.cli:app
   :commands: dev
   :exclude-commands: dev.debug, dev.internal

This approach allows you to:

  • Organize large CLI applications into logical sections

  • Document different command groups on separate pages

  • Exclude internal or debug commands from user documentation

  • Create targeted documentation for different audiences

Output Formats

While the Sphinx directive uses RST internally, you can also generate documentation programmatically in multiple formats:

from myapp.cli import app

# Generate reStructuredText
rst_docs = app.generate_docs(output_format="rst")

# Generate Markdown
md_docs = app.generate_docs(output_format="markdown")

# Generate HTML
html_docs = app.generate_docs(output_format="html")

This is useful for generating documentation outside of Sphinx, such as for GitHub README files or other documentation systems.

See Also