Sync Google Drive folders into the Cortex knowledge graph — on demand or on a schedule, fully server-side, with no OAuth anywhere.
The model: your instance gets its own Google service account (a bot identity in your own free Google Cloud project). Anyone — Workspace org or personal Gmail — simply shares Drive folders with the service account's email address, like sharing with a colleague, and those folders become syncable. No consent screens, no app verification, no CASA review, no token expiry dances, no user caps.
Regular files upload as-is (binary passthrough); Google Docs, Sheets, and Slides export as PDF. Edited files replace their previous Cortex document instead of duplicating.
Built from cortex-app-template.
Type: platform — the sync runs inside Cortex as a declarative platform
task.
Requires a Cortex instance with the
google_sa_tokenauth transform and binary passthrough upload (cortex-app ≥ 2.1 / July 2026 platform extensions, wave 2). The service-account key is deliberately per deployment — Cortex ships no shared Google credentials.
- Create a free project at console.cloud.google.com, enable the Google Drive API (APIs & Services → Library).
- Create a service account (IAM & Admin → Service Accounts → Create — no roles needed), then Keys → Add key → JSON. A key file downloads.
npm install && npm run package→gdrive-sync-{version}.zip; install via Cortex admin → Settings → Apps → Install (needsENABLE_APPS=true).- Configure the app: paste the entire JSON key file, unmodified —
from the opening
{to the closing}, including theprivate_keywith its\nsequences — intoGDRIVE_SA_KEY(stored encrypted; tokens are minted from it server-side and the key never leaves the instance), and the account'sclient_emailintoGDRIVE_SA_EMAIL. - Open the app, copy the service account's address, and share folders with it in Google Drive (right-click → Share → Viewer). They appear in the picker; select, schedule, Sync.
- setup — one Drive
files.listper synced folder (selected roots + sub-folders expanded at submit time, capped at 40; up to 1000 files per folder per run). - per file — listings concatenated and deduped against app storage:
synced/{id}:{md5|modifiedTime}(binaries change theirmd5Checksum, Google-native docs theirmodifiedTime). Unsupported Google types (Forms, Sites, …), non-document extensions (optional) and files over ~19 MB are skipped with visible reasons. Then a binary passthrough upload: regular files viafiles.get?alt=media, Docs/Sheets/Slides viafiles.export→ PDF. Edited files replace their Cortex document in place: the upload carries a stablesource_key(gdrive:{fileId}) plus the previous document id (docmap/{id}), so the document keeps its id and Cortex re-extracts only the parts that changed. On a Cortex backend without in-place replace, the app falls back to the old behaviour (new document, then the previous one is deleted). - Auth is entirely config-side: the manifest's
auth_headercarries agoogle_sa_token(...)transform, so every call gets a freshly minted, cached service-account token injected server-side. The task itself holds no credentials.
- Deleting or unsharing a file does not delete it in Cortex.
- Folders with more than 1000 direct files sync their first 1000 per run.
- Google Docs/Sheets/Slides export caps at 10 MB (Google's export limit) — oversized exports surface as failed items.
- New sub-folders under a synced root are discovered on re-submit (Sync now), not mid-schedule.
keyScope: read_write;endpoints: ["upload", "documents", "collections"]capabilities: http(host-allowlisted towww.googleapis.com),tasks,storage; scope requested is read-only (drive.readonly)
cp .env.example .env # CORTEX_DEV_URL + a cortex_rw_… key
npm run dev