How Lazy Command Loading Works in agents-cli's Click-Based Architecture
The agents-cli tool implements lazy command loading through a custom LazyGroup class that stores import paths and help strings during registration, deferring heavy module imports until a user actually invokes a specific command.
This optimization pattern appears in the google/agents-cli repository to keep CLI startup times fast while maintaining a rich command structure. By subclassing Click's standard Group class, the tool avoids paying the import cost for unused subcommands like scaffolding, evaluation pipelines, or publishing workflows.
The LazyGroup Implementation
The core mechanism lives in src/google/agents/cli/_click.py, where the LazyGroup class extends click.Group with deferred loading capabilities.
Storing Command References Without Importing
Instead of importing command modules at startup, LazyGroup maintains a registry of import metadata:
class LazyGroup(click.Group):
"""Click group that defers importing subcommand modules until needed."""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._lazy_commands: dict[str, tuple[str, str]] = {}
def add_lazy_command(self, name: str, import_path: str, short_help: str) -> None:
# Store the "name → (module_path:attr, short_help)" mapping.
self._lazy_commands[name] = (import_path, short_help)
The add_lazy_command method populates _lazy_commands with a mapping of command names to tuples containing the import path and short help text. For example, the string "google.agents.cli.setup.cmd_setup:cmd_setup" tells Python exactly which module and attribute to retrieve later.
Listing Commands Without Triggering Imports
To ensure agents-cli --help remains responsive, the class overrides list_commands to merge eagerly-loaded commands with lazy ones:
def list_commands(self, ctx):
return sorted(set(super().list_commands(ctx)) |
set(self._lazy_commands))
This allows the help system to display all available command names immediately, without importing the underlying implementation modules.
On-Demand Command Resolution
When a user executes agents-cli <command> or requests <command> --help, Click queries the group for the actual command object.
The get_command Method
The get_command method in LazyGroup performs the actual import only when needed:
def get_command(self, ctx, cmd_name):
if cmd_name in self._lazy_commands and cmd_name not in self.commands:
import_path, _ = self._lazy_commands[cmd_name]
module_path, attr = import_path.split(":")
cmd = getattr(importlib.import_module(module_path), attr)
patch_source_in_help(cmd) # adds source-path footer
self.commands[cmd_name] = cmd
return super().get_command(ctx, cmd_name)
The method parses the stored "module_path:attr" string, dynamically imports the module using importlib.import_module, retrieves the Click command object via getattr, and caches it in self.commands.
Caching for Subsequent Calls
Once loaded, commands reside in the standard self.commands dictionary. Subsequent invocations of the same command bypass the import logic entirely, providing fast repeated execution while maintaining the initial startup performance benefits.
Help Output Optimization
Displaying accurate help text without triggering imports requires special handling for lazy entries.
The format_commands Override
The format_commands method distinguishes between loaded and lazy commands when building help output:
def format_commands(self, ctx, formatter):
rows = []
for name in self.list_commands(ctx):
if name in self.commands:
rows.append((name, self.commands[name].get_short_help_str(limit=1000)))
else:
lazy = self._lazy_commands.get(name)
if lazy is not None:
rows.append((name, lazy[1])) # short_help from registration
if rows:
with formatter.section("Commands"):
formatter.write_dl(rows)
For lazy commands, the method uses the short_help string provided during registration rather than accessing the command object's docstring, ensuring zero-import help generation.
Source Path Attribution
A diagnostic feature adds the source file path to every command's help output.
The patch_source_in_help Function
The patch_source_in_help function decorates commands to append a "Source:" line indicating the absolute file path where the command is defined. This runs exactly once per command thanks to an internal _source_patched guard, executing only during the first lazy load.
Registration in the Root CLI
The root CLI group in src/google/agents/cli/main.py subclasses LazyGroup as _MainGroup and registers every top-level command using the lazy pattern:
@cli.group(cls=_MainGroup)
def main():
"""Google Agents CLI tool."""
pass
main.add_lazy_command("setup", "google.agents.cli.setup.cmd_setup:cmd_setup",
"Install agents-cli and skills")
main.add_lazy_command("scaffold", "google.agents.cli.scaffold.cmd_scaffold_group:scaffold_group",
"Scaffold new agents and skills")
main.add_lazy_command("publish", "google.agents.cli.publish.cmd_publish_group:publish_group",
"Publish agents to the marketplace")
Heavy modules like scaffold templates or publish workflows remain unimported until explicitly invoked.
Benefits of Lazy Loading
This architecture provides several concrete advantages:
- Fast startup time – Only
main.pyand_click.pyload initially; heavy dependencies like rendering engines or API clients stay unloaded until needed. - Reduced memory footprint – Unused subcommands never occupy RAM, keeping the base process lightweight.
- Accurate help display – Short help strings defined at registration time ensure
agents-cli --helpshows complete command listings without importing implementation details. - Source traceability – Every command help output includes the absolute source path, helping developers locate implementation files quickly.
Summary
- LazyGroup in
src/google/agents/cli/_click.pystores command metadata (import path and help text) instead of command objects. - add_lazy_command registers commands without importing their modules, using a
"module_path:attribute"string format. - get_command performs the actual import via
importlibonly when a command is invoked, caching the result for future calls. - format_commands displays help using pre-registered short descriptions, avoiding imports during help generation.
- patch_source_in_help adds source file attribution to commands exactly once during their first load.
- The root CLI in
src/google/agents/cli/main.pyuses this pattern for all subcommands, ensuring fast startup while supporting a rich command hierarchy.
Frequently Asked Questions
How does agents-cli avoid slow startup times with many subcommands?
The tool avoids slow startup by using the LazyGroup class to defer module imports. When you run agents-cli --help, the system only imports main.py and _click.py, displaying command names from the _lazy_commands dictionary without loading heavy implementation modules like scaffolders or publishers.
What is the string format used for lazy command registration?
The registration uses a "module_path:attribute" format, such as "google.agents.cli.setup.cmd_setup:cmd_setup". This string tells Python which module to import and which specific Click command object to retrieve from that module's namespace.
Does lazy loading affect command execution performance after the first run?
No. The first invocation of a command triggers the import and executes patch_source_in_help, but the resulting command object is cached in self.commands. Subsequent calls to the same command bypass the import logic and execute at native speed.
Can nested command groups also use lazy loading?
Yes. Nested groups like scaffold_group can themselves subclass LazyGroup and call add_lazy_command for their own subcommands. This creates a hierarchical lazy-loading system where even complex nested commands remain unloaded until the specific subcommand path is invoked.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →