Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.praison.ai/llms.txt

Use this file to discover all available pages before exploring further.

PraisonAI picks one of five paths based on what you type — and adding a new subcommand means it Just Works.

Quick Start

1

Check Version

praisonai --version
# Fast path - no heavy imports
2

Interactive Mode

praisonai
# Drops into Typer's interactive TUI
3

Get Help

praisonai --help
# Auto-generated help with all subcommands
4

Use Subcommands

praisonai chat "Build a weather agent"
# Routes to Typer automatically
5

Free-text Prompts

praisonai "Build a weather agent"
# Routes to legacy for direct prompts

How It Works

ComponentPurposeRoute Decision
main()Entry routerApplies 5 rules in order
_find_first_command()Positional finderSkips flags, finds command
_get_typer_commands()Auto-discoveryCached command introspection
TyperSubcommand handlerRegistered commands only
LegacyFallback handlerEverything else

Routing Rules

#What you typeRouteNotes
1praisonai --version / praisonai -VVersion short-circuitPrints version and returns. Does not import praisonai.cli.* — stays fast even with broken optional deps. Pinned by TestVersionShortCircuit.
2praisonai --help / praisonai -hTyperTyper’s auto-generated help lists every registered subcommand (auto-discovered, no manual list).
3praisonai (no argv)TyperDrops into Typer’s interactive TUI.
4praisonai --verbose / praisonai -o json (only flags)Typer_find_first_command returns None → Typer handles global-flag-only cases.
5praisonai chat ... (first positional ∈ registered commands)TyperAuto-discovered via Click introspection of app. Adding a new subcommand to cli/app.py makes it routable here with zero dispatcher changes.
6praisonai "Build a weather agent" (free-text — token contains a space)Legacy PraisonAI().main()Free-text prompts always fall through to legacy.
7praisonai agents.yaml (filename, not a registered command)Legacy PraisonAI().main()Routing decision is by command-set membership, NOT by os.path.isfile(). A typo’d YAML path also routes to legacy and surfaces there.
8praisonai totally-unknown (unknown positional)Legacy PraisonAI().main()Same as row 7 — anything not in the discovered command set falls through.

Auto-Discovery

Commands registered in praisonai/cli/app.py become routable automatically through Click introspection.
Adding a new subcommand? Register it in praisonai/cli/app.py (e.g. app.add_typer(my_app, name="mycmd")) and the dispatcher picks it up automatically — praisonai mycmd ... routes to Typer with no changes to __main__.py. The command set is discovered once via click.Context.list_commands() and cached behind a thread-safe lock.
# In praisonai/cli/app.py
from .commands.mycmd import app as mycmd_app

def register_commands():
    # ... other commands ...
    app.add_typer(mycmd_app, name="mycmd", help="My new command")
    # That's it - no dispatcher changes needed
The auto-discovery cache (_get_typer_commands()) works by:
  1. Importing the Typer app and calling register_commands()
  2. Using Click’s introspection to list all registered commands
  3. Caching the result in _typer_commands_cache with thread safety
  4. Returning an empty set on failure (cache not poisoned for retry)

Common Patterns

Bare Prompt

praisonai "Create a Python script that scrapes weather data"
# Routes to legacy - spaces in token indicate free-text prompt

YAML File

praisonai agents.yaml
# Routes to legacy - filename not in registered command set

Subcommand with Global Flags

praisonai --verbose chat "Hello world"
# --verbose is skipped when finding first positional (chat)
# Routes to Typer since 'chat' is a registered command

Best Practices

The --version flag takes a fast path that prints version information without importing any praisonai.cli.* modules. This keeps the command responsive even if optional dependencies are broken or missing. The version check happens before any heavy imports or command discovery.
To add a new subcommand, simply register it in praisonai/cli/app.py using app.add_typer(). The dispatcher automatically discovers it through Click introspection with no manual updates needed to routing logic. The command becomes available immediately after registration.
When you mistype a command name, it routes to legacy mode instead of showing a Typer “command not found” error. This design choice ensures that typo’d commands behave like free-text prompts, maintaining backward compatibility while still allowing auto-discovery of new commands.
Registration errors from register_commands() propagate directly to the user — the dispatcher does not swallow them. If an optional dependency is missing or a command fails to register, you see the real error instead of silent fallback behavior. This fail-loud approach aids debugging.

Registration errors fail loud. If register_commands() raises (e.g. an ImportError from a missing optional dep), the exception propagates from praisonai ... — you see the real error, not Typer’s “no command” page. This is intentional and pinned by tests.

CLI Reference

Complete command reference

CLI Commands

Basic CLI usage guide

Gateway

Multi-bot WebSocket gateway

Version

Version management