I want to create a completion script for: > program [OPTS] SUBCOMMAND [SUBCOMMAND-OPTS] [ARGS] A common approach is: _arguments -C \ '1: :cmds' \ '*::arg:->args' \ && ret=0 case $state in (args) case $line[1] in (subcmd1|subcmd2) _message 'no more arguments' && ret=0 ;; (subwithextraopts) _arguments ... && ret=0 ;; (othersubwithextraopts) _arguments ... && ret=0 ;; esac esac But that relies on subcommand being at $line[1] which is rarely the case (at least in my application) git is actually a good example: git -TAB #tabs git options git add -TAB #tabs git-add options git --bare log -TAB #tabs git-log options (but log is not $line[1] That leads to the idea using git completion as reference, which in turn leads to the question: how to debug such a completion? It is a very extensive...