Taking in user input in such a way can be dangerous, I had to use the $safe alias to guard against injection when evaluating the subcommand. Make sure to understand everything on this page if you're handling unknown content: http://en.wikichip.org/wiki/mirc/msl_injection

Here I've used a regex which captures a command and its arguments, if the arguments also match the regex I make a recursive call. The regex is designed such that empty or missing brackets are also acceptable: @command@ or @command@[]. Limiting character classes may help guard against invalid input depending on your preference. Reading back over your examples maybe I've misunderstood that subsequent text should be evaluated rather than the arguments in [], but you'll need to provide a more exact syntax if that's the case. I think trying to allow both would create an ambiguous syntax or complicate the code on a per-command basis.

Some work could be done in regard to $isid but that's a general issue and does not deal directly with the problem at hand (recursion).

This will embolden and underline text:
//echo -ag $processcommand(@bold@[@underline@[some @value@[] $chr(91) $chr(93) $!pi $($pi %foo,0) with pi]])

This will beep and echo text:
//noop $processcommand(@echo@[@beep@])

This will echo text as per your described commands:
//noop $processcommand(@echo@[@lower@[@target@[1] ONE TWO THREE]])

Code:
alias processcommand {
  var %regex = /^@(\S+?)@(?:\[(.*)\])?(.*)$/iS

  if (!$regex($1-,%regex)) return

  var %command = $regml(1)
  var %args = $regml(2)
  var %text = $regml(3)

  if (%args != $null) && ($regex(%args,%regex)) {
    %args = $recurse($!processcommand( $safe(%args) ))
  }

  if (%command == lower) {
    return $lower(%args)
  }
  if (%command == target) {
    return $gettok(%text,%args,32)
  }
  elseif (%command == bold) {
    return  $+ %args
  }
  elseif (%command == underline) {
    return  $+ %args
  }
  elseif (%command == beep) {
    beep | return beep
  }
  elseif (%command == echo) {
    echo -ag %args | return echo
  }

}

alias recurse { if ($isid) return $($1-,2) | else $1- }
alias safe return $!decode( $encode($1,m) ,m)