API Reference

xclif

class xclif.Arg(description=None, name=None)[source]

Bases: object

Annotation metadata for positional arguments.

Use inside Annotated to attach a description or display name:

def copy(src: Annotated[str, Arg(description="Source file", name="SRC")]) -> None: ...
Parameters:
  • description (str | None)

  • name (str | None)

class xclif.Cascade[source]

Bases: object

Annotation metadata to cascade an option to subcommands.

Use as a type wrapper to make an option’s value available to all subcommands via get_context():

def root(
    base_url: Cascade[WithConfig[str]] = DEFAULT_BASE_URL,
) -> None: ...

Subcommands can then use get_context()["base_url"].

class xclif.Cli(root_command, version=None, env_prefix=None, config_name=None, local_config=None, config_command=True, completions_command=True, mcp_command=True, show_no_description=None)[source]

Bases: object

Entry point for an Xclif-powered CLI application.

Typically constructed via from_routes() (file-based routing) or from_manifest() (pre-compiled manifest for fast startup). Direct construction is only needed when using the flat decorator API.

Parameters:
  • root_command (xclif.command.Command) – The root Command of the CLI tree.

  • version (str | None) – Version string shown by --version. Auto-detected from package metadata when None.

  • env_prefix (str | None) – Prefix for environment-variable overrides (e.g. "MYAPP"MYAPP_FOO). Defaults to the uppercased root command name.

  • config_name (str | None) – App name used to locate the config directory via platformdirs. Defaults to the root command name.

  • local_config (str | None) – Filename to look for in the current working directory as a local config file (e.g. ".myapp.toml"). When set, the file is loaded and its values take priority over the user-level config but are still overridden by env vars and CLI flags. Supports .toml and .json extensions. None (the default) disables local config.

  • config_command (bool) – Whether to auto-inject the config subcommand when any parameter uses WithConfig. True (the default) keeps the current behaviour; set to False to suppress it.

  • completions_command (bool) – Whether to auto-inject the completions subcommand. True (the default) keeps the current behaviour; set to False to suppress it. Injection is also skipped when the root command already defines a completions subcommand or declares positional arguments (since a command with positional args cannot have subcommands).

  • mcp_command (bool) – Whether to auto-inject the mcp subcommand when the optional mcp package is installed. True (the default) keeps the current behaviour; set to False to suppress it. Injection is also skipped when the root command already defines an mcp subcommand or declares positional arguments.

  • show_no_description (bool | None) – Default value for show_no_description on all commands in the tree. When False, suppress the “No description” placeholder in help output for commands without a docstring. When None (the default), each command uses its own setting (True by default for backward compatibility). Per-command @command(show_no_description=...) overrides this default.

serve_mcp()[source]

Start an MCP stdio server exposing all leaf commands as tools.

Requires the optional ‘mcp’ package: pip install xclif[mcp]

Return type:

None

add_command(path, command)[source]

Mount command at the given path within the command tree.

path is a list of names from the root downward, e.g. ["server", "start"] mounts command as myapp server start. Intermediate groups are created automatically if they don’t exist.

Parameters:
  • path (list[str])

  • command (Command)

Return type:

None

classmethod from_manifest(manifest, *, version=None, env_prefix=None, config_name=None, local_config=None, show_no_description=None)[source]

Load a pre-compiled manifest produced by xclif compile.

This is a faster alternative to from_routes() — it skips the pkgutil.walk_packages + inspect.getmembers filesystem scan at the cost of a one-time xclif compile build step.

Parameters:
  • manifest (ModuleType) – The generated manifest module (typically myapp._xclif_manifest).

  • version (str | None) – Explicit version string. When None, auto-detected from the top-level package of manifest (same behaviour as from_routes()).

  • local_config (str | None) – Filename for cwd-based local config. See Cli.

  • env_prefix (str | None)

  • config_name (str | None)

  • show_no_description (bool | None)

Return type:

Self

