This is how I do monthly scheduled procedures:
ad_schedule_proc -thread t -schedule_proc ns_schedule_daily [list 0 0] proc_name_here
This actually runs the procedure every day at midnight, but the next part is this:
In the procedure you're running daily, check to see which day of the month it is. In my case, I make sure it's the first day of each month at the very beginning. If it's not, then I do nothing, otherwise, the procedure will continue.
if {[clock format [clock seconds] -format "%e"] != 1} {
return
}
A more elegant method may exist, but this is how I've done it for a long time, and it works fine.