.claude/skills/ts-calendar-integration/SKILL.md
Integrate with Google Calendar and Microsoft Outlook Calendar for scheduling, event management, and availability tracking. Use when someone asks to "create calendar events", "check availability", "schedule meetings", "sync calendars", "Google Calendar API", "Outlook Calendar API", "booking system", "find free slots", or "manage recurring events". Covers Google Calendar API v3, Microsoft Graph Calendar API, event CRUD, availability/free-busy queries, recurring events, and building scheduling features.
npx skillsauth add eliferjunior/Claude calendar-integrationInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This skill helps AI agents integrate with Google Calendar and Microsoft Outlook Calendar. It covers authentication, event CRUD, recurring events, availability/free-busy queries, webhook notifications, and building scheduling features like booking pages and meeting coordinators.
import { google } from 'googleapis';
// OAuth 2.0 (user context)
const oauth2Client = new google.auth.OAuth2(
process.env.GOOGLE_CLIENT_ID,
process.env.GOOGLE_CLIENT_SECRET,
process.env.GOOGLE_REDIRECT_URI
);
const authUrl = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: ['https://www.googleapis.com/auth/calendar'],
});
const { tokens } = await oauth2Client.getToken(authorizationCode);
oauth2Client.setCredentials(tokens);
const calendar = google.calendar({ version: 'v3', auth: oauth2Client });
// Service Account (server-to-server, domain-wide delegation)
const auth = new google.auth.GoogleAuth({
keyFile: '/path/to/service-account-key.json',
scopes: ['https://www.googleapis.com/auth/calendar'],
clientOptions: { subject: '[email protected]' },
});
// Timed event with attendees and Meet link
const event = await calendar.events.insert({
calendarId: 'primary',
requestBody: {
summary: 'Sprint Planning',
description: 'Plan sprint 14 tasks and capacity.',
start: { dateTime: '2026-03-01T14:00:00', timeZone: 'America/New_York' },
end: { dateTime: '2026-03-01T15:00:00', timeZone: 'America/New_York' },
attendees: [{ email: '[email protected]' }, { email: '[email protected]' }],
conferenceData: {
createRequest: { requestId: 'req-' + Date.now(), conferenceSolutionKey: { type: 'hangoutsMeet' } },
},
},
conferenceDataVersion: 1,
sendUpdates: 'all',
});
// Recurring event
await calendar.events.insert({
calendarId: 'primary',
requestBody: {
summary: 'Daily Standup',
start: { dateTime: '2026-03-01T09:30:00', timeZone: 'America/New_York' },
end: { dateTime: '2026-03-01T09:45:00', timeZone: 'America/New_York' },
recurrence: ['RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR;UNTIL=20260630T000000Z'],
},
});
Daily: RRULE:FREQ=DAILY;COUNT=30
Weekly: RRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR
Biweekly: RRULE:FREQ=WEEKLY;INTERVAL=2;BYDAY=TU
Monthly (date): RRULE:FREQ=MONTHLY;BYMONTHDAY=1
Monthly (day): RRULE:FREQ=MONTHLY;BYDAY=2TU
With end date: RRULE:FREQ=WEEKLY;BYDAY=MO;UNTIL=20261231T000000Z
// List upcoming events (next 7 days)
const { data } = await calendar.events.list({
calendarId: 'primary',
timeMin: new Date().toISOString(),
timeMax: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(),
singleEvents: true, orderBy: 'startTime', maxResults: 50,
});
// Update event
await calendar.events.patch({
calendarId: 'primary', eventId,
requestBody: { summary: 'Sprint Planning (MOVED)', start: { dateTime: '2026-03-02T14:00:00', timeZone: 'America/New_York' }, end: { dateTime: '2026-03-02T15:00:00', timeZone: 'America/New_York' } },
sendUpdates: 'all',
});
// Delete event
await calendar.events.delete({ calendarId: 'primary', eventId, sendUpdates: 'all' });
const { data } = await calendar.freebusy.query({
requestBody: {
timeMin: '2026-03-01T09:00:00-05:00',
timeMax: '2026-03-01T18:00:00-05:00',
timeZone: 'America/New_York',
items: [{ id: '[email protected]' }, { id: '[email protected]' }],
},
});
// data.calendars['[email protected]'].busy → array of { start, end } blocks
import { ClientSecretCredential } from '@azure/identity';
import { Client } from '@microsoft/microsoft-graph-client';
import { TokenCredentialAuthenticationProvider } from '@microsoft/microsoft-graph-client/authProviders/azureTokenCredentials';
const credential = new ClientSecretCredential(
process.env.AZURE_TENANT_ID, process.env.AZURE_CLIENT_ID, process.env.AZURE_CLIENT_SECRET
);
const authProvider = new TokenCredentialAuthenticationProvider(credential, {
scopes: ['https://graph.microsoft.com/.default'],
});
const graphClient = Client.initWithMiddleware({ authProvider });
// Create event with Teams meeting
const event = await graphClient.api(`/users/${userId}/events`).post({
subject: 'Sprint Planning',
start: { dateTime: '2026-03-01T14:00:00', timeZone: 'America/New_York' },
end: { dateTime: '2026-03-01T15:00:00', timeZone: 'America/New_York' },
attendees: [
{ emailAddress: { address: '[email protected]' }, type: 'required' },
],
isOnlineMeeting: true,
onlineMeetingProvider: 'teamsForBusiness',
});
// List events in date range
const events = await graphClient.api(`/users/${userId}/calendarView`)
.query({ startDateTime: '2026-03-01T00:00:00Z', endDateTime: '2026-03-07T23:59:59Z' })
.select('subject,start,end,location,isOnlineMeeting')
.orderby('start/dateTime').top(50).get();
// Find meeting times (smart scheduling)
const suggestions = await graphClient.api(`/users/${userId}/findMeetingTimes`).post({
attendees: [
{ emailAddress: { address: '[email protected]' }, type: 'required' },
],
timeConstraint: { timeslots: [{
start: { dateTime: '2026-03-01T09:00:00', timeZone: 'America/New_York' },
end: { dateTime: '2026-03-05T18:00:00', timeZone: 'America/New_York' },
}] },
meetingDuration: 'PT1H',
maxCandidates: 5,
});
| Feature | Google Calendar | Outlook (Graph) | |---------|----------------|-----------------| | Auth | Google OAuth 2.0 | Azure AD OAuth 2.0 | | Video meeting | Google Meet | Teams (isOnlineMeeting) | | Free/busy | freebusy.query | getSchedule / findMeetingTimes | | Webhooks | Push notifications (7 day max) | Subscriptions (3 day max) | | Recurring | RRULE strings | Structured recurrence object | | Smart scheduling | Not built-in | findMeetingTimes (ranked) |
User prompt: "Find a 1-hour slot next week when Sarah, Mike, and Conference Room B are all free, then create a Sprint Planning meeting with a Google Meet link."
The agent will:
calendar.freebusy.query with all three calendar IDs for next week's business hourscalendar.events.insert including attendees, Meet link (conferenceDataVersion: 1), and send notifications to all attendeesUser prompt: "Create a daily standup meeting at 9:30 AM ET on weekdays in Microsoft Teams for our engineering team, running through June 2026."
The agent will:
graphClient.api('/users/{userId}/events').post() with isOnlineMeeting: true, onlineMeetingProvider: 'teamsForBusiness', and a weekly recurrence pattern for Monday-FridaystartDate: '2026-03-01' and endDate: '2026-06-30'timeZone — never rely on server timezone for calendar operationssingleEvents: true (Google) or calendarView (Outlook) to expand recurring eventssendUpdates: 'all') — silent changes cause confusiondevelopment
Expert guidance for Fireworks AI, the platform for running open-source LLMs (Llama, Mixtral, Qwen, etc.) with enterprise-grade speed and reliability. Helps developers integrate Fireworks' inference API, fine-tune models, and deploy custom model endpoints with function calling and structured output support.
development
Convert any website into clean, structured data with Firecrawl — API-first web scraping service. Use when someone asks to "turn a website into markdown", "scrape website for LLM", "Firecrawl", "extract website content as clean text", "crawl and convert to structured data", or "scrape website for RAG". Covers single-page scraping, full-site crawling, structured extraction, and LLM-ready output.
tools
Expert guidance for Firebase, Google's platform for building and scaling web and mobile applications. Helps developers set up authentication, Firestore/Realtime Database, Cloud Functions, hosting, storage, and analytics using Firebase's SDK and CLI.
development
When the user needs to build file upload functionality for a web application. Use when the user mentions "file upload," "image upload," "upload endpoint," "multipart upload," "presigned URL," "S3 upload," "file validation," "upload to cloud storage," or "accept user files." Handles upload endpoints, file validation (type, size, magic bytes), cloud storage integration, and upload status tracking. For image/video processing after upload, see media-transcoder.