classmethod from_routes(routes, *, version=None, env_prefix=None, config_name=None, local_config=None, show_no_description=None)[source]

Build a Cli by walking a routes package at runtime.

Each module in routes that exports a Command becomes a subcommand. The package structure determines the command hierarchy — see File-Based Routing for details.

Parameters:
  • routes (ModuleType) – The routes package module (e.g. import myapp.routes as routes).

  • version (str | None) – Explicit version string. When None, auto-detected from the top-level package of routes.

  • env_prefix (str | None) – Prefix for env-var overrides. Defaults to the uppercased root command name.

  • config_name (str | None) – App name for config directory resolution. Defaults to the root command name.

  • note:: (..) – For production CLIs, prefer from_manifest() to avoid the pkgutil.walk_packages overhead on every invocation.

  • local_config (str | None)

  • show_no_description (bool | None)

Return type:

Self

class xclif.Context(_data)[source]

Bases: object

Read-only view of cascading framework state.

Built-in properties provide typed access to implicit options:

ctx = get_context()
ctx.verbosity  # int (0–3)
ctx.colors     # "always" | "never" | "auto"

User-defined cascading options (marked with Cascade()) are accessible via dict-style lookup:

ctx["my_option"]
ctx.get("my_option", default)
Parameters:

_data (dict)

property verbosity: int

Verbosity level (0–3). Corresponds to -v / -vv / -vvv.

property colors: str

"always", "never", or "auto".

Type:

Color mode

property log_level: int

Standard logging level implied by verbosity.

get(key, default=None)[source]

Return the value for key, or default if not set.

Parameters:
Return type:

object

class xclif.Option(description=None, name=None)[source]

Bases: object

Annotation metadata for CLI options.

Use inside Annotated to attach a description or override the flag name:

def build(dry_run: Annotated[bool, Option(description="Skip execution", name="dry-run")] = False) -> None: ...

name overrides the CLI flag (--dry-run). The Python kwarg name is unchanged.

Parameters:
  • description (str | None)

  • name (str | None)

class xclif.Path(*args, **kwargs)[source]

Bases: PurePath

PurePath subclass that can make system calls.

Path represents a filesystem path but unlike PurePath, also offers methods to do system calls on path objects. Depending on your system, instantiating a Path will return either a PosixPath or a WindowsPath object. You can also instantiate a PosixPath or WindowsPath directly, but cannot instantiate a WindowsPath on a POSIX system or vice versa.

stat(*, follow_symlinks=True)[source]

Return the result of the stat() system call on this path, like os.stat() does.

lstat()[source]

Like stat(), except if the path points to a symlink, the symlink’s status information is returned, rather than its target’s.

exists(*, follow_symlinks=True)[source]

Whether this path exists.

This method normally follows symlinks; to check whether a symlink exists, add the argument follow_symlinks=False.

is_dir()[source]

Whether this path is a directory.

is_file()[source]

Whether this path is a regular file (also True for symlinks pointing to regular files).

is_mount()[source]

Check if this path is a mount point

Whether this path is a symbolic link.

is_junction()[source]

Whether this path is a junction.

is_block_device()[source]

Whether this path is a block device.

is_char_device()[source]

Whether this path is a character device.

is_fifo()[source]

Whether this path is a FIFO.

is_socket()[source]

Whether this path is a socket.

samefile(other_path)[source]

Return whether other_path is the same or not as this file (as returned by os.path.samefile()).

open(mode='r', buffering=-1, encoding=None, errors=None, newline=None)[source]

Open the file pointed to by this path and return a file object, as the built-in open() function does.

read_bytes()[source]

Open the file in bytes mode, read it, and close the file.

read_text(encoding=None, errors=None)[source]

Open the file in text mode, read it, and close the file.

write_bytes(data)[source]

Open the file in bytes mode, write to it, and close the file.

write_text(data, encoding=None, errors=None, newline=None)[source]

Open the file in text mode, write to it, and close the file.

iterdir()[source]

Yield path objects of the directory contents.

The children are yielded in arbitrary order, and the special entries ‘.’ and ‘..’ are not included.

glob(pattern, *, case_sensitive=None)[source]

Iterate over this subtree and yield all existing files (of any kind, including directories) matching the given relative pattern.

rglob(pattern, *, case_sensitive=None)[source]

Recursively yield all existing files (of any kind, including directories) matching the given relative pattern, anywhere in this subtree.

walk(top_down=True, on_error=None, follow_symlinks=False)[source]

Walk the directory tree from this directory, similar to os.walk().

classmethod cwd()[source]

Return a new path pointing to the current working directory.

classmethod home()[source]

Return a new path pointing to the user’s home directory (as returned by os.path.expanduser(‘~’)).

absolute()[source]

Return an absolute version of this path by prepending the current working directory. No normalization or symlink resolution is performed.

Use resolve() to get the canonical path to a file.

resolve(strict=False)[source]

Make the path absolute, resolving all symlinks on the way and also normalizing it.

owner()[source]

Return the login name of the file owner.

group()[source]

Return the group name of the file gid.

Return the path to which the symbolic link points.

touch(mode=438, exist_ok=True)[source]

Create this file with the given access mode, if it doesn’t exist.

mkdir(mode=511, parents=False, exist_ok=False)[source]

Create a new directory at this given path.

chmod(mode, *, follow_symlinks=True)[source]

Change the permissions of the path, like os.chmod().

lchmod(mode)[source]

Like chmod(), except if the path points to a symlink, the symlink’s permissions are changed, rather than its target’s.

Remove this file or link. If the path is a directory, use rmdir() instead.

rmdir()[source]

Remove this directory. The directory must be empty.

rename(target)[source]

Rename this path to the target path.

The target path may be absolute or relative. Relative paths are interpreted relative to the current working directory, not the directory of the Path object.

Returns the new Path instance pointing to the target path.

replace(target)[source]

Rename this path to the target path, overwriting if that path exists.

The target path may be absolute or relative. Relative paths are interpreted relative to the current working directory, not the directory of the Path object.

Returns the new Path instance pointing to the target path.

Make this path a symlink pointing to the target path. Note the order of arguments (link, target) is the reverse of os.symlink.

Make this path a hard link pointing to the same file as target.

Note the order of arguments (self, target) is the reverse of os.link’s.

expanduser()[source]

Return a new path with expanded ~ and ~user constructs (as returned by os.path.expanduser)

class xclif.WithConfig[source]

Bases: object

Marker for parameters that can be read from a config file or env var.

name: WithConfig[str] is sugar for Annotated[str, WithConfig()].

Priority order: CLI flag > env var > config file > default. Env var: <PREFIX>_<PARAM_NAME_UPPERCASED> Config key: the parameter name as-is.

xclif.command(*names, show_no_description=None)[source]

Convert a function into an xclif.Command.

Names are optional. The first name is the canonical command name; any additional names become aliases (alternative names that resolve to the same command). When no names are given, the function name is used (or the module name when the function is called _).

Parameters:
  • show_no_description (bool | None) – When False, suppress the “No description” placeholder in help output when no docstring is provided. When None (the default), uses the framework default (True for backward compatibility).

  • names (str)

Return type:

Callable[[Callable], Command]

xclif.configure_logging(verbosity=0, colors='auto', *, logger=None, level=None, force=False, console=None, show_time=False, show_level=True, show_path=None, markup=False, rich_tracebacks=True)[source]

Configure standard logging for an Xclif command run.

The root logger is used by default, so ordinary logging.getLogger calls in command code work without any Xclif-specific API. If logging has already been configured by the application, Xclif leaves existing handlers in place and only updates the logger level. Pass force=True to replace existing handlers with Xclif’s Rich handler.

Returns the installed handler, or None when existing non-Xclif handlers were respected.

Parameters:
Return type:

logging.Handler | None

xclif.get_context()[source]

Return the Context for the current command dispatch.

Raises RuntimeError if called outside of command dispatch (i.e., no command is currently being executed by the framework).

Return type:

Context

xclif.get_logger(name=None)[source]

Return a standard library logger.

This is a tiny convenience wrapper around logging.getLogger(); Xclif intentionally does not introduce its own logger abstraction.

Parameters:

name (str | None)

Return type:

Logger

xclif.level_from_verbosity(verbosity)[source]

Map Xclif verbosity counts to standard logging levels.

0 shows warnings and errors, 1 enables info logs, 2 enables debug logs, and 3 enables every record that reaches the configured logger. Values outside the supported range are clamped.

Parameters:

verbosity (int)

Return type:

int

xclif.command

class xclif.command.Command(name, run, arguments=<factory>, options=<factory>, subcommands=<factory>, implicit_options=<factory>, version=None, aliases=<factory>, show_no_description=True)[source]

Bases: object

A parsed command node in the CLI tree.

Normally you don’t construct this directly — use the command() decorator or Command.command() / Command.group() for the flat API. The file-based routing approach (Cli.from_routes) builds the tree automatically from the package layout.

Parameters:
print_short_help(*, force_rich=False, force_plain=False)[source]

Print a compact one-screen help summary to stdout.

Parameters:
Return type:

None

print_long_help(*, force_rich=False, force_plain=False)[source]

Print the full help page (including the long description) to stdout.

Parameters:
Return type:

None

print_agent_help()[source]

Print a hyper-short, token-efficient help summary for LLM agents.

Automatically used when stdout is not a TTY (e.g. piped to another process or called by an agent). Recursively flattens the entire command tree and filters out framework-owned implicit options and hidden subcommands like completions.

Example output:

myapp: My application.

greet NAME - Greet someone. Options: --template STR (default: 'Hello, {}!')
config get - Print the current config.
config set KEY VALUE - Set config values.
Return type:

None

command(*names)[source]

Register a subcommand on this command using the decorator API.

This is the flat API alternative to file-based routing. For large codebases where better scaling is desirable, consider the manifest compiler (xclif compile) instead, which pre-builds a static manifest and avoids the filesystem walk cost of Cli.from_routes.

Parameters:

names (str)

Return type:

Callable[[Callable], Command]

group(name)[source]

Create an empty subcommand group on this command.

Part of the flat decorator API. For large codebases where better scaling is desirable, consider the manifest compiler (xclif compile) to pre-build a static manifest instead.

Parameters:

name (str)

Return type:

Command

execute(args=None, context=None)[source]

Parse args and run the appropriate subcommand, returning an exit code.

When args is None, sys.argv[1:] is used. Pass an explicit list for testing without subprocess overhead:

assert my_command.execute(["greet", "Alice"]) == 0
Parameters:
Return type:

int

property description: str

Full docstring of the command’s run function, cleaned by inspect.getdoc.

property short_description: str

First line of description, used in subcommand listings.

xclif.command.command(*names, show_no_description=None)[source]

Convert a function into an xclif.Command.

Names are optional. The first name is the canonical command name; any additional names become aliases (alternative names that resolve to the same command). When no names are given, the function name is used (or the module name when the function is called _).

Parameters:
  • show_no_description (bool | None) – When False, suppress the “No description” placeholder in help output when no docstring is provided. When None (the default), uses the framework default (True for backward compatibility).

  • names (str)

Return type:

Callable[[Callable], Command]

xclif.definition

class xclif.definition.Argument(name, converter, description, variadic=False, config=None, choices=None)[source]

Bases: Generic

A positional argument on a command.

Created automatically from a function signature by the command() decorator. Use Arg inside Annotated to attach a description or display name.

Parameters:
property short_description: str

First line of description, used in compact help output.

xclif.context

Dispatch context — exposes cascading framework state to user code.

class xclif.context.Context(_data)[source]

Bases: object

Read-only view of cascading framework state.

Built-in properties provide typed access to implicit options:

ctx = get_context()
ctx.verbosity  # int (0–3)
ctx.colors     # "always" | "never" | "auto"

User-defined cascading options (marked with Cascade()) are accessible via dict-style lookup:

ctx["my_option"]
ctx.get("my_option", default)
Parameters:

_data (dict)

property verbosity: int

Verbosity level (0–3). Corresponds to -v / -vv / -vvv.

property colors: str

"always", "never", or "auto".

Type:

Color mode

property log_level: int

Standard logging level implied by verbosity.

get(key, default=None)[source]

Return the value for key, or default if not set.

Parameters:
Return type:

object

xclif.context.get_context()[source]

Return the Context for the current command dispatch.

Raises RuntimeError if called outside of command dispatch (i.e., no command is currently being executed by the framework).

Return type:

Context

xclif.logging

Logging helpers for Xclif-powered CLIs.

This module builds on Python’s standard logging package. It adds a small Rich-backed default handler and a verbosity-to-level mapping that matches Xclif’s built-in -v / --verbose flag.

class xclif.logging.RichLogHandler(level=0, *, colors='auto', console=None, show_time=False, show_level=True, show_path=False, markup=False, rich_tracebacks=True, tracebacks_show_locals=False)[source]

Bases: Handler

A lazy wrapper around rich.logging.RichHandler.

Constructing Rich’s handler imports Rich, which is nice for output but expensive on the hot path. This wrapper defers that import until a log record actually passes the configured level filters.

Parameters:
  • level (int | str)

  • colors (str)

  • console (Console | None)

  • show_time (bool)

  • show_level (bool)

  • show_path (bool)

  • markup (bool)

  • rich_tracebacks (bool)

  • tracebacks_show_locals (bool)

setLevel(level)[source]

Set the logging level of this handler. level must be an int or a str.

Parameters:

level (int | str)

Return type:

None

setFormatter(fmt)[source]

Set the formatter for this handler.

Parameters:

fmt (Formatter | None)

Return type:

None

emit(record)[source]

Do whatever it takes to actually log the specified logging record.

This version is intended to be implemented by subclasses and so raises a NotImplementedError.

Parameters:

record (LogRecord)

Return type:

None

flush()[source]

Ensure all logging output has been flushed.

This version does nothing and is intended to be implemented by subclasses.

Return type:

None

close()[source]

Tidy up any resources used by the handler.

This version removes the handler from an internal map of handlers, _handlers, which is used for handler lookup by name. Subclasses should ensure that this gets called from overridden close() methods.

Return type:

None

xclif.logging.configure_logging(verbosity=0, colors='auto', *, logger=None, level=None, force=False, console=None, show_time=False, show_level=True, show_path=None, markup=False, rich_tracebacks=True)[source]

Configure standard logging for an Xclif command run.

The root logger is used by default, so ordinary logging.getLogger calls in command code work without any Xclif-specific API. If logging has already been configured by the application, Xclif leaves existing handlers in place and only updates the logger level. Pass force=True to replace existing handlers with Xclif’s Rich handler.

Returns the installed handler, or None when existing non-Xclif handlers were respected.

Parameters:
Return type:

logging.Handler | None

xclif.logging.get_logger(name=None)[source]

Return a standard library logger.

This is a tiny convenience wrapper around logging.getLogger(); Xclif intentionally does not introduce its own logger abstraction.

Parameters:

name (str | None)

Return type:

Logger

xclif.logging.level_from_verbosity(verbosity)[source]

Map Xclif verbosity counts to standard logging levels.

0 shows warnings and errors, 1 enables info logs, 2 enables debug logs, and 3 enables every record that reaches the configured logger. Values outside the supported range are clamped.

Parameters:

verbosity (int)

Return type:

int

xclif.errors

exception xclif.errors.UsageError(message, hint=None)[source]

Bases: Exception

A user-facing CLI invocation error.

Parameters:
  • message (str)

  • hint (str | None)

Return type:

None

xclif.compiler

See the Manifest Compiler guide.