Why does this recursive pattern guard not work?

Recursive patterns are tricky. I suggest you to browse this site for different approaches.

In the current case you have to include patterns to match both ptn and lists of ptn:

ptn = {_String, {___String}, {___String} | 
          (a_ /; MatchQ[a, ptn ..]) | (a_ /; And @@ (MatchQ[#, ptn ..] & /@ a))};

MatchQ[lst, ptn]
(* True *)

MatchQ[{"a", {}, {}}, ptn]
(* True *)

MatchQ[{"a", {"b"}}, ptn]
(* False *)

l = {u, {u, {v, {u, {u, v}}}}} /.
                              u -> Sequence @@ {"a", {"b"}} /. v -> {"a", {"b"}, {"c"}}
(* {"a", {"b"}, {"a", {"b"}, {{"a", {"b"}, {"c"}}, {"a", {"b"}, {"a", {"b"}, 
   {"a", {"b"}, {"c"}}}}}}} *)

MatchQ[l, ptn]
(* True *)