taslim/calsync

A lightweight, stateless Google Apps Script that automatically mirrors your personal calendar events as private holds on your work calendar.

1

stars

15

commits

JavaScript

primary language

Sep 3, 2026

updated

taslim.xyz

README

CalSync 📅

A Google Apps Script that mirrors your personal calendar as [DNS] External Appointment holds on your work calendar, so colleagues see that you are busy without seeing why.

What it does

  • Clamps each personal event to your work hours, in your work calendar's time zone, with one hold per weekday it touches.
  • Ignores all-day events, events marked Free, declined invitations, and weekends.
  • Skips holds fully covered by an Out of Office block, and holds that would fill a whole workday (use Out of Office for those).
  • Keeps holds in step with their events: they move, shrink, and disappear as the personal event changes. Runs every 5 minutes and stores nothing outside the two calendars.
  • Tags each mirrored personal event, or recurring series, with the id of its earliest hold in the window (workHoldId, a private extended property), so tools that only see your personal calendar can tell holds from real conflicts. Optional.

Setup

  1. On your personal account, share the calendar with your work account: Settings › Settings for my calendars › your calendar › Share with specific people. Permission: Make changes to events, or See all event details if you turn tagPersonalEvents off. Free/busy is not enough.
  2. On your work account, open script.google.com, create a project, and paste Code.js into it.
  3. Edit CONFIG at the top: your personal calendar address(es), work hours, and anything else you want changed.
  4. Add the Google Calendar API under Services (the + in the sidebar).
  5. Run install from the function dropdown and grant the permissions it asks for (Advanced › Go to project).

Each run logs what it created, updated, and removed under Executions.

Everyday use

  • Change a setting: edit CONFIG and save. The next run applies it to existing holds.
  • Skip one event: mark it Free or decline it on your personal calendar. Deleting the hold only brings it back on the next run.
  • Read the tag: workHoldId is present while the event has a hold within the 28-day window and cleared once it needs none. A recurring event carries it on the series, so every occurrence shows it.
  • Remove a calendar: run uninstall, take it out of CONFIG, then run install. Holds are looked up by calendar, so its holds would otherwise stay.
  • Upgrade: paste the new Code.js and run install once. It rebuilds the holds.
  • Stop: run uninstall. It removes the trigger and every hold.

Development

node --test runs Code.js against in-memory stand-ins for the Calendar API. Node 20 or newer, no dependencies.

Contributors

claude

8 commits

taslim

7 commits

taslim/calsync

A lightweight, stateless Google Apps Script that automatically mirrors your personal calendar events as private holds on your work calendar.

1

stars

15

commits

JavaScript

primary language

Sep 3, 2026

updated

taslim.xyz

README

CalSync 📅

A Google Apps Script that mirrors your personal calendar as [DNS] External Appointment holds on your work calendar, so colleagues see that you are busy without seeing why.

What it does

  • Clamps each personal event to your work hours, in your work calendar's time zone, with one hold per weekday it touches.
  • Ignores all-day events, events marked Free, declined invitations, and weekends.
  • Skips holds fully covered by an Out of Office block, and holds that would fill a whole workday (use Out of Office for those).
  • Keeps holds in step with their events: they move, shrink, and disappear as the personal event changes. Runs every 5 minutes and stores nothing outside the two calendars.
  • Tags each mirrored personal event, or recurring series, with the id of its earliest hold in the window (workHoldId, a private extended property), so tools that only see your personal calendar can tell holds from real conflicts. Optional.

Setup

  1. On your personal account, share the calendar with your work account: Settings › Settings for my calendars › your calendar › Share with specific people. Permission: Make changes to events, or See all event details if you turn tagPersonalEvents off. Free/busy is not enough.
  2. On your work account, open script.google.com, create a project, and paste Code.js into it.
  3. Edit CONFIG at the top: your personal calendar address(es), work hours, and anything else you want changed.
  4. Add the Google Calendar API under Services (the + in the sidebar).
  5. Run install from the function dropdown and grant the permissions it asks for (Advanced › Go to project).

Each run logs what it created, updated, and removed under Executions.

Everyday use

  • Change a setting: edit CONFIG and save. The next run applies it to existing holds.
  • Skip one event: mark it Free or decline it on your personal calendar. Deleting the hold only brings it back on the next run.
  • Read the tag: workHoldId is present while the event has a hold within the 28-day window and cleared once it needs none. A recurring event carries it on the series, so every occurrence shows it.
  • Remove a calendar: run uninstall, take it out of CONFIG, then run install. Holds are looked up by calendar, so its holds would otherwise stay.
  • Upgrade: paste the new Code.js and run install once. It rebuilds the holds.
  • Stop: run uninstall. It removes the trigger and every hold.

Development

node --test runs Code.js against in-memory stand-ins for the Calendar API. Node 20 or newer, no dependencies.

Contributors

claude

8 commits

taslim

7 commits

Languages

JavaScript

100.0%