DEV Community

Lay Patel
Lay Patel

Posted on AI-assisted

My Google Calendar connector got merged. Then the maintainer fixed 8 things in it

I filled a Google Calendar with test meetings for a made-up drone project, synced it into AI memory, and asked who leads the project, how long the battery lasts, and how much was spent on batteries.

Project Falcon is led by Meera Joshi, the battery lasts 55 minutes, and 12 lakh rupees were spent on batteries.

Then I deleted the Budget meeting, and deleted one occurrence of the daily sync with "This event". I synced again and asked the same question.

Project Falcon is led by Meera Joshi, the battery lasts 55 minutes, and the provided context does not mention how much was spent on batteries.

The money is gone, because it only lived in the deleted meeting. And deleting one occurrence didn't take the series with it. Asked what the daily sync covers, it still answered:

The daily sync covers the daily stand-up for Project Falcon, where the team tests drone navigation over the Pune test field

cognee is an open source memory layer for AI agents: it turns data into a knowledge graph you can query in plain language. This connector was my first merged PR of Mergetober. PR #370 went into cognee-community on October 15, four days after I opened it.

The same day, the maintainer moved it into the cognee SDK. It now ships with cognee itself, and the SDK file credits PR #370 at the top. That port is the best part of this story, so I'll come back to it.

What I want to use it for

My calendar has college and hackathon dates, and sometimes submission deadlines. So far I've only run this on the test meetings in this post, but on my own calendar I'd ask things like "what do I have coming up before my next hackathon?" or "how many days do I have left to finish this?" A calendar app shows me the days, but it can't answer that in one line.

Try it

  1. In the Google Cloud Console, create a free project and enable the Google Calendar API.
  2. Under Google Auth Platform, set up the consent screen as External, keep it in Testing, add your own account as a test user, and add only the calendar.readonly scope.
  3. Under Clients, create an OAuth client of type Desktop app and download its JSON.
  4. Install cognee with the Calendar extra and point it at that file:
pip install "cognee[google-calendar]"
export GOOGLE_CALENDAR_CREDENTIALS_PATH=~/client_secret.json
export GOOGLE_CALENDAR_TOKEN_PATH=~/.cognee_google_calendar_token.json
export LLM_API_KEY=<your key>
Enter fullscreen mode Exit fullscreen mode
  1. Run this. The first run opens a browser for consent, and later runs reuse the saved token:
import asyncio

import cognee
from cognee.tasks.ingestion.connectors import google_calendar_source


async def main():
    await cognee.remember(
        google_calendar_source(calendar_ids=["primary"]),
        dataset_name="my_calendar",
        primary_key="id",
        write_disposition="merge",  # makes re-runs incremental and lets deletes reach the graph
        max_rows_per_table=0,  # removes the default cap of 50 rows
    )

    answer = await cognee.recall("Who is in my Thursday meetings?", datasets=["my_calendar"])
    print(answer)


asyncio.run(main())
Enter fullscreen mode Exit fullscreen mode

Two things to know before you run it. The first run reads each calendar's whole history, because sync tokens don't allow a time window. And apps left in Testing get refresh tokens that expire after 7 days, so sign in again or publish the app for longer use.

What happened on a real calendar

My live test used the community package on a real Google account, with Gemini as the LLM and local fastembed for embeddings. The calendar had 3 test events and a daily sync repeating 3 times.

A Google Calendar week showing Project Falcon kickoff, Falcon daily sync on three days, Battery review and Budget meeting

Run What happened Sync stats
1 First sync: the 3 events, the daily sync series, and one occurrence Google keeps as changed scanned 5
2 Budget meeting and one daily sync occurrence forgotten, the series kept deleted 2
3 No changes all 0
4 Asked about the deleted money and the daily sync: the money isn't in the context, the series is all 0

The PR has a video of all four runs.

Why a calendar is harder than a folder of documents

  • A series is one document. Events are listed with singleEvents off, so a recurring meeting is one document with its RRULE. An occurrence you changed becomes its own document.
  • One deleted occurrence isn't a deleted series. Google sends back a cancelled entry for it, and only that occurrence is forgotten. Deleting the whole series forgets the series and its changed occurrences.
  • Sync tokens expire. Later runs only fetch what changed. When Google answers 410 Gone, the calendar is listed again and compared against what's stored, so events deleted in the meantime are still forgotten.
  • People live in the text. The calendar name, organizer and attendees with their responses are written into each event, so cognee's entity extraction can connect the same person across meetings. That comes from the LLM reading the text, not from a hard identity mapping.
  • It only reads. The only scope is calendar.readonly, attachments are never read, and the saved state holds sync tokens and ids, not titles or descriptions. The event text does go to your LLM provider during processing, like any document you add to cognee, so use a local model if that matters to you.

The 8 things I missed

PR #370 had no review comments. It was merged as it was.

Then the maintainer ported it to the SDK and fixed eight things along the way, so the SDK wouldn't ship them. The list is in cognee#5912, and reading it taught me more than the merge did.

Wrong data:

  • All-day events came out a day too long, because Google's end date is exclusive.
  • primary and the calendar's real id produced two sets of documents.
  • Hidden calendars dropped out of the list, which changed the ids and names of everything under them.
  • Attendees were written in whatever order Google returned them, so a reorder sent the event through LLM extraction again.

Failure handling:

  • A 404 on one calendar forgot it, even when the same run still saw it in the calendar list.
  • A 403 with a rate-limit reason wasn't treated as a rate limit.
  • check_active, the callback that lets a host stop a sync, only ran once per sync. Now it runs before every API call.

Privacy:

  • Calendar ids, which are usually email addresses, ended up in logs and error messages.

None of these showed up in my 35 tests or my live run. My tests even covered all-day events, and they still passed.

What I did with it

I went through that list and applied what fit to the connectors I still had open. Dropbox got it on October 17 and Outlook on October 18: check_active before every request, no ids in logs or errors, stable attendee order, all-day events ending on the right day. My Google Meet connector was built on the same layout.

So the lesson from my first merged PR of Mergetober is that a merge doesn't mean your code is finished. When someone fixes your code, read the diff. It's a free review, and it's specific to you.

Links

Top comments (0)