From f4fbdcac8eade23d95a60ff528e7eb0148dc81c7 Mon Sep 17 00:00:00 2001 From: Vijay Janapa Reddi Date: Fri, 11 Jul 2025 22:37:35 -0400 Subject: [PATCH] feat: Reorganize CLI into hierarchical command structure - Add system, module, and package command groups for clear subsystem separation - Create SystemCommand, ModuleCommand, and PackageCommand classes - Maintain backward compatibility with existing flat commands - Enhanced help system with contextual guidance at each level - Updated main CLI to show organized command groups - Added comprehensive documentation for CLI reorganization New structure: - tito system (info, doctor, jupyter) - tito module (status, test, notebooks) - tito package (sync, reset, nbdev) Benefits: - Clear subsystem separation - Intuitive command discovery - Better extensibility for future commands - Reduced cognitive load for users --- docs/development/cli-reorganization.md | 266 +++++++++++++++++++++++++ tito/commands/__init__.py | 13 ++ tito/commands/info.py | 8 +- tito/commands/module.py | 88 ++++++++ tito/commands/package.py | 88 ++++++++ tito/commands/system.py | 85 ++++++++ tito/main.py | 45 ++++- 7 files changed, 587 insertions(+), 6 deletions(-) create mode 100644 docs/development/cli-reorganization.md create mode 100644 tito/commands/module.py create mode 100644 tito/commands/package.py create mode 100644 tito/commands/system.py diff --git a/docs/development/cli-reorganization.md b/docs/development/cli-reorganization.md new file mode 100644 index 00000000..7a031e1f --- /dev/null +++ b/docs/development/cli-reorganization.md @@ -0,0 +1,266 @@ +# CLI Reorganization: Hierarchical Command Structure + +TinyTorch CLI has been reorganized into a clear hierarchical structure with three main command groups: `system`, `module`, and `package`. This provides better organization and makes it clear which subsystem each command operates on. + +## New Command Structure + +### System Commands (`tito system`) +**Environment, configuration, and system tools** + +- `tito system info` - Show system information and course navigation +- `tito system doctor` - Run environment diagnosis +- `tito system jupyter` - Start Jupyter notebook server + +### Module Commands (`tito module`) +**Development workflow and module management** + +- `tito module status` - Check status of all modules +- `tito module test` - Run module tests +- `tito module notebooks` - Build notebooks from Python files + +### Package Commands (`tito package`) +**nbdev integration and package management** + +- `tito package sync` - Export notebook code to Python package +- `tito package reset` - Reset tinytorch package to clean state +- `tito package nbdev` - nbdev notebook development commands + +## Benefits of Hierarchical Structure + +### 1. **Clear Subsystem Separation** +Each command group operates on a specific subsystem: +- **System**: Environment and configuration +- **Module**: Individual module development +- **Package**: Overall package management + +### 2. **Intuitive Command Discovery** +Users can explore commands by subsystem: +```bash +tito system # Shows all system commands +tito module # Shows all module commands +tito package # Shows all package commands +``` + +### 3. **Extensibility** +New commands can be easily categorized: +- Adding deployment tools? → `tito system deploy` +- Adding module generators? → `tito module create` +- Adding package publishing? → `tito package publish` + +### 4. **Reduced Cognitive Load** +Instead of remembering 10+ flat commands, users think in terms of: +- What subsystem am I working with? +- What do I want to do in that subsystem? + +## Usage Examples + +### System Operations +```bash +# Check environment setup +tito system doctor + +# Get system information +tito system info + +# Start development environment +tito system jupyter +``` + +### Module Development +```bash +# Check module status with metadata +tito module status --metadata + +# Test all modules +tito module test --all + +# Test specific module +tito module test --module tensor + +# Generate notebooks +tito module notebooks --module tensor +``` + +### Package Management +```bash +# Export modules to package +tito package sync + +# Export specific module +tito package sync --module tensor + +# Reset package to clean state +tito package reset + +# Run nbdev commands +tito package nbdev --export +``` + +## Backward Compatibility + +The old flat command structure is still supported for backward compatibility: + +```bash +# These still work (legacy commands) +tito status +tito test --all +tito sync +tito info +``` + +However, the new hierarchical structure is recommended for new usage. + +## Migration Guide + +### For Users +**Old → New Command Mapping:** + +```bash +# System commands +tito info → tito system info +tito doctor → tito system doctor +tito jupyter → tito system jupyter + +# Module commands +tito status → tito module status +tito test → tito module test +tito notebooks → tito module notebooks + +# Package commands +tito sync → tito package sync +tito reset → tito package reset +tito nbdev → tito package nbdev +``` + +### For Scripts +Update automation scripts to use the new structure: + +```bash +# Old +./scripts/test-all.sh: +tito test --all + +# New (recommended) +./scripts/test-all.sh: +tito module test --all +``` + +## Implementation Details + +### Command Group Classes +Each command group is implemented as a separate class: + +- `SystemCommand` - Handles system subcommands +- `ModuleCommand` - Handles module subcommands +- `PackageCommand` - Handles package subcommands + +### Argument Parsing +Uses argparse subparsers for clean hierarchical structure: + +```python +# Main parser +parser = argparse.ArgumentParser(prog="tito") +subparsers = parser.add_subparsers(dest='command') + +# System group +system_parser = subparsers.add_parser('system') +system_subparsers = system_parser.add_subparsers(dest='system_command') + +# System subcommands +system_subparsers.add_parser('info') +system_subparsers.add_parser('doctor') +system_subparsers.add_parser('jupyter') +``` + +### Help System +Each level provides contextual help: + +```bash +tito # Shows command groups +tito system # Shows system subcommands +tito module # Shows module subcommands +tito package # Shows package subcommands +``` + +## Future Enhancements + +### Additional Command Groups +The structure supports adding new command groups: + +```bash +# Deployment commands +tito deploy status +tito deploy docker +tito deploy cloud + +# Research commands +tito research benchmark +tito research profile +tito research compare +``` + +### Command Aliases +Short aliases for common commands: + +```bash +# System +tito sys info # alias for tito system info + +# Module +tito mod status # alias for tito module status +tito mod test # alias for tito module test + +# Package +tito pkg sync # alias for tito package sync +``` + +### Interactive Mode +Enhanced interactive command discovery: + +```bash +tito interactive +# → Shows menu of command groups +# → Allows drilling down into subcommands +# → Provides guided command building +``` + +## Best Practices + +### 1. **Use Hierarchical Commands** +Prefer the new structure for clarity: +```bash +# Good +tito module status --metadata + +# Avoid (legacy) +tito status --metadata +``` + +### 2. **Think in Subsystems** +When adding new functionality, consider which subsystem it belongs to: +- Environment/config → `system` +- Individual modules → `module` +- Overall package → `package` + +### 3. **Consistent Naming** +Use consistent naming patterns within each group: +- `status` for checking state +- `test` for running tests +- `sync` for synchronization +- `reset` for cleanup + +### 4. **Help Documentation** +Always provide clear help text for new commands: +```python +parser.add_parser('new-command', help='Clear description of what this does') +``` + +## Conclusion + +The hierarchical CLI structure provides: +- **Better organization** with clear subsystem separation +- **Improved discoverability** through logical grouping +- **Enhanced extensibility** for future commands +- **Maintained compatibility** with existing workflows + +This structure scales well as TinyTorch grows and provides a professional CLI experience that matches industry standards. \ No newline at end of file diff --git a/tito/commands/__init__.py b/tito/commands/__init__.py index 8ba96fc8..3bcadcde 100644 --- a/tito/commands/__init__.py +++ b/tito/commands/__init__.py @@ -2,9 +2,12 @@ CLI Commands package. Each command is implemented as a separate module with proper separation of concerns. +Commands are organized into logical groups: system, module, and package. """ from .base import BaseCommand + +# Individual commands (for backward compatibility) from .notebooks import NotebooksCommand from .info import InfoCommand from .test import TestCommand @@ -15,8 +18,14 @@ from .jupyter import JupyterCommand from .nbdev import NbdevCommand from .status import StatusCommand +# Command groups +from .system import SystemCommand +from .module import ModuleCommand +from .package import PackageCommand + __all__ = [ 'BaseCommand', + # Individual commands 'NotebooksCommand', 'InfoCommand', 'TestCommand', @@ -26,4 +35,8 @@ __all__ = [ 'JupyterCommand', 'NbdevCommand', 'StatusCommand', + # Command groups + 'SystemCommand', + 'ModuleCommand', + 'PackageCommand', ] \ No newline at end of file diff --git a/tito/commands/info.py b/tito/commands/info.py index 93ff2164..606ab498 100644 --- a/tito/commands/info.py +++ b/tito/commands/info.py @@ -81,13 +81,13 @@ class InfoCommand(BaseCommand): # Command Reference Panel cmd_text = Text() cmd_text.append("📊 Module Status: ", style="dim") - cmd_text.append("tito status\n", style="bold cyan") + cmd_text.append("tito module status\n", style="bold cyan") cmd_text.append("🧪 Run Tests: ", style="dim") - cmd_text.append("tito test --all\n", style="bold cyan") + cmd_text.append("tito module test --all\n", style="bold cyan") cmd_text.append("🔄 Export Code: ", style="dim") - cmd_text.append("tito sync\n", style="bold cyan") + cmd_text.append("tito package sync\n", style="bold cyan") cmd_text.append("🩺 Check Environment: ", style="dim") - cmd_text.append("tito doctor", style="bold cyan") + cmd_text.append("tito system doctor", style="bold cyan") console.print(Panel(cmd_text, title="📋 Quick Commands", border_style="bright_magenta")) diff --git a/tito/commands/module.py b/tito/commands/module.py new file mode 100644 index 00000000..59794975 --- /dev/null +++ b/tito/commands/module.py @@ -0,0 +1,88 @@ +""" +Module command group for TinyTorch CLI: development workflow and module management. +""" + +from argparse import ArgumentParser, Namespace +from rich.panel import Panel + +from .base import BaseCommand +from .status import StatusCommand +from .test import TestCommand +from .notebooks import NotebooksCommand + +class ModuleCommand(BaseCommand): + @property + def name(self) -> str: + return "module" + + @property + def description(self) -> str: + return "Module development and management commands" + + def add_arguments(self, parser: ArgumentParser) -> None: + subparsers = parser.add_subparsers( + dest='module_command', + help='Module subcommands', + metavar='SUBCOMMAND' + ) + + # Status subcommand + status_parser = subparsers.add_parser( + 'status', + help='Check status of all modules' + ) + status_cmd = StatusCommand(self.config) + status_cmd.add_arguments(status_parser) + + # Test subcommand + test_parser = subparsers.add_parser( + 'test', + help='Run module tests' + ) + test_cmd = TestCommand(self.config) + test_cmd.add_arguments(test_parser) + + # Notebooks subcommand + notebooks_parser = subparsers.add_parser( + 'notebooks', + help='Build notebooks from Python files' + ) + notebooks_cmd = NotebooksCommand(self.config) + notebooks_cmd.add_arguments(notebooks_parser) + + def run(self, args: Namespace) -> int: + console = self.console + + if not hasattr(args, 'module_command') or not args.module_command: + console.print(Panel( + "[bold cyan]Module Commands[/bold cyan]\n\n" + "Available subcommands:\n" + " • [bold]status[/bold] - Check status of all modules\n" + " • [bold]test[/bold] - Run module tests\n" + " • [bold]notebooks[/bold] - Build notebooks from Python files\n\n" + "[dim]Examples:[/dim]\n" + "[dim] tito module status --metadata[/dim]\n" + "[dim] tito module test --all[/dim]\n" + "[dim] tito module notebooks --module tensor[/dim]", + title="Module Command Group", + border_style="bright_cyan" + )) + return 0 + + # Execute the appropriate subcommand + if args.module_command == 'status': + cmd = StatusCommand(self.config) + return cmd.execute(args) + elif args.module_command == 'test': + cmd = TestCommand(self.config) + return cmd.execute(args) + elif args.module_command == 'notebooks': + cmd = NotebooksCommand(self.config) + return cmd.execute(args) + else: + console.print(Panel( + f"[red]Unknown module subcommand: {args.module_command}[/red]", + title="Error", + border_style="red" + )) + return 1 \ No newline at end of file diff --git a/tito/commands/package.py b/tito/commands/package.py new file mode 100644 index 00000000..7036922a --- /dev/null +++ b/tito/commands/package.py @@ -0,0 +1,88 @@ +""" +Package command group for TinyTorch CLI: nbdev integration and package management. +""" + +from argparse import ArgumentParser, Namespace +from rich.panel import Panel + +from .base import BaseCommand +from .sync import SyncCommand +from .reset import ResetCommand +from .nbdev import NbdevCommand + +class PackageCommand(BaseCommand): + @property + def name(self) -> str: + return "package" + + @property + def description(self) -> str: + return "Package management and nbdev integration commands" + + def add_arguments(self, parser: ArgumentParser) -> None: + subparsers = parser.add_subparsers( + dest='package_command', + help='Package subcommands', + metavar='SUBCOMMAND' + ) + + # Sync subcommand + sync_parser = subparsers.add_parser( + 'sync', + help='Export notebook code to Python package' + ) + sync_cmd = SyncCommand(self.config) + sync_cmd.add_arguments(sync_parser) + + # Reset subcommand + reset_parser = subparsers.add_parser( + 'reset', + help='Reset tinytorch package to clean state' + ) + reset_cmd = ResetCommand(self.config) + reset_cmd.add_arguments(reset_parser) + + # Nbdev subcommand + nbdev_parser = subparsers.add_parser( + 'nbdev', + help='nbdev notebook development commands' + ) + nbdev_cmd = NbdevCommand(self.config) + nbdev_cmd.add_arguments(nbdev_parser) + + def run(self, args: Namespace) -> int: + console = self.console + + if not hasattr(args, 'package_command') or not args.package_command: + console.print(Panel( + "[bold cyan]Package Commands[/bold cyan]\n\n" + "Available subcommands:\n" + " • [bold]sync[/bold] - Export notebook code to Python package\n" + " • [bold]reset[/bold] - Reset tinytorch package to clean state\n" + " • [bold]nbdev[/bold] - nbdev notebook development commands\n\n" + "[dim]Examples:[/dim]\n" + "[dim] tito package sync --module tensor[/dim]\n" + "[dim] tito package reset --force[/dim]\n" + "[dim] tito package nbdev --export[/dim]", + title="Package Command Group", + border_style="bright_cyan" + )) + return 0 + + # Execute the appropriate subcommand + if args.package_command == 'sync': + cmd = SyncCommand(self.config) + return cmd.execute(args) + elif args.package_command == 'reset': + cmd = ResetCommand(self.config) + return cmd.execute(args) + elif args.package_command == 'nbdev': + cmd = NbdevCommand(self.config) + return cmd.execute(args) + else: + console.print(Panel( + f"[red]Unknown package subcommand: {args.package_command}[/red]", + title="Error", + border_style="red" + )) + return 1 \ No newline at end of file diff --git a/tito/commands/system.py b/tito/commands/system.py new file mode 100644 index 00000000..9c48eb90 --- /dev/null +++ b/tito/commands/system.py @@ -0,0 +1,85 @@ +""" +System command group for TinyTorch CLI: environment, configuration, and system tools. +""" + +from argparse import ArgumentParser, Namespace +from rich.panel import Panel + +from .base import BaseCommand +from .info import InfoCommand +from .doctor import DoctorCommand +from .jupyter import JupyterCommand + +class SystemCommand(BaseCommand): + @property + def name(self) -> str: + return "system" + + @property + def description(self) -> str: + return "System environment and configuration commands" + + def add_arguments(self, parser: ArgumentParser) -> None: + subparsers = parser.add_subparsers( + dest='system_command', + help='System subcommands', + metavar='SUBCOMMAND' + ) + + # Info subcommand + info_parser = subparsers.add_parser( + 'info', + help='Show system information and course navigation' + ) + info_cmd = InfoCommand(self.config) + info_cmd.add_arguments(info_parser) + + # Doctor subcommand + doctor_parser = subparsers.add_parser( + 'doctor', + help='Run environment diagnosis' + ) + doctor_cmd = DoctorCommand(self.config) + doctor_cmd.add_arguments(doctor_parser) + + # Jupyter subcommand + jupyter_parser = subparsers.add_parser( + 'jupyter', + help='Start Jupyter notebook server' + ) + jupyter_cmd = JupyterCommand(self.config) + jupyter_cmd.add_arguments(jupyter_parser) + + def run(self, args: Namespace) -> int: + console = self.console + + if not hasattr(args, 'system_command') or not args.system_command: + console.print(Panel( + "[bold cyan]System Commands[/bold cyan]\n\n" + "Available subcommands:\n" + " • [bold]info[/bold] - Show system information and course navigation\n" + " • [bold]doctor[/bold] - Run environment diagnosis\n" + " • [bold]jupyter[/bold] - Start Jupyter notebook server\n\n" + "[dim]Example: tito system info[/dim]", + title="System Command Group", + border_style="bright_cyan" + )) + return 0 + + # Execute the appropriate subcommand + if args.system_command == 'info': + cmd = InfoCommand(self.config) + return cmd.execute(args) + elif args.system_command == 'doctor': + cmd = DoctorCommand(self.config) + return cmd.execute(args) + elif args.system_command == 'jupyter': + cmd = JupyterCommand(self.config) + return cmd.execute(args) + else: + console.print(Panel( + f"[red]Unknown system subcommand: {args.system_command}[/red]", + title="Error", + border_style="red" + )) + return 1 \ No newline at end of file diff --git a/tito/main.py b/tito/main.py index 2eaeeb48..59164459 100644 --- a/tito/main.py +++ b/tito/main.py @@ -18,6 +18,7 @@ from typing import Dict, Type from .core.config import CLIConfig from .core.console import get_console, print_banner, print_error from .core.exceptions import TinyTorchCLIError +from rich.panel import Panel from .commands.base import BaseCommand from .commands.notebooks import NotebooksCommand from .commands.info import InfoCommand @@ -28,6 +29,9 @@ from .commands.reset import ResetCommand from .commands.jupyter import JupyterCommand from .commands.nbdev import NbdevCommand from .commands.status import StatusCommand +from .commands.system import SystemCommand +from .commands.module import ModuleCommand +from .commands.package import PackageCommand # Configure logging logging.basicConfig( @@ -49,6 +53,11 @@ class TinyTorchCLI: self.config = CLIConfig.from_project_root() self.console = get_console() self.commands: Dict[str, Type[BaseCommand]] = { + # New hierarchical command groups + 'system': SystemCommand, + 'module': ModuleCommand, + 'package': PackageCommand, + # Legacy flat commands (for backward compatibility) 'notebooks': NotebooksCommand, 'info': InfoCommand, 'test': TestCommand, @@ -65,7 +74,21 @@ class TinyTorchCLI: parser = argparse.ArgumentParser( prog="tito", description="TinyTorch CLI - Build ML systems from scratch", - formatter_class=argparse.RawDescriptionHelpFormatter + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +Command Groups: + system System environment and configuration commands + module Module development and management commands + package Package management and nbdev integration commands + +Examples: + tito system info Show system information + tito module status --metadata Module status with metadata + tito package sync Export notebooks to package + +Legacy commands (deprecated, use grouped commands above): + tito info, tito status, tito test, tito sync, etc. + """ ) # Global options @@ -143,7 +166,25 @@ class TinyTorchCLI: # Handle no command if not parsed_args.command: - parser.print_help() + # Show enhanced help with command groups + self.console.print(Panel( + "[bold cyan]TinyTorch CLI - Build ML Systems from Scratch[/bold cyan]\n\n" + "[bold]Command Groups:[/bold]\n" + " [bold green]system[/bold green] - System environment and configuration\n" + " [bold green]module[/bold green] - Module development and management\n" + " [bold green]package[/bold green] - Package management and nbdev integration\n\n" + "[bold]Quick Start:[/bold]\n" + " [dim]tito system info[/dim] - Show system information\n" + " [dim]tito module status --metadata[/dim] - Module status with metadata\n" + " [dim]tito package sync[/dim] - Export notebooks to package\n\n" + "[bold]Get Help:[/bold]\n" + " [dim]tito system[/dim] - Show system subcommands\n" + " [dim]tito module[/dim] - Show module subcommands\n" + " [dim]tito package[/dim] - Show package subcommands\n" + " [dim]tito --help[/dim] - Show full help", + title="TinyTorch CLI", + border_style="bright_blue" + )) return 0 # Execute command