| name | add-cli-subcommand |
| description | Add a new subcommand to the dotcontext bash CLI (e.g. `dotcontext status`, `dotcontext validate`) — define the command function, route it via the case statement, and wire help and shell completion. Use when extending the CLI surface. |
Skill: Add a New CLI Subcommand
When to Use
Use this skill when you need to add a new subcommand to the dotcontext CLI (e.g., dotcontext status, dotcontext validate).
Prerequisites
- Understanding of bash scripting
- Familiarity with the existing command structure in
dotcontext
Steps
1. Define the command function
Add a new function in the dotcontext script. Follow the naming convention cmd_<name>:
cmd_status() {
print_header "Status"
print_green "✓ Status check complete"
}
2. Add to the command router
Find the case statement in main() and add your command:
case "$1" in
init)
shift
cmd_init "$@"
;;
status)
shift
cmd_status "$@"
;;
esac
3. Add help text
Update the show_help() function:
show_help() {
echo "Usage: dotcontext <command> [options]"
echo ""
echo "Commands:"
echo " init Initialize context structure"
echo " status Check context health"
}
4. Handle arguments
Parse command-specific flags:
cmd_status() {
local verbose=false
while [ $# -gt 0 ]; do
case "$1" in
-v|--verbose)
verbose=true
shift
;;
*)
print_red "Unknown option: $1"
exit 1
;;
esac
done
}
5. Use helper functions
Leverage existing helpers for consistent output:
print_green "Success message"
print_yellow "Warning message"
print_red "Error message"
print_blue "Info message"
if prompt_yes_no "Continue?"; then
fi
download_file "$url" "$dest"
6. Test on multiple platforms
Test your command on:
- macOS (bash 3.2)
- Linux (bash 5.x)
- WSL (if applicable)
Anti-Patterns
- Don't use bashisms - Avoid
[[ ]], $'...', arrays (use POSIX [ ], quoted strings)
- Don't hardcode paths - Use variables like
$CONTEXT_DIR
- Don't skip error handling - Check file existence, command success
- Don't output without color helpers - Use
print_* functions for consistency
Example
From the existing cmd_update function:
cmd_update() {
local update_templates=false
local force=false
while [[ $# -gt 0 ]]; do
case "$1" in
--templates) update_templates=true; shift ;;
--force) force=true; shift ;;
*) shift ;;
esac
done
if [ "$update_templates" = true ]; then
cmd_update_templates "$force"
else
cmd_update_cli
fi
}
Related
- ADR-001: Single bash executable
- Critical Rule: POSIX compatibility