calendar-autoblock
A Google Apps Script that keeps a Google Calendar at a target occupancy with untitled blocking events, so working hours stop being endlessly bookable. It respects real meetings, never touches an event it did not create, and runs dry by default.
- 2026
- Design, engineering
- JavaScript, Google Apps Script, Google Calendar API, clasp, Node.js
Open calendar slots get taken. Dropping placeholder blocks by hand works and then decays: you stop doing it, and a week later the afternoons are gone again. This script runs daily and keeps a rolling two-week window at whatever occupancy you ask for.
How it places blocks
Occupancy is measured as a total. Ask for 50% and a week already 30% booked with real meetings receives 20% of generated blocks, not 50% on top. Lunch and the end of the day are hard reserves, placed on every free day and never pruned, so they act as a floor even when the week is already busy; every run logs the projected occupancy and notes when it lands above the target.
Everything else is sampled. A candidate gets a weighted start time and a 30, 45 or 60 minute duration, and it is accepted only if it overlaps nothing, leaves no gap shorter than 30 minutes beside another event, and builds no contiguous wall longer than two hours. After enough rejections it relaxes to the shortest duration, and if the target still cannot be met it logs the shortfall instead of forcing blocks in. The next two days are frozen apart from conflict cleanup, so availability other people already saw does not get reshuffled.
Safety
Generated events carry a private extended property, and the script only ever deletes or modifies events carrying it, re-fetching each one to verify the tag before removing it. Blocks you placed by hand look like any other real meeting to the script: counted toward occupancy, never touched. DRY_RUN defaults to true, so the first run only logs the plan. Per-run caps abort before writing if a bug ever produces an implausible plan, and one function removes every generated block for the next year.
The placement engine is pure and tested. The same fourteen assertions run under Node with a stub for the one Apps Script API the pure code touches, and unchanged inside the Apps Script editor. There is no configuration UI; the constants are the interface. MIT licensed.
Technology
- Google Apps Script running on a daily time-based trigger, so it needs no server and no browser open. It reads and writes through the Calendar advanced service, tagging every event it creates with a private extended property.
- A pure placement engine separated from the Apps Script API: weighted sampling of start times and durations, gap and chain constraints, a freeze window for the next two days, and a logged shortfall instead of forced blocks when the target cannot be met.
- clasp for pushing code from a local repo, with Node.js running the same fourteen engine tests locally through a stub for the one Apps Script call the pure code makes. The suite also runs unchanged inside the Apps Script editor.
- Safety rails as code:
DRY_RUNon by default, per-run caps on creates and deletes, a re-fetch and tag check before every deletion, and a single function that removes every generated block for the next year. MIT licensed.