Every new type is assumed to be a “container” by default. If you want to opt out of this for a new type that you define, you define Base.broadcastable(x::MyType) = Ref(x). This has been done for strings and a bunch of other types, and packages should use it too.
Treating Strings as “atoms” seems to be much more common than treating them as containers of characters (e.g. consider strings as filenames, as labels in a dataframe, as keys in a dictionary…). Also, keep in mind that “characters” are often an ambiguous way to think about the contents of strings. For example, "Raphaël" and "Raphaël" are canonically equivalent strings, but they don’t contain the same Chars (or even the same number of Chars).
(And the non-consecutive indexing of String—which is crucial for efficient access with a variable-length encoding like Julia’s UTF-8—also makes them technically difficult to treat as an AbstractVector{Char} in broadcast or anywhere else.)