I asked my AI memory three things about a project: who leads it, how long the drone battery lasts, and how much was spent on batteries.
Project Falcon is led by Meera Joshi, the drone battery lasts 55 minutes, and 12 lakh rupees was spent on batteries.
Then I opened Dropbox, deleted a PDF and a folder, and moved one file somewhere else. I synced again and asked the same question.
Meera Joshi leads Project Falcon. The provided context does not contain information about how long the drone battery lasts or how much was spent on batteries.
That second answer is what I spent most of October on. Getting files into memory is the easy part. The hard part is getting them out at the right moment, and never by accident.
(Project Falcon is made up. I wrote those files for testing.)
cognee is an open source memory layer for AI agents. You hand it data and it builds a knowledge graph plus vector search on top, so you can ask questions across everything. For Mergetober I built a Dropbox connector for it, and it was merged into cognee-community on October 30.
A bit about me: I'm studying CSE (AI/ML), I started coding and using git in May 2026, and I had some open source experience before this. I joined Mergetober because it was something related to AI, and I mean, you can give it memory. Who wouldn't love that?
What I want to use it for
So far I've only run this on the test files below, not on my own, and honestly I rarely use Dropbox. If I sync something real, it'll be my college technical reports, like FASTag and smart dustbin. They're PDFs, so the connector can read them, and a question like "which of my reports use RFID, and what did I say about it?" needs an answer across all of them, which a plain file search won't give me.
Try it
The package isn't on PyPI yet, so install it from the repo:
git clone https://github.com/topoteretes/cognee-community
cd cognee-community/packages/connector/dropbox
uv sync
-
Create a Dropbox app with Scoped access. Pick App folder if you only want it to see
Apps/<your app>/, or Full Dropbox if you want everything. - In the Permissions tab, enable
files.metadata.readandfiles.content.read, then click Submit. Nothing else is needed. - Copy the App key and get a refresh token once. This uses the PKCE flow, so there's no app secret and the token doesn't expire:
DROPBOX_APP_KEY=<app key> uv run python examples/get_refresh_token.py
- Set
DROPBOX_APP_KEY,DROPBOX_REFRESH_TOKENand yourLLM_API_KEY, then save this assync.pyand run it withuv run python sync.py:
import asyncio
import os
import cognee
from cognee_community_connector_dropbox import dropbox_source
async def main():
await cognee.remember(
dropbox_source(
folder_paths=["/Notes"],
refresh_token=os.environ["DROPBOX_REFRESH_TOKEN"],
app_key=os.environ["DROPBOX_APP_KEY"],
),
dataset_name="my_dropbox",
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("What are my notes about?", datasets=["my_dropbox"])
print(answer)
asyncio.run(main())
Run it again whenever you want to sync. It reads txt, md, csv and PDF files and exports Paper docs. Anything else is skipped and counted.
What happened on a real Dropbox
I tested on a free Dropbox account with an App folder app, Gemini as the LLM and local fastembed for embeddings. These are the four runs behind the answers at the top:
| Run | What happened | Sync stats |
|---|---|---|
| 1 | First sync of 5 files, logo.png skipped as unsupported |
scanned 5, skipped 1 |
| 2 | After deleting budget-report.pdf and the Meetings folder, and moving project-falcon.md into a new Archive folder |
scanned 1, deleted 2 |
| 3 | No changes, and the access token refreshed by itself | scanned 0 |
| 4 | Asked only about facts from the deleted files | scanned 0 |
The battery facts lived only in the deleted files, so they're gone. Meera Joshi survives because that name was also in the moved file, which was updated in place and not forgotten.
Here's run 4. cognee says the facts are no longer in its context, and the sync stats are all zero:
The PR has a video of runs 1 and 2, with the changes being made in Dropbox.
Four things that make forgetting hard
Only what changed is fetched. The connector saves Dropbox's list_folder cursor, one per folder, so the next run gets just the changes.
Deletes arrive without an id. Dropbox reports a deleted file by path, but memory is keyed by id. So the connector keeps a path to id index and turns deleted paths back into ids. A deleted folder forgets everything under it: /notes/ matches, /notes2 doesn't.
A move looks like a delete. A rename shows up as a deleted old path plus the same id at a new path. Deletes are held until every folder has been read, so a moved file is updated in place. It isn't forgotten and learned again.
A passing error never deletes. A network error, a 5xx, a rate limit, a bad token, or a folder Dropbox reports as locked or restricted removes nothing. Data only goes when Dropbox says it's gone, when a file leaves the synced folders, or when a stored file turns unreadable for good: skipped now, or failed on 3 runs in a row. Old text shouldn't stay in memory as if it were still current.
What the review taught me
I opened the PR on October 8 with 35 tests, an in-memory fake of Dropbox, and the live test above. It merged 22 days later with 125 tests. Most of that gap came from review. goran-radonic ran my code through real dlt and cognee and injected failures on purpose, round after round.
Four of the things that came up:
- A file written over an old path. Delete a file and create a new one at the same path, and between two syncs Dropbox may report only the new file. My index overwrote the old id and nothing ever forgot it. Through real cognee, the dataset ended up with 2 documents and both versions in the graph.
- A file edited down to nothing. An emptied file gets skipped, and a skipped file emitted nothing, so the old text stayed in memory. The same went for a file that grew past the size limit or got renamed to a type I don't read.
- The third sync after a folder delete. The folder was forgotten correctly, but I lost track of it. The next run read it as never synced and raised a folder not found error.
-
One locked folder. This was the last round, on the day it merged, and it's the comment that stuck with me most. I was treating every lookup error on a synced folder as "the folder is gone". That included
locked, which is temporary, andother, the SDK's catch-all. One injectedlockederror made the run forget that folder's files, and the next run learned them again, paying for LLM extraction twice. It also made my own README line, "A passing error never deletes", false. Now onlynot_foundandnot_folderforget a folder.
The other half of the review was about my tests. The maintainer would remove code and check whether anything went red. In the first round, a whole filter could be deleted and all 56 tests stayed green. That's mutation testing. I already checked that each new test failed without its fix, but I hadn't asked the same of the code I'd written earlier. From then on, I reran each mutation myself before pushing.
What I took from it:
- A fake only knows what you told it. Mine passed because it shared my assumptions. As I said in the PR, the real pipeline "found things my fake never would".
- A green test means nothing until you've seen it red. Remove the fix, watch the test fail, put the fix back.
- Ask "what if this fails halfway?" about every line that touches state. And never write "any error means gone". List the errors that really mean gone, and let everything else stop the run.
I've carried all three into my other connectors. Thanks to goran-radonic for the time put into these rounds.
Limits so far
- Team spaces aren't supported yet.
- Paper export is unit tested, but I haven't tried it on a live Paper doc.
Links
- PR: https://github.com/topoteretes/cognee-community/pull/316
- cognee: https://github.com/topoteretes/cognee
- Built during Mergetober by WeMakeDevs x cognee

Top comments (0)