What to do for macro-only APIs?

I'm working on a crate that does a lot of work with macros, and the generated code ends up calling back into plain functions and referring to items from my crate. Subsequently, these items need to be public, because their callers are technically code in external crates, even though that code is generated by my macro.

This is inconvenient for compatibility, because external code can potentially call into these functions that are really implementation details that are only public for technical reasons. I don't want to have to pay attention to these functions' interfaces or incorporate them into the semver of my crate. I've marked them #[doc(hidden)] to hopefully discourage that, but it would be nicer to be able to completely rule out anyone but me calling them.

If the macros are macro_rules macros, then all of the items can live in a single crate, which would make it easy it limit what is exposed.

Which leads me to believe that you're using attribute macros and/or proc-macros.
If so, then keep in mind that ultimately macros are just a fa├žade for the generated code i.e. of the generated code would need to use a public API, then so does the macro. So it isn't the macro imposing the pub-ness, it's the code that the macro invocations expand to that does the imposing.

Because of that, if the calls need to cross crate boundaries then I think hiding the items from generated docs is about the best that currently can be achieved.
If others then use the hidden items, and the API breaks, then that's on the consumers since no stability was promised on those APIs in the first place.

But it does make me think of a hypothetical pub(machine) visibility that would mark an item as pub but only to consumers that live within macroexpansions.