Skip to content

perf: implement lazy loading for heavy CLI commands (50% faster startup)#151

Merged
jeremyeder merged 1 commit intoambient-code:mainfrom
jeremyeder:perf/lazy-load-cli-commands
Dec 4, 2025
Merged

perf: implement lazy loading for heavy CLI commands (50% faster startup)#151
jeremyeder merged 1 commit intoambient-code:mainfrom
jeremyeder:perf/lazy-load-cli-commands

Conversation

@jeremyeder
Copy link
Copy Markdown
Contributor

Summary

Improves CLI startup time by 50% (2.7s → 1.4s) by implementing lazy loading for commands that import heavy dependencies.

Performance Improvement

Metric Before After Improvement
agentready --help 2.718s 1.368s 50% faster (1.35s saved)
agentready assess 2.7s + assess time 1.4s + assess time 1.3s saved

Implementation

Added LazyGroup class that defers importing command modules until they're actually invoked:

  • Lazy-loaded commands: assess-batch, experiment, extract-skills, learn, submit

    • These import heavy dependencies: scipy (457ms), pandas (196ms), anthropic (218ms), github (75ms)
    • Only loaded when the specific command is run
  • Immediately loaded commands: align, bootstrap, demo, repomix, research, schema

    • Lightweight commands with minimal dependencies
    • Always available with no lazy loading overhead

Why This Matters

  • Most CLI invocations don't need scipy/pandas/anthropic
  • Users running common commands like assess or --help get instant response
  • Commands that need heavy libraries still load them when invoked (no functionality change)
  • Improves developer experience for frequent CLI usage

Technical Approach

Used Click's extensible Group class pattern (standard in Click ecosystem):

  1. Created LazyGroup that overrides get_command()
  2. Lazy commands registered in lazy_subcommands dict (module_name, command_name)
  3. Import happens on first invocation, then command is cached
  4. list_commands() includes lazy commands so --help shows all available commands

Testing

  • ✅ All commands tested and working (agentready --help, experiment --help, assess-batch --help, etc.)
  • --help shows all commands (including lazy ones)
  • ✅ Lazy commands load correctly when invoked
  • ✅ No regression in functionality
  • ✅ Pre-commit hooks passed (black, isort, ruff)

Before/After Example

Before (all commands imported eagerly):

from .experiment import experiment  # ← Imports scipy immediately
cli.add_command(experiment)

After (lazy loading):

@click.group(cls=LazyGroup, lazy_subcommands={
    'experiment': ('experiment', 'experiment'),  # ← Only imported when invoked
})

Future Optimization Potential

If we wanted even faster startup (~0.5s target), we could:

  • Lazy load more modules (assessors, services)
  • Use importlib for deferred imports
  • Profile remaining slow imports

But this 50% improvement addresses the main bottleneck (heavy scientific libraries).


Ready to merge: This is a low-risk refactoring with significant UX improvement and no breaking changes.

🤖 Generated with Claude Code

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant