API Reference¶
xclif¶
- class xclif.Arg(description=None, name=None)[source]¶
Bases:
objectAnnotation metadata for positional arguments.
Use inside
Annotatedto attach a description or display name:def copy(src: Annotated[str, Arg(description="Source file", name="SRC")]) -> None: ...
- class xclif.Cascade[source]¶
Bases:
objectAnnotation 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:
objectEntry point for an Xclif-powered CLI application.
Typically constructed via
from_routes()(file-based routing) orfrom_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
Commandof 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.tomland.jsonextensions. None (the default) disables local config.config_command (bool) – Whether to auto-inject the
configsubcommand when any parameter usesWithConfig. True (the default) keeps the current behaviour; set to False to suppress it.completions_command (bool) – Whether to auto-inject the
completionssubcommand. True (the default) keeps the current behaviour; set to False to suppress it. Injection is also skipped when the root command already defines acompletionssubcommand or declares positional arguments (since a command with positional args cannot have subcommands).mcp_command (bool) – Whether to auto-inject the
mcpsubcommand when the optionalmcppackage 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 anmcpsubcommand or declares positional arguments.show_no_description (bool | None) – Default value for
show_no_descriptionon all commands in the tree. WhenFalse, suppress the “No description” placeholder in help output for commands without a docstring. WhenNone(the default), each command uses its own setting (Trueby 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.
pathis a list of names from the root downward, e.g.["server", "start"]mounts command asmyapp server start. Intermediate groups are created automatically if they don’t exist.
- 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 thepkgutil.walk_packages+inspect.getmembersfilesystem scan at the cost of a one-timexclif compilebuild 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:
- classmethod from_routes(routes, *, version=None, env_prefix=None, config_name=None, local_config=None, show_no_description=None)[source]¶
Build a
Cliby walking a routes package at runtime.Each module in routes that exports a
Commandbecomes 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 thepkgutil.walk_packagesoverhead on every invocation.local_config (str | None)
show_no_description (bool | None)
- Return type:
- class xclif.Context(_data)[source]¶
Bases:
objectRead-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)
- class xclif.Option(description=None, name=None)[source]¶
Bases:
objectAnnotation metadata for CLI options.
Use inside
Annotatedto attach a description or override the flag name:def build(dry_run: Annotated[bool, Option(description="Skip execution", name="dry-run")] = False) -> None: ...
nameoverrides the CLI flag (--dry-run). The Python kwarg name is unchanged.
- class xclif.Path(*args, **kwargs)[source]¶
Bases:
PurePathPurePath 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_file()[source]¶
Whether this path is a regular file (also True for symlinks pointing to regular files).
- 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_text(encoding=None, errors=None)[source]¶
Open the file in text mode, read 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 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.
- touch(mode=438, exist_ok=True)[source]¶
Create this file with the given access mode, if it doesn’t exist.
- lchmod(mode)[source]¶
Like chmod(), except if the path points to a symlink, the symlink’s permissions are changed, rather than its target’s.
- unlink(missing_ok=False)[source]¶
Remove this file or link. If the path is a directory, use rmdir() instead.
- 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.
- symlink_to(target, target_is_directory=False)[source]¶
Make this path a symlink pointing to the target path. Note the order of arguments (link, target) is the reverse of os.symlink.
- class xclif.WithConfig[source]¶
Bases:
objectMarker for parameters that can be read from a config file or env var.
name: WithConfig[str]is sugar forAnnotated[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
_).
- 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.getLoggercalls 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. Passforce=Trueto replace existing handlers with Xclif’s Rich handler.Returns the installed handler, or
Nonewhen existing non-Xclif handlers were respected.
- xclif.get_context()[source]¶
Return the
Contextfor the current command dispatch.Raises
RuntimeErrorif called outside of command dispatch (i.e., no command is currently being executed by the framework).- Return type:
- 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.
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:
objectA parsed command node in the CLI tree.
Normally you don’t construct this directly — use the
command()decorator orCommand.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.
- print_long_help(*, force_rich=False, force_plain=False)[source]
Print the full help page (including the long description) to stdout.
- 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 ofCli.from_routes.
- 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
- property description: str
Full docstring of the command’s
runfunction, cleaned byinspect.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
_).
xclif.definition¶
- class xclif.definition.Argument(name, converter, description, variadic=False, config=None, choices=None)[source]¶
Bases:
GenericA positional argument on a command.
Created automatically from a function signature by the
command()decorator. UseArginsideAnnotatedto attach a description or display name.- Parameters:
xclif.context¶
Dispatch context — exposes cascading framework state to user code.
- class xclif.context.Context(_data)[source]¶
Bases:
objectRead-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)
- xclif.context.get_context()[source]¶
Return the
Contextfor the current command dispatch.Raises
RuntimeErrorif called outside of command dispatch (i.e., no command is currently being executed by the framework).- Return type:
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:
HandlerA 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:
- 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
- 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.getLoggercalls 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. Passforce=Trueto replace existing handlers with Xclif’s Rich handler.Returns the installed handler, or
Nonewhen existing non-Xclif handlers were respected.
- 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.
xclif.errors¶
xclif.compiler¶
See the Manifest Compiler guide.