Libra CodeHub

CedarCopilot/cedar-mail

Branch: staging

feat(calendar): support recurring invites via RRULE

merged#2764CedarCopilot

CedarCopilot wants to merge 2 commits into staging from feat/calendar-recurring-invites

Live on prod, no production signal yetTimeline and evidence
  1. Opened
    Sep 11, 2026, 3:34 PM
  2. Sep 12, 2026, 10:45 AM
  3. Merged
    Sep 12, 2026, 11:23 AM
  4. Live on prod
    Sep 12, 2026, 11:23 AM
  5. Observed 2 days, 9 surfaces, 4,919 requests
    Sep 12, 2026, 11:23 AM
  6. Pipelines steady after this deploy
    Sep 12, 2026, 11:23 AM
  7. Unobserved

    Live on prod, no production signal yet

    Sep 15, 2026, 10:31 AM

Behaviors Libra is checking

Users can create repeating Google Calendar invites by passing RFC 5545 RRULE strings through calendar modify-event.Degradedlow confidence

Strict CloudWatch fallback found 7 prod failure log lines for [processBufferedSlackWebhookEvents] Parked non-recoverable row (No valid connection tokens found for user <id>) in the last 24h while checking requestbody, proposedcalendareventrenderer, calendartool.

prod, checked Sep 15, 2026, 10:09 AM
Interactive calendar proposals preserve recurrence rules through proposal creation and include them when the user approves the card.Degradedlow confidence

Verification reached its 130s outer budget before the verifier returned. Libra is keeping this intent verifying until the next check.

prod, checked Sep 15, 2026, 10:31 AM
Create requests that omit recurrence continue to produce one-time calendar events without a recurrence field in the provider request.Degradedlow confidence

Strict CloudWatch fallback found 7 prod failure log lines for [processBufferedSlackWebhookEvents] Parked non-recoverable row (No valid connection tokens found for user <id>) in the last 24h while checking createcalendareventfromproposal, requestbody.

prod, checked Sep 15, 2026, 10:31 AM
Malformed recurrence input is rejected before any Google Calendar service call, including non-RRULE entries, rules without FREQ, or rules combining COUNT and UNTIL.Degradedlow confidence

Unable to verify the behavior from the available telemetry: no production spans named `calendar.modify-event` were found since deployment, and the broader calendar query only showed unrelated sync/list operations. Additional telemetry mapping is required before assigning a.

prod, checked Sep 15, 2026, 10:23 AM
Updates that do not change recurrence continue to target the specific expanded calendar instance supplied by the caller.Degradedlow confidence

Strict CloudWatch fallback found 6 prod failure log lines for [processBufferedSlackWebhookEvents] Parked non-recoverable row (No valid connection tokens found for user <id>) in the last 24h while checking eventid, proposedcalendareventrenderer, calendartool.

prod, checked Sep 15, 2026, 9:09 AM
Users can replace an event series' complete recurrence rule set or pass an empty recurrence array to turn the series into a one-time event.Degradedlow confidence

Strict CloudWatch fallback found 6 prod failure log lines for [processBufferedSlackWebhookEvents] Parked non-recoverable row (No valid connection tokens found for user <id>) in the last 24h while checking proposedcalendareventrenderer, calendartool, modifycalendareventtool.

prod, checked Sep 15, 2026, 10:27 AM

Libra measured 5 of 9 production surfaces on prod. 2 surfaces had under 20 requests, so Libra has not judged them; 2 surfaces had no requests at all. Libra has 6 low-confidence degraded verdicts it is still confirming. Libra checks hourly for 3 days after each deploy.

Summary

  • Adds a recurrence field (array of RFC 5545 RRULE strings, e.g. ["RRULE:FREQ=WEEKLY;BYDAY=MO;COUNT=8"]) to the agent-facing modify-calendar-event tool's create/update operations, so an agent can say "set up a weekly sync every Monday for 8 weeks" and get a real repeating invite.
  • Threaded through createCalendarEventFromProposal (the autonomous-surface create path) and the consolidated calendar family tool used by external MCP.
  • The in-app approval card now shows a "Repeats ยท Weekly on Mon, ..." row (reusing the existing parseRecurrenceLabel util from the human-driven calendar UI) and forwards recurrence on both its live apply path and its legacy direct-tRPC fallback.
  • Setting recurrence on an existing event now correctly requires organizer permission (canModifyForEveryone), same as any other shared-field edit.
  • calendar skill docs updated with RRULE patterns and the "update replaces the whole rule set" gotcha.

The Google Calendar API plumbing (driver + tRPC route the manual calendar UI already uses) already accepted recurrence untouched , the gap was purely that the agent-facing tool layer had no way to ask for a repeating event.

Test plan

  • pnpm --filter @zero/server exec vitest run on the touched calendar test files , 60/60 passing
  • pnpm --filter @zero/server run types , clean
  • pnpm --filter @zero/mail run types , clean
  • pnpm deps:check , 0 dependency-direction violations
  • Passed a thermo-review pass (no blocking/should-fix findings)

๐Ÿค– Generated with Claude Code

https://claude.ai/code/session_01Vf2i8VJzcyXMh1MF6FiCG6

