openclaw/skills/gws-calendar/SKILL.md
View, create, and manage Google Calendar events for Dylan, Julia, or other accounts. Use when asked about schedule, appointments, meetings, calendar, what's coming up, free time, conflicts, or availability.
npx skillsauth add Dbochman/dotfiles gws-calendarInstall 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.
Access Google Calendar via the gws CLI at /opt/homebrew/bin/gws. Credentials are AES-256-GCM encrypted at ~/.config/gws/.
Read references/gws-cli.md before selecting an account, changing authentication, or executing a write.
| Account | Owner | Service-command selection |
|---------|-------|---------------------------|
| ${DYLAN_EMAIL} | Dylan | GOOGLE_WORKSPACE_CLI_ACCOUNT=${DYLAN_EMAIL} |
| ${JULIA_EMAIL} | Julia | GOOGLE_WORKSPACE_CLI_ACCOUNT=${JULIA_EMAIL} |
| ${STARMARKET_GMAIL} | Dylan (spam) | GOOGLE_WORKSPACE_CLI_ACCOUNT=${STARMARKET_GMAIL} |
| ${OPENCLAW_EMAIL} | OpenClaw | GOOGLE_WORKSPACE_CLI_ACCOUNT=${OPENCLAW_EMAIL} |
When Dylan asks about "my calendar", use default. When he says "Julia's calendar", use her account.
All raw API commands follow: GOOGLE_WORKSPACE_CLI_ACCOUNT=<email> gws calendar <resource> <method> [--params '<JSON>'] [--json '<JSON>']
--params = URL/query parameters (calendarId, timeMin, maxResults, etc.)--json = request body (for create/update)gws calendar calendarList list
# Today's events
gws calendar events list --params '{
"calendarId": "primary",
"timeMin": "2026-03-05T00:00:00-05:00",
"timeMax": "2026-03-06T00:00:00-05:00",
"singleEvents": true,
"orderBy": "startTime"
}'
# Next 7 days
gws calendar events list --params '{
"calendarId": "primary",
"timeMin": "2026-03-05T00:00:00-05:00",
"timeMax": "2026-03-12T00:00:00-05:00",
"singleEvents": true,
"orderBy": "startTime"
}'
# Julia's events today
GOOGLE_WORKSPACE_CLI_ACCOUNT=${JULIA_EMAIL} gws calendar events list --params '{
"calendarId": "primary",
"timeMin": "2026-03-05T00:00:00-05:00",
"timeMax": "2026-03-06T00:00:00-05:00",
"singleEvents": true,
"orderBy": "startTime"
}'
# All calendars (use calendarList first, then query each)
gws calendar events list --params '{
"calendarId": "<calendarId>",
"timeMin": "...",
"timeMax": "...",
"singleEvents": true,
"orderBy": "startTime"
}'
Important: Always compute timeMin/timeMax as RFC3339 timestamps with timezone. Use America/New_York (-05:00 EST / -04:00 EDT).
gws calendar events get --params '{
"calendarId": "primary",
"eventId": "<eventId>"
}'
Use the q parameter:
gws calendar events list --params '{
"calendarId": "primary",
"q": "dinner",
"timeMin": "2026-03-01T00:00:00-05:00",
"timeMax": "2026-03-31T00:00:00-05:00",
"singleEvents": true,
"orderBy": "startTime"
}'
gws calendar events insert --params '{"calendarId": "primary"}' --json '{
"summary": "Team Standup",
"description": "Daily sync",
"location": "Zoom",
"start": {"dateTime": "2026-03-10T09:00:00-05:00", "timeZone": "America/New_York"},
"end": {"dateTime": "2026-03-10T09:30:00-05:00", "timeZone": "America/New_York"},
"attendees": [
{"email": "[email protected]"}
]
}'
gws calendar events insert --params '{"calendarId": "primary"}' --json '{
"summary": "Vacation",
"start": {"date": "2026-03-15"},
"end": {"date": "2026-03-16"}
}'
gws calendar events insert --params '{"calendarId": "primary"}' --json '{
"summary": "Weekly Standup",
"start": {"dateTime": "2026-03-10T09:00:00-05:00", "timeZone": "America/New_York"},
"end": {"dateTime": "2026-03-10T09:15:00-05:00", "timeZone": "America/New_York"},
"recurrence": ["RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR"]
}'
| Pattern | RRULE |
|---------|-------|
| Every Monday | RRULE:FREQ=WEEKLY;BYDAY=MO |
| Every weekday | RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR |
| Biweekly Tuesday | RRULE:FREQ=WEEKLY;INTERVAL=2;BYDAY=TU |
| Daily | RRULE:FREQ=DAILY |
| 1st of every month | RRULE:FREQ=MONTHLY;BYMONTHDAY=1 |
| First Friday of every month | RRULE:FREQ=MONTHLY;BYDAY=1FR |
| Weekly until end of year | RRULE:FREQ=WEEKLY;BYDAY=WE;UNTIL=20261231T235959Z |
gws calendar events insert --params '{"calendarId": "primary", "conferenceDataVersion": 1}' --json '{
"summary": "1:1 with Alice",
"start": {"dateTime": "2026-03-10T14:00:00-05:00", "timeZone": "America/New_York"},
"end": {"dateTime": "2026-03-10T14:30:00-05:00", "timeZone": "America/New_York"},
"attendees": [{"email": "[email protected]"}],
"conferenceData": {
"createRequest": {"requestId": "meet-1", "conferenceSolutionKey": {"type": "hangoutsMeet"}}
}
}'
gws calendar events patch --params '{
"calendarId": "primary",
"eventId": "<eventId>"
}' --json '{
"summary": "New Title",
"start": {"dateTime": "2026-03-10T10:00:00-05:00", "timeZone": "America/New_York"},
"end": {"dateTime": "2026-03-10T10:30:00-05:00", "timeZone": "America/New_York"}
}'
Use patch (not update) to only change specified fields.
gws calendar events delete --params '{
"calendarId": "primary",
"eventId": "<eventId>"
}'
gws calendar freebusy query --json '{
"timeMin": "2026-03-10T00:00:00-05:00",
"timeMax": "2026-03-10T23:59:59-05:00",
"items": [
{"id": "${DYLAN_EMAIL}"},
{"id": "${JULIA_EMAIL}"}
]
}'
First get the event, then patch the attendee status:
# Get the event to find your attendee entry
gws calendar events get --params '{"calendarId": "primary", "eventId": "<eventId>"}'
# Accept/decline by updating the event
gws calendar events patch --params '{
"calendarId": "primary",
"eventId": "<eventId>"
}' --json '{
"attendees": [{"email": "${DYLAN_EMAIL}", "responseStatus": "accepted"}]
}'
For any command, check available parameters:
gws schema calendar.events.list
gws schema calendar.events.insert
primary = default calendar for the account2026-03-10T09:00:00-05:00)singleEvents: true + orderBy: startTime when listing to expand recurring eventsrecurrence array with RRULE_ suffix) for single-instance changesgws outputs JSON by default — pipe through jq or parse directlytools
Use exact configured Reolink cameras through the local Home Hub for availability and power status, fresh stills, visual commentary, protected Dylan/Julia/household sharing, and reversible spotlight control. Supports trusted owner tasks and explicitly scoped proactive automations; not for Nest or Ring cameras, arbitrary recipients, recordings, account changes, or raw camera APIs.
data-ai
Privately manage Dylan and Julia's household plant inventory and care history by physical location, bed, and exact Flower Cam view. Use for confirmed plant onboarding from camera conversations, camera- or bed-filtered inventory, record corrections, individual or whole-bed care, and private filtered exports. Pair with reolink-camera when an owner asks about plants visible in Flower Cam images.
testing
Inspect and control the physically secured Reachy Mini at Crosstown through ClawBody. Use for requests to check Reachy, look around, express an emotion, play any official emotion or dance preset, speak proactively, mute or unmute its microphone, stop movement, or describe what its camera sees.
tools
Handle Reachy/iMessage handoffs, selective durable memory, forgetting, and diagnostics; automatic context comes from the gateway plugin.