Skip to content

Google Workspace

Bridges four Google services to the Workstacean bus: Gmail (inbound polling), Calendar (inbound polling), Drive (outbound operations), and Docs (outbound operations).

The plugin is disabled entirely if any of GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, or GOOGLE_REFRESH_TOKEN are missing. All three must be set.

workspace/google.yaml is hot-reloaded — changes apply without restarting the container. Polling intervals and label lists are restarted automatically when they change.

ServiceDirectionWhat it does
GmailInbound (polling)Watches configured labels; publishes unread messages to the bus
CalendarInbound (polling)Fetches upcoming events in the next 7 days; publishes to the bus
DriveOutbound (subscription)Handles file create, update, and append operations
DocsOutbound (subscription)Handles document create and text-insert operations
drive:
orgFolderId: "" # Google Drive folder ID for the org root (shared across projects)
templateFolderId: "" # Per-project folder template (optional)
calendar:
orgCalendarId: "" # Calendar ID for the shared org calendar
pollIntervalMinutes: 60 # How often to poll for upcoming events (default: 60)
gmail:
watchLabels: [] # Gmail labels to watch for inbound messages
pollIntervalMinutes: 5 # How often to poll each label (default: 5)
routingRules: [] # Label → skillHint mappings
# Example:
# - label: "bug-report"
# skillHint: bug_triage
# - label: "gtm-request"
# skillHint: content_strategy
FieldTypeDefaultDescription
drive.orgFolderIdstring""Root org Drive folder ID. Required for Drive operations.
drive.templateFolderIdstring""Template folder for new project folders (optional).
calendar.orgCalendarIdstring""Google Calendar ID (e.g. user@example.com). Required for Calendar polling.
calendar.pollIntervalMinutesnumber60Polling interval for calendar events.
gmail.watchLabelsstring[][]Gmail label names to watch. Gmail polling is skipped if empty.
gmail.pollIntervalMinutesnumber5Polling interval per label.
gmail.routingRulesRoutingRule[][]Maps a label to a skillHint attached to the published bus message.
- label: "bug-report" # Gmail label name (case-insensitive)
skillHint: bug_triage # Skill hint attached to the published message payload

Per-project Google Workspace overrides can be added to each project entry in workspace/projects.yaml:

projects:
- slug: my-project
googleWorkspace:
driveFolderId: "1ABC123XYZ" # Project-specific Drive folder
sharedDocId: "1DEF456UVW" # Shared Google Doc for this project
calendarId: "team@example.com" # Project-specific calendar (overrides org default)
FieldTypeDescription
googleWorkspace.driveFolderIdstringProject Drive folder ID. Used by Cindi when creating project files.
googleWorkspace.sharedDocIdstringShared Google Doc ID. Used by Jon and Quinn for running notes.
googleWorkspace.calendarIdstringProject calendar ID. Overrides calendar.orgCalendarId for this project.
TopicTriggerPayload fields
message.inbound.google.gmailNew unread message found matching a watched labelmessageId, threadId, label, from, to, subject, date, body (≤4000 chars), skillHint (if routing rule matched)
message.inbound.google.calendarCalendar poll found upcoming eventsevents[] (id, title, description, start, end, attendees, link), window (from, to)

Outbound topics (subscribed by the plugin)

Section titled “Outbound topics (subscribed by the plugin)”

Publish to these topics to trigger Drive or Docs operations. Set reply.topic on your message to receive the result.

operationRequired fieldsOptional fieldsReturns
createname, mimeTypeparentId, contentfileId, name, webViewLink
updatefileId, contentfileId, name
appendfileId, contentfileId, name

Example:

{
"operation": "create",
"name": "Project Brief",
"mimeType": "text/plain",
"parentId": "1ABC123XYZ",
"content": "Initial content here"
}
operationRequired fieldsOptional fieldsReturns
createtitlecontentdocumentId, title, link
insertdocumentId, contentindex (default: 1)documentId, link
updatedocumentId, contentindex (default: 1)documentId, link

Example:

{
"operation": "create",
"title": "Sprint Retro — 2026-Q1",
"content": "## Summary\n\n..."
}
TopicWhenPayload
auth.token_refresh_failedAccess token refresh failed after 3 retries{ plugin: "google", reason: string }
config.updatedgoogle.yaml was hot-reloaded{ plugin: "google", config: "google.yaml" }

All three secrets must be injected at runtime (from Infisical, project 11e172e0-a1f6-41d5-9464-df72779a7063, env prod):

SecretInfisical keyDescription
OAuth2 client IDGOOGLE_CLIENT_IDCreated in Google Cloud Console → APIs & Services → Credentials
OAuth2 client secretGOOGLE_CLIENT_SECRETPaired with the client ID
OAuth2 refresh tokenGOOGLE_REFRESH_TOKENLong-lived token; exchanged for short-lived access tokens automatically

The plugin refreshes the access token automatically. Tokens are cached in memory with a 5-minute safety buffer. A background job proactively refreshes when fewer than 10 minutes remain.

AgentServices usedHow
JonDocsCreates and updates Google Docs for project artefacts
CindiDriveCreates per-project folders; uploads files to Drive
AvaCalendarReads upcoming events via message.inbound.google.calendar to signal deadlines
QuinnDocsReads and writes shared Docs for portfolio summaries and PR reviews