This guide is for developers who want to work with the Smart Sync Google Calendars project using local development tools, version control, and command-line deployment.
The CLI (Command-Line Interface) method provides:
- ✅ Local file editing - Use your favorite editor (VS Code, Cursor, Vim, etc.)
- ✅ Version control - Track changes with Git, create branches, roll back changes
- ✅ AI assistant integration - Use with Cursor, GitHub Copilot, or other AI coding tools
- ✅ Automation - Deploy with a single command (
npm run deploy) - ✅ Team collaboration - Share changes via Git, review code with pull requests
- ✅ Professional workflow - Matches standard software development practices
Prefer a simpler, browser-only setup? → See the UI Setup Guide for the UI method (no command-line tools required).
This project syncs multiple Google calendars into a single "Busy Time" calendar using Google Apps Script.
Source Calendars:
- Your personal calendar (e.g.,
user@gmail.com) - Your work calendars (e.g.,
work1@company.com,work2@company.com, etc.)
Target Calendar:
- "Busy Time" calendar (a shared Google Calendar where all events are synced with prefixes)
Sync Configuration:
- Window: 30 days in the past, 365 days in the future
- Trigger: Event-based (syncs when any source calendar updates)
- Privacy: No descriptions synced, locations included
- Prefixes: Events tagged with source calendar labels (e.g.,
[personal],[work1],[work2])
# Check if nvm is installed
which nvmIf nvm is not installed, install it from nvm-sh/nvm.
# List installed Node.js versions
nvm lsThe project includes an .nvmrc file that specifies the recommended Node.js version.
# Navigate to project root
cd /path/to/smart-sync-google-calendars
# Use the Node.js version specified in .nvmrc (LTS)
nvm useIf the LTS version isn't installed, install it:
# Install the latest LTS version
nvm install --lts
# Use it as the project version
nvm useTroubleshooting nvm:
If nvm command is not found, ensure it's loaded in your ~/.zshrc:
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"Then reload: source ~/.zshrc
Optional: Auto-Switch Node Versions
To automatically switch Node versions when entering the project directory, add this to your ~/.zshrc:
# Auto-load .nvmrc when entering directories
autoload -U add-zsh-hook
load-nvmrc() {
local node_version="$(nvm version)"
local nvmrc_path="$(nvm_find_nvmrc)"
if [ -n "$nvmrc_path" ]; then
local nvmrc_node_version=$(nvm version "$(cat "${nvmrc_path}")")
if [ "$nvmrc_node_version" = "N/A" ]; then
nvm install
elif [ "$nvmrc_node_version" != "$node_version" ]; then
nvm use
fi
elif [ "$node_version" != "$(nvm version default)" ]; then
echo "Reverting to nvm default version"
nvm use default
fi
}
add-zsh-hook chpwd load-nvmrc
load-nvmrcThen reload: source ~/.zshrc
# These should now work and show version numbers
node -v
npm -v
npx --version # Verify npx is also availableIf any of these commands fail, ensure you've run nvm use in the project directory.
The project includes a package.json file with clasp as a development dependency.
# Install all dependencies locally
npm installThis installs clasp locally in the node_modules directory rather than globally, ensuring version consistency.
# Check if clasp is available (should show version)
npx clasp --version- Visit the Apps Script API page in your user settings
- Make sure you're logged in to your primary Google account (the one that will host the script)
- Turn on "Google Apps Script API"
# Login using the locally installed clasp
npx clasp loginThis command will:
- Open a new tab in your default web browser
- Prompt you to log in to your Google account (use your primary Google account)
- Ask you to grant
clasppermissions to manage your Apps Script projects
After you approve the permissions, you can close the browser tab. Your terminal will show that you have been successfully logged in.
Now you can create the Apps Script project in your Google account.
npm run clasp:createThis runs: clasp create --title "Smart Sync Google Calendars" --rootDir . (from the scripts/ directory)
This command creates a new standalone Google Apps Script project in your Google account and creates a .clasp.json file in the scripts/ directory.
Important Note: After running this command, check the scripts/.clasp.json file. If it contains a rootDir that's not ".", update it to:
{"scriptId":"YOUR_SCRIPT_ID_HERE", "rootDir":"."}Before deploying, you need to configure which calendars to sync.
# Copy the example config to create your own
cp scripts/Config.gs.example scripts/Config.gsYou need to find the Calendar IDs for:
- Your personal calendar
- Each work calendar you want to sync
- Your target calendar (where synced events will appear)
→ See UI Setup Guide - Step 3: Find Your Calendar IDs for detailed instructions.
This section covers:
- How to find your personal calendar ID
- How to find work calendar IDs (including sharing requirements)
- How to create or identify a target calendar
Open scripts/Config.gs in your editor and fill in your actual calendar IDs:
const CALENDARS_TO_MERGE = {
"personal": "john.doe@gmail.com", // Your personal calendar ID
"work1": "john.doe@company1.com", // First work calendar
"work2": "john.contractor@company2.com", // Second work calendar
// Add or remove calendars as needed
}
const CALENDAR_TO_MERGE_INTO = "abc123def456...@group.calendar.google.com" // Target calendar IDNotes:
- The keys (
"personal","work1", etc.) become prefixes in synced event titles - You can customize the sync window and other settings in this file
- This file is git-ignored to protect your privacy
After creating the project and configuring your calendars, deploy the code:
npm run deployThis command pushes your local files (scripts/SyncCalendarsIntoOne.gs, scripts/BatchRequests.gs, scripts/Config.gs, scripts/appsscript.json) to Google Apps Script.
What happens during deployment:
- Your local
.gsfiles are uploaded to Google Apps Script - The
appsscript.jsonmanifest configures the project settings - Your
Config.gsfile is deployed (but remains git-ignored locally)
After the first push, create a "production" deployment. This gives you a stable version for your triggers to run against.
-
Create a version:
npm run clasp:version "Initial deployment"Note the version number that's output (e.g., "1").
-
Create a new deployment:
npx clasp deploy --description "Production deployment" --versionNumber {VERSION_NUMBER}Replace
{VERSION_NUMBER}with the version number from step 1 (e.g.,--versionNumber 1).Note: If the above command doesn't work, try:
npx clasp deploy
This creates a deployment using the latest version.
-
Save the Deployment ID: The command will output a Deployment ID. Save this for future reference, or run
npx clasp deploymentsto see it later.
npm run clasp:openThis opens your project in the Google Apps Script web editor.
→ See UI Setup Guide - Step 6: First Test Run & Authorization for detailed authorization and testing instructions.
This section covers:
- How to run the function manually
- Authorizing the script to access your calendars
- Understanding the "unsafe app" warning (it's safe because you're the developer)
- Checking execution logs
Quick summary:
- Select
SyncCalendarsIntoOnefrom the function dropdown - Click Run (
▶️ ) - Complete the authorization flow
- Check execution logs for success
→ See UI Setup Guide - Step 7: Verify Synced Events for instructions on verifying the sync worked.
This section covers:
- Finding synced events in your target calendar
- Verifying event prefixes
- Checking that times, locations, and conference links are preserved
You can also view logs from the command line:
npm run clasp:logsThis shows recent execution logs, which is helpful for debugging.
The sync only runs when triggered. Set up triggers so your calendars stay in sync automatically.
→ See UI Setup Guide - Step 8: Set Up Automatic Triggers for complete trigger setup instructions.
This section covers:
- Calendar-based triggers (recommended) - Syncs when source calendars update
- Time-based triggers (alternative) - Syncs on a schedule
- How to configure each trigger
- Best practices (one trigger per source calendar)
Quick summary:
- Open the Apps Script editor:
npm run clasp:open - Click the clock icon (⏰) to open Triggers
- Add one trigger per source calendar:
- Function:
SyncCalendarsIntoOne - Deployment:
Head - Event source:
From calendar - Calendar: Enter the calendar ID
- Function:
→ See UI Setup Guide - Step 9: Test Automatic Sync for testing instructions.
This section covers:
- Creating a test event in a source calendar
- Verifying it appears in the target calendar
- Checking execution history
Now that your project is set up, here's your typical development workflow:
-
Edit files locally in your favorite editor:
# Open in VS Code code scripts/SyncCalendarsIntoOne.gs # Or use Cursor, Vim, etc.
-
Deploy your changes:
npm run deploy
Changes take effect immediately for the
Headdeployment. -
Test your changes:
- Open the Apps Script editor:
npm run clasp:open - Run the function manually
- Check execution logs:
npm run clasp:logs
- Open the Apps Script editor:
If you need to add/remove calendars or change settings:
- Edit
scripts/Config.gslocally - Deploy changes:
npm run deploy
- Add/remove triggers if you added/removed source calendars
Since you're using Git, you can:
# Check status
git status
# Create a branch for your changes
git checkout -b feature/improve-sync-logic
# Commit your changes
git add scripts/SyncCalendarsIntoOne.gs
git commit -m "Improve event change detection"
# Push to remote
git push origin feature/improve-sync-logicRemember: scripts/Config.gs and scripts/.clasp.json are git-ignored to protect your private information.
When you're ready to create a stable version:
# Create a new version
npm run clasp:version "Description of changes"
# Create a deployment from that version
npx clasp deploy --description "Production v2" --versionNumber 2Problem: clasp can't find the files to deploy.
Solution:
- Check that
scripts/.clasp.jsonexists - Verify that
rootDirinscripts/.clasp.jsonis set to"." - Make sure you're running commands from the project root directory (npm scripts handle the
scripts/directory automatically)
Problem: clasp doesn't recognize your authentication.
Solution:
# Login again
npx clasp login
# Verify you're logged in
npx clasp whoamiProblem: npm run deploy fails with an error.
Solution:
- Check that you've authenticated:
npx clasp whoami - Verify the script ID in
scripts/.clasp.jsonmatches your project - Try pulling first to sync:
npx clasp pull(careful: this overwrites local changes) - Check the Apps Script API is enabled at script.google.com/home/usersettings
For common sync issues not specific to CLI:
- Events not syncing
- Calendar not found errors
- Authorization issues
- Duplicate events
- Wrong event times
- Triggers not firing
- Quota/rate limits exceeded
→ See UI Setup Guide - Troubleshooting for comprehensive troubleshooting guide.
Once you're set up, future code updates are simple:
# Make your changes in local files
vim scripts/SyncCalendarsIntoOne.gs
# Deploy to Google Apps Script
npm run deploy
# Check logs if needed
npm run clasp:logsFor more details on the deployment workflow, see the Updating Deployments Guide.
If you're using Cursor:
- Open the project in Cursor
- The AI has full context of your code
- Ask questions like:
- "How does the smart sync work?"
- "Can you add a feature to filter events by keyword?"
- "Help me debug why events aren't syncing"
- Make changes with AI assistance
- Deploy with
npm run deploy
If you're using GitHub Copilot in VS Code:
- Open
.gsfiles in VS Code - Copilot provides suggestions based on your code
- Use comments to guide Copilot:
// Create a function to filter events that contain "personal" - Accept suggestions and deploy
Understanding the file structure helps with development:
smart-sync-google-calendars/
├── scripts/
│ ├── SyncCalendarsIntoOne.gs # Main sync logic
│ ├── BatchRequests.gs # Batch API handler
│ ├── Config.gs # Your private config (git-ignored)
│ ├── Config.gs.example # Config template (safe to commit)
│ ├── appsscript.json # Project manifest
│ └── .clasp.json # Clasp configuration (git-ignored)
├── docs/ # Documentation
│ ├── setup-ui-based.md # UI setup guide
│ ├── setup-cli-based.md # This file
│ └── updating-deployments.md # Deployment guide
├── .gitignore # Git exclusions
├── .nvmrc # Node.js version
├── package.json # npm dependencies & scripts
├── package-lock.json # Locked dependency versions
└── README.md # Project overview
SyncCalendarsIntoOne.gs- Contains all sync logic (fetching, comparing, updating events)BatchRequests.gs- Helper class for efficient batch API requestsConfig.gs- Your calendar IDs and settings (keep private!)appsscript.json- Manifest that configures OAuth scopes and enabled services
You're all set up for local development! Here's what you can do next:
Edit scripts/SyncCalendarsIntoOne.gs to:
- Change what event data gets synced
- Add custom filtering (e.g., skip events with certain keywords)
- Modify event title formatting
- Add new features
# View recent logs
npm run clasp:logs
# Open in browser to see execution history
npm run clasp:openIf you make improvements that others might benefit from:
- Fork the repository
- Create a feature branch
- Make your changes
- Submit a pull request
- General Setup: See UI Setup Guide
- Deployment Help: See Updating Deployments Guide
- Calendar API: Google Calendar API Docs
- Apps Script: Google Apps Script Docs
- clasp Documentation: GitHub - google/clasp
- Project Repository: GitHub
Happy vibe-coding! 🚀 You now have a full local development environment for managing your calendar sync script.