Sync one or more source Google calendars into private Busy hold events in one or more target calendars using gog. Use when users need idempotent double-booking prevention, backfill of legacy holds, drift reconcile, or safe scheduled sync.
Scanned 9/7/2026
Install to Claude Code
npx -y skills add modbender/skill-library-mcp --skill calendar-hold-sync --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Calendar Hold Sync?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/modbender-calendar-hold-sync)More formats (shields.io, HTML) on the badges page.
---
name: calendar-hold-sync
description: Sync one or more source Google calendars into private Busy hold events in one or more target calendars using gog. Use when users need idempotent double-booking prevention, backfill of legacy holds, drift reconcile, or safe scheduled sync.
---
# Calendar Hold Sync
Implement hold mirroring from source Google calendars into target calendars to prevent double-booking.
## Dependency
- Require `gog` CLI in `PATH`.
- Require user OAuth already configured for each account used in `mappings`.
- Do not hardcode account emails, calendar IDs, or event IDs in code.
If `gog` is not configured, use this setup flow:
1. Run `gog auth credentials /path/to/client_secret.json`.
2. Run `gog auth add you@gmail.com --services calendar`.
3. Verify with `gog auth list`.
Only add additional Google services if you explicitly need them for another workflow.
Official `gog` references:
- Homepage: https://gogcli.sh/
- Source: https://github.com/steipete/gogcli
## Config Contract
Use a user-provided JSON config file with this shape:
- `mappings[]`
- `mappings[].name`
- `mappings[].targetAccount`
- `mappings[].targetCalendarId` (default `primary`)
- `mappings[].sources[]` with `{ account, calendarId }`
- `mappings[].lookaheadDays` (default `30`)
- `mappings[].allDayMode`: `ignore|mirror`
- `mappings[].overlapPolicy`: `skip|allow`
- `hold.summary` (default `Busy`)
- `hold.visibility` (`private`)
- `hold.transparency` (`busy`)
- `hold.notifications` (`none`)
- `hold.reminders` (`none`)
- `metadata.format` (`SYNCV1`)
- `metadata.encoding` (`base64url(json)`)
- `metadata.fields`: `srcAccount,srcCalendar,eventId,start,end,title`
- `scheduling.reconcileCron`
- `scheduling.daytimeCron` (optional)
- `scheduling.driftWindowDays` (optional)
- `scheduling.watchIntervalSeconds` (optional, default `20`)
- `safety.dryRun`
- `safety.maxChangesPerRun`
- `safety.excludeIfSummaryMatches[]`
- `safety.excludeIfDescriptionPrefix[]`
- `gog.listEventsCmd|createEventCmd|updateEventCmd|deleteEventCmd` (optional template overrides)
- `gog.allowCustomCommands` (must be `true` to enable any `gog.*Cmd` override)
## Custom Command Template Safety
When custom commands are enabled:
- Only `gog` command templates are accepted.
- Templates are rendered by replacing placeholders like `{account}` and `{calendarId}`.
- Rendered commands are executed as argv tokens (no shell interpolation).
- Keep `gog.allowCustomCommands=false` unless you fully trust and audit the config file.
## Metadata Encoding
Store source linkage in hold `description` as:
- `SYNCV1:<base64url(JSON)>`
JSON fields:
- `srcAccount`
- `srcCalendar`
- `eventId`
- `start`
- `end`
- `title`
## Behavior
For each mapping:
1. Read source events in the active window.
2. Build desired hold events (`private`, `busy`, no reminders).
3. Detect existing managed holds by `SYNCV1:` prefix.
4. Reconcile idempotently:
- Create missing holds.
- Update drifted holds.
- Delete stale holds.
5. If overlap policy is `skip`, do not create a hold when a non-managed target event overlaps.
6. Enforce `maxChangesPerRun`.
7. Respect `dryRun`.
## Backfill
Backfill mode upgrades legacy hold events (matching expected hold signature but lacking `SYNCV1`) by attaching encoded metadata when a unique source match exists.
## Command Surface
- `hold-sync validate-config`
- `hold-sync reconcile --mapping <name>|--all [--dry-run]`
- `hold-sync backfill --mapping <name>|--all [--dry-run]`
- `hold-sync status --mapping <name>|--all`
- `hold-sync install-cron --mapping <name>|--all`
- `hold-sync watch --mapping <name>|--all [--dry-run] [--interval-seconds <n>]`
## Watch Cadence
Require watch cadence to be configurable from user config:
- `scheduling.watchIntervalSeconds` controls watch poll frequency.
- `mappings[].lookaheadDays` controls rolling watch/reconcile window.
Recommend baseline values:
- `watchIntervalSeconds: 900` (15 minutes)
- `lookaheadDays: 1` (24 hours)
## Working Model
- Use polling-based watch mode (`hold-sync watch`) for fast updates.
- Expect update latency approximately equal to `watchIntervalSeconds`.
- Treat this as self-hosted/operator-run automation.
## Known Limits
- Do not assume webhook/push subscriptions are present; current fast sync path is polling.
- Keep periodic scheduled reconcile as fallback even when watch mode is enabled.
## Required Tests
- metadata encode/decode round-trip
- overlap detection correctness
- idempotent reconcile upsert/delete behavior
Attribution: `gog` setup flow adapted from:
- https://clawhub.ai/steipete/gog
- https://github.com/steipete/gogcli
- https://gogcli.sh/
## Provider Notes (openclaw)
Use this variant when publishing to ClawHub/OpenClaw.
- Keep instructions implementation-focused and command-oriented.
- Keep dependency explicit: `gog` must be preconfigured by user.
- Prefer deterministic script execution over speculative edits.
- Avoid provider-specific APIs; treat the CLI as the boundary.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!