Not sure what the name for this type of cycling would be, but the approach I would take to this is to use an additional command that's actually triggered by the keypress, which uses an integer (regular, don't bother with small) variable to keep track of which command in the rotation should be executed, some conditions, and the "Execute Another Command" action.
A relatively simple method would be something like
Begin Integer Compare : [>{CMDWHENISAY}TargetIndex] Equals 0
Execute command, 'command 1'
Else If Integer Compare : [>{CMDWHENISAY}TargetIndex] Equals 1
Execute command, 'command 2'
Else If Integer Compare : [>{CMDWHENISAY}TargetIndex] Equals 2
Execute command, 'command 3'
End Condition
Set integer [>{CMDWHENISAY}TargetIndex] to [>{CMDWHENISAY}TargetIndex] plus 1
Begin Integer Compare : [>{CMDWHENISAY}TargetIndex] Is Greater Than 2
Set integer [>{CMDWHENISAY}TargetIndex] value to 0
End Condition
Note the use of the "{CMDWHENISAY}" token in the command name, which will be replaced with the contents of the "When I say" field of the command when the command executes, which means you can have as many copies of this command in your profile without needing to come up with a unique variable name for each variation.
The ">" prefix also means the variable is non-persistently profile-scoped, meaning it will be reset whenever you unload the profile the command is in, so it'll start from the top again (if you want to keep the value instead, change that to ">>" instead to make it a persistently profile-scoped variable, which will be available to the profile whenever it's loaded within the same session (I.E. the value is still lost when VoiceAttack shuts down, as with any variable scope)
Now, that will work just fine by itself, but you'll notice that each potential branch of the condition needs to check for a specific number, as well as the condition that resets the number when the last item is reached check for a value greater than a specific number.
The latter needs to be incremented whenever you add another branch to the condition, which isn't too much hassle, but, if you need to insert or remove an item somewhere aside from the very end of the list, you'd need to re-number (or move the "Execute Another Command" action for) every single other option after the one you insert or remove
An alternative method that does not exhibit that issue when editing, would be something like
Set integer [>{CMDWHENISAY}TargetIndex] to [>{CMDWHENISAY}TargetIndex] plus 1
Set integer [~currentIndex] to [~currentIndex] plus 1
Begin Integer Compare : [>{CMDWHENISAY}TargetIndex] Equals [~currentIndex]
Execute command, 'command 1'
End Condition - Exit when condition met
Set integer [~currentIndex] to [~currentIndex] plus 1
Begin Integer Compare : [>{CMDWHENISAY}TargetIndex] Equals [~currentIndex]
Execute command, 'command 2'
End Condition - Exit when condition met
Set integer [~currentIndex] to [~currentIndex] plus 1
Begin Integer Compare : [>{CMDWHENISAY}TargetIndex] Equals [~currentIndex]
Execute command, 'command 3'
End Condition - Exit when condition met
Set integer [>{CMDWHENISAY}TargetIndex] value to 0
Set integer [~currentIndex] value to 0
Jump: Command Start
This example uses two variables: The target index, which is profile-scoped and keeps track of which command was executed previously, and the current index, which is command-scoped (meaning the value is only available to the instance of the command being executed, and is lost when that instance stops executing) and used to check whether the item being evaluated by a condition is the one that should be executed.
The "When this block is reached, exit command if condition is met" option of the "End a Conditional Block" action is used to stop the command when the target item is reached and has been executed.
At the bottom, if none of the items in the list were at the target index, logically the target index must be beyond the amount of available items, so because the command isn't stopped before the end as none of the conditions were met, both indices are reset to 0.
Next, a "Jump to a Place in this Command" action is used with the "Jump to the Beginning of this Command" option, to essentially restart the command from the top.
As the index was reset to 0, the command first increments it to 1, and then the first item in the list will be executed, thus completing the cycle and stopping the command
Do make sure to enable the "Evaluate 'Not Set' as zero" in the conditions and the "Set an Integer Value" actions that increment the value (regardless of which of the examples you choose)
Spaces in the action list are empty "Add a Comment to the Action List" actions, to visually separate the different blocks
Adding an item to the list is as simple as selecting and duplicating a single block consisting of the "Set an Integer Value" action and the condition
E.G. adding a fourth command, say between the first and the second commands, would look like
Set integer [>{CMDWHENISAY}TargetIndex] to [>{CMDWHENISAY}TargetIndex] plus 1
Set integer [~currentIndex] to [~currentIndex] plus 1
Begin Integer Compare : [>{CMDWHENISAY}TargetIndex] Equals [~currentIndex]
Execute command, 'command 1'
End Condition - Exit when condition met
Set integer [~currentIndex] to [~currentIndex] plus 1
Begin Integer Compare : [>{CMDWHENISAY}TargetIndex] Equals [~currentIndex]
Execute command, 'command 4'
End Condition - Exit when condition met
Set integer [~currentIndex] to [~currentIndex] plus 1
Begin Integer Compare : [>{CMDWHENISAY}TargetIndex] Equals [~currentIndex]
Execute command, 'command 2'
End Condition - Exit when condition met
Set integer [~currentIndex] to [~currentIndex] plus 1
Begin Integer Compare : [>{CMDWHENISAY}TargetIndex] Equals [~currentIndex]
Execute command, 'command 3'
End Condition - Exit when condition met
Set integer [>{CMDWHENISAY}TargetIndex] value to 0
Set integer [~currentIndex] value to 0
Jump: Command Start
No re-numbering at all, just select, duplicate, edit the "Execute Another Command" action to execute the desired command, and save.