realvco Docs

Calendar Voice Reminders

In a busy week, it’s easy to forget a meeting. Let Rose watch your calendar and speak to you before important moments — like having a thoughtful assistant sitting next to you.


Scenario

Where This Fits

ScenarioTriggerDelivery
Customer meeting15 minutes beforeVoice + text
Team meeting10 minutes beforeVoice
Major deadline1 day outVoice + details
Business travel2 hours before departureVoice + weather
Daily check-inFixed daily timeShort voice

Expected Results

  • No more missed meetings — early, with time to prep
  • Voice stands out — harder to ignore than a text notification
  • Works on the go — listen in the car
  • Layered alerts — one day, one hour, fifteen minutes

Calendar Integration

Supported Sources

SourceMethodDifficulty
Google CalendarGoogle APIMedium
Microsoft OutlookMicrosoft Graph APIMedium
CalDAVStandard protocolHigh
Local calendar filesRead .ics filesLow

Google Calendar Setup

{`1. Open Google Cloud Console
   https://console.cloud.google.com/

2. Create or pick a project

3. Enable the Google Calendar API
   - APIs and Services → Library
   - Search "Google Calendar API"
   - Click Enable

4. Create credentials
   - APIs and Services → Credentials
   - Create credentials → OAuth 2.0 Client ID
   - Application type: Desktop app
   - Download the JSON file

5. Store the file at:
   ~/.config/realvco/google-credentials.json`}

Calendar Sync Script

{`// Calendar sync

const { google } = require('googleapis');
const fs = require('fs');

async function getUpcomingEvents() {
  const credentials = JSON.parse(
    fs.readFileSync(process.env.GOOGLE_CREDENTIALS_PATH)
  );

  const { client_secret, client_id, redirect_uris } = credentials.installed;
  const oAuth2Client = new google.auth.OAuth2(
    client_id, client_secret, redirect_uris[0]
  );

  oAuth2Client.setCredentials({
    access_token: process.env.GOOGLE_ACCESS_TOKEN,
    refresh_token: process.env.GOOGLE_REFRESH_TOKEN
  });

  const calendar = google.calendar({ version: 'v3', auth: oAuth2Client });

  const now = new Date();
  const tomorrow = new Date(now);
  tomorrow.setDate(tomorrow.getDate() + 1);

  const response = await calendar.events.list({
    calendarId: 'primary',
    timeMin: now.toISOString(),
    timeMax: tomorrow.toISOString(),
    singleEvents: true,
    orderBy: 'startTime'
  });

  return response.data.items;
}

module.exports = { getUpcomingEvents };`}

Voice Reminder Configuration

Reminder Flow

┌──────────────┐     ┌──────────────┐     ┌──────────────┐
│ Check calendar│ → │ Decide timing │ → │ Compose voice │
├──────────────┤     ├──────────────┤     ├──────────────┤
│ Every 5 min  │     │ • 15 min out │     │ • Meeting    │
│ Read events  │     │ • 1 hour out │     │ • Start time │
│              │     │ • 1 day out  │     │ • Location   │
└──────────────┘     └──────────────┘     └──────┬───────┘


                                           ┌──────────────┐
                                           │   Deliver    │
                                           ├──────────────┤
                                           │ • Text       │
                                           │ • Voice      │
                                           │ • Push       │
                                           └──────────────┘

Templates

{`# 15-Minute Reminder

⏰ Meeting starts in 15 minutes

"Hey, your meeting starts in 15 minutes.
Meeting: {meeting_title}
Time: {start_time}
Location: {location}

Ready?"

---

# 1-Hour Reminder

📅 Meeting reminder

"In 1 hour you have a meeting.
{meeting_title}, starting at {start_time}.
{description}

Don't forget the prep materials."

---

# Morning Briefing

📋 Today's schedule

"Good morning. You have {count} items today:

{for each event}
- {time}: {title}
{/for}

Have a good one."`}

Voice Delivery Settings

{`# Voice reminder configuration

tts:
  provider: elevenlabs   # or google, azure
  voice_id: nova
  language: en

reminders:
  - name: meeting_15min
    trigger: "event.start - 15 minutes"
    message_template: "meeting_15min"
    channels:
      - telegram_voice
      - telegram_text

  - name: meeting_1hour
    trigger: "event.start - 1 hour"
    message_template: "meeting_1hour"
    channels:
      - telegram_text

  - name: daily_briefing
    trigger: "08:00 daily"
    message_template: "daily_morning"
    channels:
      - telegram_voice

  - name: deadline_alert
    trigger: "deadline - 1 day"
    message_template: "deadline_reminder"
    channels:
      - telegram_voice
      - telegram_text`}

