When you define a PyMC model you define a generative model (think of it as chained np.random.foo functions), that can be evaluated via forward sampling to obtain random draws. You take draws from the top variables and then pass it to the children and so on, until there are no variables left to evaluate.
This notebook goes a bit over the internals: PyMC and PyTensor — PyMC 5.10.0 documentation and this outdated notebook shows a simple re-implementation of sample_prior_predictive from scratch: Google Colab
If you provide either a random or dist functions to CustomDist those will be used for forward sampling in prior_predictive. As I mentioned a PyMC model is just a (symbolic) chain of np.random.foo calls, and your random function is one more in there.
Let me know if this is too hand-wavy and you need more precise pointers.