It's mostly based on manipulating lists. Scoping is a bit odd, but if you squint, the fact that unevaluated lists are passed into functions where they can be manipulated (by normal tcl list functions) and then evaluated in the caller's scope (or in other scopes), coupled with the fact that built in syntax (if, proc, for, etc) is the same as user-defined function call syntax, gives you more metaprogramming power than you might expect.
True, mostly. As the other commenter noted, function calls can be squeezed through some rather macro-looking holes if you just push hard enough.
Don't get me wrong, Tcl metaprogramming is awful and gross and I don't recommend it, I was just being the stereotypical nitpick HN commenter for that moment since it CAN be done.