Scheduling

Heartbeat Checks

{`// Heartbeat reminder check

const { getUpcomingEvents } = require('./calendar-sync');
const { sendVoiceMessage } = require('./telegram-bot');
const { generateTTS } = require('./tts-service');

async function checkReminders() {
  const now = new Date();
  const events = await getUpcomingEvents();

  for (const event of events) {
    const startTime = new Date(event.start.dateTime);
    const diffMinutes = (startTime - now) / (1000 * 60);

    if (diffMinutes > 14 && diffMinutes < 15) {
      await sendMeetingReminder(event, '15min');
    }

    if (diffMinutes > 59 && diffMinutes < 60) {
      await sendMeetingReminder(event, '1hour');
    }
  }
}

async function sendMeetingReminder(event, timing) {
  const templates = {
    '15min': \`Hey, your meeting starts in 15 minutes. Meeting: \${event.summary}. Time: \${formatTime(event.start.dateTime)}.\`,
    '1hour': \`In 1 hour you have a meeting. \${event.summary}, starting at \${formatTime(event.start.dateTime)}.\`
  };

  const message = templates[timing];

  const voiceBuffer = await generateTTS(message);

  await sendVoiceMessage({
    chat_id: process.env.ADMIN_CHAT_ID,
    voice: voiceBuffer,
    caption: message
  });

  console.log(\`✅ Sent \${timing} reminder: \${event.summary}\`);
}

// Check every 5 minutes
setInterval(checkReminders, 5 * 60 * 1000);

module.exports = { checkReminders };`}

Cron Schedule

{`# Send today's agenda at 8 AM
0 8 * * * cd /home/node/.openclaw/workspace && node scripts/daily-briefing.js

# Check upcoming meetings every 5 minutes
*/5 * * * * cd /home/node/.openclaw/workspace && node scripts/check-reminders.js

# Preview tomorrow's schedule at 9 PM
0 21 * * * cd /home/node/.openclaw/workspace && node scripts/tomorrow-preview.js`}

Advanced

Smart Reminders

{`# Context-aware reminders

## Travel
"Heads up — your airport departure is in 2 hours.
Flight: {flight_number}
Destination: {destination}
Local weather: {weather}

Passport and chargers are packed?"

## Customer meeting prep
"In 30 minutes you meet with {client_name}.

Last conversation summary:
{last_conversation_summary}

Open items:
{pending_items}

Relevant documents:
{relevant_documents}"`}

Layered Reminders

Important meeting (marked as high priority):
├── 1 day out: detailed prep reminder + relevant docs
├── 1 hour out: departure reminder + transit info
├── 15 min out: get-ready reminder
└── 1 min out: final check

Regular meeting:
└── 15 min out: standard reminder

Deadlines:
├── 3 days out: early-prep reminder
├── 1 day out: due-tomorrow reminder
└── Morning of: due-today reminder

Integrations

{`# Weather API
For offsite meetings, append:
"Rain tomorrow in San Francisco — bring an umbrella."

# Transit API
For external meetings, suggest:
"Estimated 30-minute drive — suggest leaving at 2:30."

# CRM
Before a customer meeting:
"This is your third meeting with XX Corp.
Last time you discussed {previous_topic}.
Today's focus is {meeting_goal}."`}

FAQ

The Voice Is Hard to Hear

  1. Pick a clearer voice model
  2. Adjust speech rate (0.9–1.1x works best)
  3. Send a text backup alongside
  4. Test in both quiet and noisy environments

Can I Change the Reminder Timing?

Yes — edit the config:

reminders:
  - trigger: "event.start - 30 minutes"  # now 30 minutes before

How Do I Skip a Reminder?

Tag the calendar event:

  • #no-reminder: skip entirely
  • #silent: text only, no voice

Which Voice Providers Are Supported?

Currently:

  • ElevenLabs (highest quality)
  • Google Cloud Text-to-Speech
  • Azure Cognitive Services
  • System TTS (free, lower quality)

Summary

Calendar voice reminders keep important moments from slipping:

  • Connect the calendar — Google / Outlook auto-sync
  • Layered alerts — one day, one hour, fifteen minutes
  • Voice notifications — louder than text, usable hands-free
  • Smarter with context — weather, transit, CRM all inline