meetings
Meetings Skill
Coordinate meetings seamlessly using calendar and email integration. Schedule meetings, find mutual availability, manage agendas, and send invites all from your agent.
Features
- Schedule Meetings: Find available time slots and create meetings
- Email Invites: Automatically send meeting invitations
- Agenda Management: Structured agendas with time allocations
- Prep Documents: Attach and share pre-meeting materials
- Meeting Templates: Pre-defined templates for common meeting types
- Calendar Integration: Syncs with Google Calendar
Installation
npm install
npm run build
Prerequisites
The meetings skill requires both calendar and email to be connected:
# Connect Google account with Calendar and Gmail scopes
node ../google-oauth/dist/cli.js connect default calendar email
CLI Usage
Check Status
# Check connection status
node dist/cli.js status
Health Check
node dist/cli.js health
Schedule a Meeting
# Basic meeting
node dist/cli.js schedule --title "Team Sync" --attendees "alice@example.com,bob@example.com"
# With all options
node dist/cli.js schedule \
--title "Project Review" \
--attendees "alice@example.com,bob@example.com,carol@example.com" \
--duration 90 \
--description "Quarterly project review" \
--location "Conference Room A" \
--days 14 \
--prep
# With agenda items
node dist/cli.js schedule \
--title "Sprint Planning" \
--attendees "dev-team@example.com" \
--duration 120 \
--agenda-0 "Review previous sprint" --agenda-0-duration 20 \
--agenda-1 "Story estimation" --agenda-1-duration 60 \
--agenda-2 "Sprint commitment" --agenda-2-duration 20 \
--prep
Quick Schedule
# Quick 30-minute meeting (minimal options)
node dist/cli.js quick --title "Quick Sync" --attendees "bob@example.com"
# With duration
node dist/cli.js quick --title "Code Review" --attendees "dev@example.com" --duration 60
Use a Template
# List available templates
node dist/cli.js templates
# Schedule from template
node dist/cli.js template "Standup" --attendees "team@example.com"
# With custom title
node dist/cli.js template "1-on-1" --title "1-on-1 with Alice" --attendees "alice@example.com"
List Meetings
# List upcoming meetings
node dist/cli.js list
# List more meetings
node dist/cli.js list --days 30 --limit 50
# Filter by status
node dist/cli.js list --status scheduled
Get Meeting Details
node dist/cli.js get meeting_abc123
Cancel a Meeting
# Cancel and notify attendees
node dist/cli.js cancel meeting_abc123
# Cancel without notifications
node dist/cli.js cancel meeting_abc123 --no-notify
Delete a Meeting
node dist/cli.js delete meeting_abc123
Find Available Time
# Find 60-minute slots in next 7 days
node dist/cli.js free
# Find 30-minute slots in next 3 days
node dist/cli.js free --duration 30 --days 3
Send Invites
# Re-send invites for a meeting
node dist/cli.js invite meeting_abc123
Send Prep Email
# Send agenda and prep materials
node dist/cli.js prep meeting_abc123
JavaScript/TypeScript API
Initialize
import { MeetingsSkill } from '@openclaw/meetings';
// Create skill for default profile
const meetings = new MeetingsSkill();
// Or for specific profile
const workMeetings = MeetingsSkill.forProfile('work');
Check Status
const status = await meetings.getStatus();
console.log('Connected:', status.connected);
console.log('Calendar:', status.calendarConnected);
console.log('Email:', status.emailConnected);
Schedule a Meeting
const result = await meetings.schedule({
title: 'Team Standup',
description: 'Daily team sync',
duration: 30,
attendees: ['alice@example.com', 'bob@example.com'],
timeMin: new Date().toISOString(),
timeMax: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(),
location: 'Conference Room A',
agenda: [
{ title: 'What did you do yesterday?', duration: 10 },
{ title: 'What will you do today?', duration: 10 },
{ title: 'Any blockers?', duration: 10 },
],
sendInvites: true,
sendPrepEmail: true,
});
if (result.success) {
console.log('Meeting scheduled:', result.meeting?.id);
console.log('Time:', result.meeting?.startTime);
} else {
console.error('Failed:', result.error);
}
Schedule from Template
const result = await meetings.scheduleFromTemplate('Standup', {
title: 'Daily Standup',
attendees: ['team@example.com'],
timeMin: new Date().toISOString(),
timeMax: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(),
sendInvites: true,
});
Find Availability
const availability = await meetings.findAvailability({
attendees: ['alice@example.com', 'bob@example.com'],
duration: 60,
timeMin: new Date().toISOString(),
timeMax: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(),
});
for (const slot of availability.availableSlots) {
console.log(`Available: ${slot.start} - ${slot.end}`);
}
List Meetings
const meetingList = await meetings.listMeetings({
status: 'scheduled',
from: new Date().toISOString(),
to: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString(),
limit: 50,
});
for (const meeting of meetingList) {
console.log(`${meeting.title}: ${meeting.startTime}`);
}
Get Meeting Details
const meeting = await meetings.getMeeting('meeting_abc123');
console.log('Title:', meeting?.title);
console.log('Attendees:', meeting?.attendees.map(a => a.email));
console.log('Agenda:', meeting?.agenda.map(item => item.title));
Update a Meeting
const updated = await meetings.updateMeeting('meeting_abc123', {
title: 'Updated Title',
startTime: new Date(Date.now() + 2 * 60 * 60 * 1000).toISOString(),
endTime: new Date(Date.now() + 3 * 60 * 60 * 1000).toISOString(),
});
Cancel a Meeting
// Cancel and notify attendees
await meetings.cancelMeeting('meeting_abc123', true);
// Cancel without notifications
await meetings.cancelMeeting('meeting_abc123', false);
Send Invites
const meeting = await meetings.getMeeting('meeting_abc123');
if (meeting) {
await meetings.sendMeetingInvite(meeting);
}
Send Prep Email
const meeting = await meetings.getMeeting('meeting_abc123');
if (meeting) {
await meetings.sendPrepEmail(meeting);
}
Meeting Templates
Default Templates
The meetings skill includes several pre-defined templates:
Standup
- Duration: 15 minutes
- Agenda: Yesterday's work, Today's plan, Blockers
Sprint Planning
- Duration: 2 hours
- Agenda: Review, Goal discussion, Estimation, Commitment
1-on-1
- Duration: 30 minutes
- Agenda: Updates, Priorities, Challenges, Career development
Retrospective
- Duration: 1 hour
- Agenda: What went well, Improvements, Action items
Review
- Duration: 1 hour
- Agenda: Status overview, Demo, Feedback
Create Custom Template
const template = await meetings.createTemplate({
name: 'Architecture Review',
title: 'Architecture Review: {topic}',
description: 'Review proposed architecture changes',
duration: 90,
agenda: [
{ id: '1', title: 'Problem statement', duration: 10 },
{ id: '2', title: 'Proposed solution', duration: 30 },
{ id: '3', title: 'Discussion', duration: 40 },
{ id: '4', title: 'Decision', duration: 10 },
],
prepDocuments: [
{ id: '1', name: 'Architecture Doc', type: 'link', required: true },
],
});
List Templates
const templates = await meetings.listTemplates();
for (const template of templates) {
console.log(`${template.name}: ${template.duration} min`);
}
Data Types
Meeting
interface Meeting {
id: string;
title: string;
description?: string;
startTime: string; // ISO datetime
endTime: string; // ISO datetime
timeZone: string;
location?: string;
videoLink?: string;
attendees: MeetingAttendee[];
agenda: AgendaItem[];
prepDocuments: PrepDocument[];
calendarEventId?: string;
status: 'draft' | 'scheduled' | 'cancelled' | 'completed';
notes?: string;
createdAt: string;
updatedAt: string;
}
MeetingAttendee
interface MeetingAttendee {
email: string;
name?: string;
optional?: boolean;
responseStatus?: 'needsAction' | 'declined' | 'tentative' | 'accepted';
}
AgendaItem
interface AgendaItem {
id: string;
title: string;
duration: number; // in minutes
presenter?: string;
description?: string;
}
PrepDocument
interface PrepDocument {
id: string;
name: string;
url?: string;
content?: string;
type: 'link' | 'file' | 'note';
required: boolean;
}
Storage
Meeting data is stored in:
~/.openclaw/skills/meetings/meetings.db
Tables:
meetings- Meeting recordstemplates- Meeting templates
Multi-Profile Support
Manage meetings for different accounts:
import { MeetingsSkill } from '@openclaw/meetings';
// Work account
const work = MeetingsSkill.forProfile('work');
// Personal account
const personal = MeetingsSkill.forProfile('personal');
// Schedule independently
await work.schedule({ /* work meeting */ });
await personal.schedule({ /* personal meeting */ });
Each profile needs separate authentication:
node ../google-oauth/dist/cli.js connect work calendar email
node ../google-oauth/dist/cli.js connect personal calendar email
Error Handling
try {
const result = await meetings.schedule({
title: 'Team Meeting',
duration: 60,
attendees: ['team@example.com'],
timeMin: new Date().toISOString(),
timeMax: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(),
});
if (!result.success) {
console.log('Could not schedule:', result.error);
console.log('Alternative slots:', result.suggestedSlots);
}
} catch (error) {
console.error('Error:', error.message);
}
Testing
# Type checking
npm run typecheck
# Build
npm run build
# Check status
npm run status
# List templates
npm run cli -- templates
# Schedule a meeting
npm run cli -- quick --title "Test Meeting" --attendees "you@example.com"
# List meetings
npm run cli -- list --days 30
Troubleshooting
"Not connected" error
Authenticate with google-oauth first:
node ../google-oauth/dist/cli.js connect default calendar email
Calendar or email not working
Check health of dependencies:
node ../calendar/dist/cli.js health
node ../email/dist/cli.js health
No available slots found
Expand your search window:
node dist/cli.js schedule --title "Meeting" --attendees "email@example.com" --days 14
Dependencies
@openclaw/calendar: Calendar integration@openclaw/email: Email integration@openclaw/google-oauth: Authentication (via calendar/email)@openclaw/auth-provider: Base authenticationsqlite3: Local storage
Security Notes
- OAuth tokens stored encrypted by auth-provider
- Meeting database has 0600 permissions
- Email communications use Gmail API
- Calendar events use Google Calendar API
More from ticruz38/skills
binance-auth
Binance API authentication and key management for trading skills. Securely stores API keys, validates permissions, supports testnet vs production environments, and provides health checks with balance queries.
45reminders
Local reminder system with natural language scheduling
29auth-provider
Centralized authentication provider for OAuth 2.0 and API key management. Supports Google, Binance, QuickBooks, and Slack. Provides encrypted SQLite storage, auto-refresh, PKCE flow, and health checks.
6slack
Send messages and notifications to Slack channels. Built on top of slack-auth for authentication, supports messaging, file uploads, channel management, DM sending, and notification templates with variable substitution.
3email
Gmail integration for reading, sending, and managing emails. Built on top of google-oauth for authentication, with SQLite caching, thread support, and full Gmail API capabilities.
3calendar
Google Calendar integration for events and availability. Built on top of google-oauth for authentication, with SQLite caching, free/busy queries, and full Calendar API capabilities.
3