For a custom triggered one, I think you should be able to steal the Campaigner query and tweak it to work for badges instead of invites.
This one is for having 5 ‘Badge 108’, and would be set to update daily.
SELECT u.id user_id, current_timestamp granted_at
FROM users u
WHERE u.id IN (
SELECT ub.user_id
FROM user_badges ub
WHERE ub.badge_id = 108
GROUP BY ub.user_id
HAVING COUNT(*) >= 4
) AND u.active AND u.silenced_till IS NULL AND u.id > 0 AND
(:backfill OR u.id IN (:user_ids) )
I’ve tested it briefly on my test site and it seems to work okay (I trigger the Badge Grant sidekiq job to speed up the wait). But hopefully that at least gives you a starting point to build from.
There are also a few different examples in here you can use for inspiration, if you’ve not found it yet, Some common badge queries idea