CLI

Modular command-line interface

5 min read 982 words

Structure: Modular command-line interface with Click framework

Location:bengal/cli/directory with organized command modules

Architecture:

  • bengal/cli/__init__.py- Main CLI group with command registration and typo detection

  • bengal/cli/base.py - Custom Click classes (BengalGroup, BengalCommand) with themed help

  • bengal/cli/commands/- Individual command modules

    • build.py- Build commands
    • serve.py- Development server
    • graph/- Graph analysis commands (package with report, orphans, pagerank, etc.)
    • perf.py- Performance analysis
    • clean.py- Cleanup utilities
    • new/- Content creation (package with presets, wizard, config, site, scaffolds)
    • validate.py- Content validation

    Features:

  • Typo Detection: Fuzzy matching for command names with suggestions

  • Rich Output: Colored output and progress bars using Rich library

  • Error Handling: Beautiful tracebacks with context and locals

  • Extensibility: Easy to add new commands in separate modules

Core Commands

Build Commands {#build-commands}:

# Basic build (parallel by default)
bengal build

# Incremental build (uses cache for faster rebuilds)
bengal build --incremental

# Force sequential processing (disable auto-parallel)
bengal build --no-parallel

# Strict mode (fail on template errors, recommended for CI)
bengal build --strict

# Debug mode (full tracebacks, developer profile)
bengal build --debug

# Verbose output (show detailed phase timing and stats)
bengal build --verbose

# Fast mode (quiet output, max speed)
bengal build --fast

# Memory-optimized for large sites (5K+ pages)
bengal build --memory-optimized

# Preview build without writing files (see what WOULD happen)
bengal build --dry-run

# Show detailed breakdown of why pages are rebuilt/skipped
bengal build --explain

# Machine-readable explain output (for tooling)
bengal build --explain --explain-json

Development Commands {#serve-commands}:

# Start development server with file watching
bengal serve

# Custom port
bengal serve --port 8080

# Disable file watching
bengal serve --no-watch

# Open browser automatically (default)
bengal serve --open

# Verbose output (show file watch events)
bengal serve --verbose

Graph Analysis Commands:

# Top-level graph command group
bengal graph

# Unified site analysis report
bengal graph report
bengal graph report --brief          # CI-friendly compact output
bengal graph report --format json    # Export as JSON

# CI integration with thresholds
bengal graph report --ci --threshold-isolated 5

# Connectivity analysis by level
bengal graph orphans                 # Show isolated pages (score < 0.25)
bengal graph orphans --level lightly # Show lightly-linked pages
bengal graph orphans --level all     # Show all under-linked pages
bengal graph orphans --format json   # Export with detailed metrics

# Analyze site structure and connectivity
bengal graph analyze
bengal graph analyze --tree          # Show site structure as tree
bengal graph analyze --output public/graph.html  # Interactive viz

# Compute PageRank scores
bengal graph pagerank --top 20

# Detect topical communities
bengal graph communities --min-size 3

# Find bridge pages (navigation bottlenecks)
bengal graph bridges --top 10

# Get link suggestions
bengal graph suggest --min-score 0.5

# Short aliases
bengal g report                      # g → graph
bengal analyze                       # Top-level alias for graph analyze

Example: bengal graph report Output

📊 Site Analysis Report
================================================================================
📈 Overview
   Total pages:        124
   Avg conn. score:    1.46

🔗 Connectivity Distribution
   🟢 Well-Connected:      39 pages (31.5%)
   🟡 Adequately:          38 pages (30.6%)
   🟠 Lightly Linked:      26 pages (21.0%)
   🔴 Isolated:            21 pages (16.9%) ⚠️
================================================================================

Refer to Graph Analysis for details and Analyze site connectivity for a guided walkthrough.

Performance Commands:

# Show recent build performance metrics
bengal perf

# Show last N builds
bengal perf --last 20

# Compare last two builds
bengal perf --compare

# Export as JSON
bengal perf --format json

Utility Commands:

# Clean output directory
bengal clean

# Clean cache and output
bengal clean --cache

# Create new site
bengal new site mysite

# Create new page
bengal new page content/blog/post.md

# Show version
bengal --version

# Show help
bengal --help

Upgrade Commands:

# Check for updates and upgrade interactively
bengal upgrade

# Skip confirmation prompt
bengal upgrade -y

# Show what would be done without executing
bengal upgrade --dry-run

# Force upgrade even if already on latest
bengal upgrade --force

The upgrade command automatically detects how Bengal was installed (uv, pip, pipx, conda) and runs the appropriate upgrade command. It checks PyPI for the latest version with a 24-hour cache to avoid repeated network requests.

Command Registration

Commands are registered inbengal/cli/__init__.py. The CLI uses command groups for organization and top-level aliases for convenience:

from bengal.cli.base import BengalCommand, BengalGroup
from bengal.cli.commands.build import build as build_cmd
from bengal.cli.commands.serve import serve as serve_cmd
from bengal.cli.commands.clean import clean as clean_cmd
from bengal.cli.commands.graph import graph_cli
from bengal.cli.commands.new import new

@click.group(cls=BengalGroup, name="bengal", invoke_without_command=True)
@click.version_option(version=__version__, prog_name="Bengal SSG")
def main(ctx: click.Context) -> None:
    """Bengal Static Site Generator CLI."""
    pass

# Command groups (organized by category)
main.add_command(graph_cli)       # bengal graph <subcommand>
main.add_command(new)             # bengal new <subcommand>

# Top-level aliases (most common operations)
main.add_command(build_cmd, name="build")
main.add_command(serve_cmd, name="serve")
main.add_command(clean_cmd, name="clean")

# Short aliases for power users
main.add_command(build_cmd, name="b")   # b → build
main.add_command(serve_cmd, name="s")   # s → serve
main.add_command(serve_cmd, name="dev") # dev → serve
main.add_command(graph_cli, name="g")   # g → graph

Custom Click Group

Bengal uses customBengalGroup and BengalCommand classes in bengal/cli/base.pythat provide themed help output and typo detection:

class BengalGroup(click.Group):
    """Custom Click group with typo detection and themed help output."""

    command_class = BengalCommand  # Use themed command class

    def resolve_command(self, ctx, args):
        """Resolve command with fuzzy matching for typos."""
        try:
            return super().resolve_command(ctx, args)
        except click.exceptions.UsageError as e:
            if "No such command" in str(e) and args:
                unknown_cmd = args[0]
                suggestions = self._get_similar_commands(unknown_cmd)
                if suggestions:
                    cli = CLIOutput()
                    cli.error_header(f"Unknown command '{unknown_cmd}'.")
                    cli.console.print("[header]Did you mean one of these?[/header]")
                    for suggestion in suggestions:
                        cli.console.print(f"  [info]•[/info] {suggestion}")
                    raise SystemExit(2)
            raise

    def _get_similar_commands(self, unknown_cmd, max_suggestions=3):
        """Find similar commands using difflib fuzzy matching."""
        from difflib import get_close_matches
        return get_close_matches(unknown_cmd, self.commands.keys(),
                                 n=max_suggestions, cutoff=0.5)

Example: Command Suggestion

$ bengal bild
Unknown command 'bild'.

Did you mean one of these?
  • buildbridges

Run 'bengal --help' to see all commands.