Greptile Summary

This PR adds agent-controlled RFC 5545 recurrence to calendar creation and updates, carries it through autonomous, approval, legacy tRPC, family-tool, and external MCP paths, displays recurrence on the approval card, and documents common rule patterns.

  • Recurrence propagation is aligned across the leaf and consolidated calendar tools.
  • Interactive and autonomous create/update paths now send recurrence to the calendar provider.
  • Existing-series updates still lack the recurring master identity needed to perform the documented series-level change.
  • Approval rendering can conceal additional recurrence entries that are nevertheless applied.
  • Agent-supplied recurrence strings are not validated before approval or provider execution.

Confidence Score: 3/5

This PR is not yet safe to merge because recurrence updates for discovered recurring events cannot address the series master, and approval cards may omit recurrence entries that will be applied.

The create and propagation paths are generally aligned, but two blocking behavioral gaps remain: list results discard the master event identity required by whole-series recurrence replacement, and approval rendering shows only the first rule while applying the entire array. Boundary validation and the explicit no-cast repository requirement also need attention.

Files Needing Attention: apps/server/src/mastra/tools/calendar/modifyCalendarEventTool.ts, apps/mail/modules/cedar-os/src/store/messages/renderers/ProposedCalendarEventRenderer.tsx, apps/server/src/mastra/tools/calendar/tests/modifyCalendarEventTool.test.ts

Important Files Changed

FilenameOverview
apps/server/src/mastra/tools/calendar/modifyCalendarEventTool.tsAdds recurrence schemas, permission handling, proposal propagation, and provider writes, but existing-series rule changes cannot target the recurring master and inputs lack RRULE validation.
apps/mail/modules/cedar-os/src/store/messages/renderers/ProposedCalendarEventRenderer.tsxDisplays and applies recurrence on approval cards, but its label represents only the first entry while the complete array is applied.
apps/server/src/mastra/tools/calendar/calendarTool.tsCorrectly forwards recurrence through the cons
Show production surfaces and changed-file mapping

Production surfaces

SurfaceRequestsErrorsp95UsersVerdict
process_calendar_event_sync_only2095 โ†’ 43390 โ†’ 0 (0%)88 ms โ†’ 89 ms33Working
4,339 requests since the deploy with 0 errors (0 errors in the 2,095-request baseline before it). p95 89 ms, was 88 ms.
/a8n/notify/google-calendar136 โ†’ 3660 โ†’ 0 (0%)61 ms โ†’ 62 ms0Working
366 requests since the deploy with 0 errors (0 errors in the 136-request baseline before it). p95 62 ms, was 61 ms.
POST /a8n/notify/google-calendar4 โ†’ 1220 โ†’ 0 (0%)52 ms โ†’ 62 ms0Working
122 requests since the deploy with 0 errors (0 errors in the 4-request baseline before it). p95 62 ms, was 52 ms.
calendar.events.list.incremental16 โ†’ 480 โ†’ 0 (0%)1554 ms โ†’ 789 ms0Working
48 requests since the deploy with 0 errors (0 errors in the 16-request baseline before it). p95 789 ms, was 1554 ms.
calendar_sync31 โ†’ 360 โ†’ 0 (0%)8098 ms โ†’ 8798 ms25Working
36 requests since the deploy with 0 errors (0 errors in the 31-request baseline before it). p95 8798 ms, was 8098 ms.
/api/trpc/calendar.listEvents0 โ†’ 60 โ†’ 0 (0%)not measured โ†’ 196 ms0Insufficient traffic
6 requests, under the 20 Libra needs
calendar.events.get6 โ†’ 20 โ†’ 0 (0%)283 ms โ†’ 268 ms0Insufficient traffic
2 requests, under the 20 Libra needs
/api/trpc/calendar.listCalendars3 โ†’ 00 โ†’ 0 (0%)284 ms โ†’ not measured0No traffic
No requests recorded since this deploy.
/api/trpc/crm.loadCalendarConversationsBatch0 โ†’ 00 โ†’ 0 (0%)not measured0No traffic
No requests recorded since this deploy.

Changed files โ†’ surfaces

  • apps/server/src/mastra/tools/calendar/calendarTool.tsprocess_calendar_event_sync_only/a8n/notify/google-calendarPOST /a8n/notify/google-calendarcalendar.events.list.incrementalcalendar_sync/api/trpc/calendar.listEvents+3
  • apps/mail/modules/cedar-os/src/store/messages/renderers/ProposedCalendarEventRenderer.tsxno production surface mapped
  • apps/server/.claude/skills/calendar/SKILL.mdno production surface mapped
  • apps/server/src/mastra/tools/calendar/__tests__/calendarTool.test.tsno production surface mapped
  • apps/server/src/mastra/tools/calendar/__tests__/modifyCalendarEventTool.test.tsno production surface mapped
  • apps/server/src/mastra/tools/calendar/modifyCalendarEventTool.tsno production surface mapped
  • apps/server/src/services/calendar/__tests__/create-calendar-event-from-proposal.test.tsno production surface mapped
  • apps/server/src/services/calendar/create-calendar-event-from-proposal.tsno production surface mapped