Custom Commands
Cecli allows you to create and use custom commands to extend its functionality. Custom commands are Python classes that extend the BaseCommand class and can be loaded from specified directories or files.
How Custom Commands Work
Command Registry System
Cecli uses a centralized command registry that manages all available commands:
- Built-in Commands: Standard commands like
/add,/model,/help, etc. - Custom Commands: User-defined commands loaded from specified paths
- Command Discovery: Automatic loading of commands from configured directories
Configuration
Custom commands can be configured using the command-paths configuration option in your YAML configuration file:
custom:
command-paths: [".aider/custom/commands", "~/my-commands/", "./special_command.py"]
The command-paths configuration option allows you to specify directories or files containing custom commands to load.
The command-paths can include:
- Directories: All
.pyfiles in the directory will be scanned forCustomCommandclasses - Individual Python files: Specific command files can be loaded directly
When cecli starts, it:
- Parses configuration: Reads
command-pathsfrom config files - Scans directories: Looks for Python files in specified directories
- Loads modules: Imports each Python file as a module
- Registers commands: Finds classes named
CustomCommandand registers them - Makes available: Registered commands appear in
/helpand can be executed
Creating Custom Commands
Custom commands are created by writing Python files that follow this structure:
from typing import List
from cecli.commands.utils.base_command import BaseCommand
from cecli.commands.utils.helpers import format_command_result
class CustomCommand(BaseCommand):
NORM_NAME = "custom-command"
DESCRIPTION = "Description of what the command does"
@classmethod
async def execute(cls, io, coder, args, **kwargs):
"""
Execute the custom command.
Args:
io: InputOutput instance
coder: Coder instance (may be None for some commands)
args: Command arguments as string
**kwargs: Additional context
Returns:
Optional result (most commands return None)
"""
# Command implementation here
result = f"Command executed with arguments: {args}"
return format_command_result(io, cls.NORM_NAME, result)
@classmethod
def get_completions(cls, io, coder, args) -> List[str]:
"""
Get completion options for this command.
Args:
io: InputOutput instance
coder: Coder instance
args: Partial arguments for completion
Returns:
List of completion strings
"""
# Return completion options or raise CommandCompletionException
# for dynamic completions
return []
@classmethod
def get_help(cls) -> str:
"""
Get help text for this command.
Returns:
String containing help text for the command
"""
help_text = super().get_help()
help_text += "\nAdditional information about this custom command."
return help_text
Important Requirements
- Class Name: The command class must be named exactly
CustomCommand - Inheritance: Must inherit from
BaseCommand(fromcecli.commands.utils.base_command) - Class Properties: Must define
NORM_NAMEandDESCRIPTIONclass attributes - Execute Method: Must implement the
executeclass method
Example: Add List Command
Here’s a complete example of a custom command that adds a list of numbers:
from typing import List
from cecli.commands.utils.base_command import BaseCommand
from cecli.commands.utils.helpers import format_command_result
class CustomCommand(BaseCommand):
NORM_NAME = "add-list"
DESCRIPTION = "Add a list of numbers."
@classmethod
async def execute(cls, io, coder, args, **kwargs):
"""Execute the context command with given parameters."""
num_list = map(int, filter(None, args.split(" ")))
return format_command_result(io, cls.NORM_NAME, sum(num_list))
@classmethod
def get_completions(cls, io, coder, args) -> List[str]:
"""Get completion options for context command."""
# The original completions_context raises CommandCompletionException
# This is handled by the completion system
from cecli.io import CommandCompletionException
raise CommandCompletionException()
@classmethod
def get_help(cls) -> str:
"""Get help text for the context command."""
help_text = super().get_help()
help_text += "Add list of integers"
return help_text
Complete Configuration Example
Complete configuration example in YAML configuration file (.aider.conf.yml or ~/.aider.conf.yml):
# Model configuration
model: gemini/gemini-3-pro-preview
weak-model: gemini/gemini-3-flash-preview
# Custom commands configuration
custom:
command-paths: [".aider/custom/commands"]
# Other cecli options
...
Error Handling
If there are errors loading custom commands:
- Invalid paths: Warnings are logged but cecli continues to run
- Syntax errors: The specific file fails to load but other commands still work
- Missing requirements: Commands that can’t be imported are skipped
Best Practices
- Organize commands: Group related commands in the same directory
- Use descriptive names: Make
NORM_NAMEclear, memorable, and unique - Provide good help: Implement
get_help()with clear usage instructions - Handle errors gracefully: Use
format_command_result()for consistent output - Test commands: Verify commands work before adding to production config
Integration with Other Features
Custom commands work seamlessly with other cecli features:
- Command completion: Custom commands appear in tab completion
- Help system: Included in
/helpoutput - TUI interface: Available in the graphical interface
- Agent Mode: Can be used alongside Agent Mode tools
Benefits
- Extensibility: Add project-specific functionality
- Automation: Create commands for repetitive tasks
- Integration: Connect cecli with other tools and systems
- Customization: Tailor cecli to your specific workflow
Custom commands provide a powerful way to extend cecli’s capabilities, allowing you to create specialized functionality for your specific needs while maintaining the familiar command interface.