Skip to content

[Gmail] Converge the gmail adapter with cloud's google-mail-relay integration #258

Description

@khaliqgant

Gmail has two parallel implementations. Neither is a copy of the other, and the one shipped in this repo is the thinner of the two.

relayfile-adapters/packages/gmail cloud + relayfile-cloud
Nango integration google-mail, sync google-mail-emails google-mail-relay — 6 syncs (labels, filters, messages, send-as, threads, renew-watch) + 3 actions (watch-mailbox, stop-watch, provision-pubsub-infrastructure), in cloud/nango-integrations/
Path root /gmail /google-mail
Resources threads, drafts, watches labels, filters, send-as, messages, threads, watch-renewals
Thread/message record a marker: id, labelIds, timestamps, url — bodies fetched separately flattened with subject / from / to / date + decoded text/plain (see cloud/packages/core/tests/provider-write-planner-google-mail-parity.test.ts)
Consumers none until AgentWorkforce/relayfile-cloud#136 the live system

google-mail-emails — this adapter's declared sync — exists nowhere outside this package's own source. The real integration was built separately in cloud with a richer sync set, and cloud's GOOGLE_MAIL_RESOURCES (packages/core/src/relayfile/provider-contracts.ts, mirrored in sync/record-writer.ts) is hand-maintained rather than imported from here — unlike github/linear/notion/slack/jira/confluence, which all import resources from their adapter package.

identity.ts already declares the intended end state: /gmail canonical, /google-mail a "read/digest compatibility identity while existing Cloud mounts are resynced", with resync: required and retireLegacyAfter: zero-references-and-explicit-cutover. That cutover has not been executed.

Why this can't be a one-line import today

Swapping cloud's hardcoded list for import { resources } from "@relayfile/gmail" regresses three ways at once:

  1. Coverage — drops labels, filters, send-as, and watch-renewals (4 of cloud's 6 resources).
  2. Paths — emits /gmail/* where cloud materializes /google-mail/*; every read misses and returns an empty tree.
  3. Record shape — the thread marker is not the flattened record cloud's readers expect.

Steps

  • 1. Port the missing resources into the adapter. Add labels, filters, send-as, messages (first-class, not just threads), and watch-renewals, matching google-mail-relay's sync outputs. The adapter adopts cloud's richer set — not the reverse.
  • 2. Adopt the flattened record shape. Thread and message records carry subject/from/to/date and decoded text/plain, so a header-level search is a grep with no hydration. Pin it against the existing cloud parity test.
  • 3. Unify the Nango integration. Reconcile google-mail + google-mail-emails against google-mail-relay's 6 syncs and 3 actions, and decide which config key survives.
  • 4. Execute the root cutover. Resync /google-mail/gmail per the GMAIL_IDENTITY.migration policy, then retire the legacy root once references hit zero. Riskiest step — it moves live mounts, and persona scopes naming /google-mail break the moment it lands.
  • 5. Delete the duplicates. cloud's GOOGLE_MAIL_RESOURCES and relayfile-cloud's providers/google-mail.ts import from @relayfile/gmail, the way github.ts does.

Steps 1–2 are the substantial work. Step 4 is the one that needs a plan rather than a PR.

Related duplication worth killing in step 5

relayfile-cloud/packages/relayfile/src/writeback/providers/google-mail.ts carries its own

const DRAFTISH_FILE_RE = /^(?:draft|create|new|tmp|temp)(?:[._-]|$)/i;

— a second copy of the reserved-prefix heuristic whose adapter-side twin was the Major finding in #257: a neutral filename like ask-storebrand.json matched neither the prefix list nor a real provider id, so it resolved as canonical and issued an update for a record that does not exist. Drafts now delegate to the adapter (relayfile-cloud#136), but that copy still governs filters and send-as there, so the same class of misclassification is live for those two resources.

Context

  • feat(gmail): wire draft writeback to the Gmail drafts API #257 — wired draft writeback to Gmail's drafts API; published as @relayfile/gmail@0.3.3.
  • AgentWorkforce/relayfile-cloud#136 — routes /google-mail/drafts/* through that adapter. First production code to consume this package for google-mail, and the bridgehead for step 5.
  • AgentWorkforce/cloud#2892 — adds /google-mail/drafts to the persona mount scope.

Found while benchmarking mail surfaces for a set of personal-assistant personas: the adapter looked far weaker on paper (threads-only markers) than what production actually materializes, because the two implementations had diverged.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions