Commands are automatically discovered from module exports - no manual registration required.
- List modules in
.commando/config.yml - Export commands from those modules
- Framework discovers and registers them automatically
# .commando/config.yml
modules:
- ./website
- ./examplesThat's it! No command mapping needed.
// website.ts
export const build: CommandoCommand = {
description: 'Build website',
execute: async (options, args, context) => {
// implementation
}
};
export const deploy: CommandoCommand = {
description: 'Deploy website',
execute: async () => { ... }
};Result: build and deploy commands available
// examples.ts
export default {
hello: {
description: 'Say hello',
execute: async () => console.log('Hello!')
},
version: {
description: 'Show version',
execute: async () => console.log('v2.0.0')
}
};Result: hello and version commands available
// commands.ts
export const build: CommandoCommand = { ... };
export default {
build, // Re-export
'special-name': { ... } // Custom name in object
};The framework checks each module for:
- Named exports - Any export that looks like a CommandoCommand (has
descriptionandexecute) - Default export - If it's an object, treat keys as command names
Detection:
function isCommandoCommand(obj: any): boolean {
return obj
&& typeof obj === 'object'
&& typeof obj.description === 'string'
&& typeof obj.execute === 'function';
}-
Named export: Command name = export name
export const build = { ... } // Command: "build"
-
Default export: Command name = object key
export default { hello: { ... } } // Command: "hello"
-
Kebab-case: Use default export for custom names
export default { 'get-config': getConfig, 'clear-cache': clearCache }
✅ Zero boilerplate - Export a command, it works ✅ Flexible - Named exports, default export, or both ✅ Type-safe - TypeScript validates CommandoCommand structure ✅ Simple - config.yml is just a module list
- Module Metadata - Customize group names with
__module__ - Subcommand Groups - Group commands under namespaces