molecule-ai

gmail-channel-molecule (0.1.2)

Published 2026-07-28 20:50:01 +00:00 by pypi-publisher

Installation

pip install --index-url https://git.moleculesai.app/api/packages/molecule-ai/pypi/simple/ --extra-index-url https://pypi.org/simple gmail-channel-molecule

About this package

Gmail inbound channel bridge for a Molecule workspace (poll-mode A2A relay, stdlib-only, per-workspace OAuth).

gmail-channel-molecule

First-party Gmail inbound channel for Molecule workspaces. Polls a Gmail mailbox (stdlib only) and relays each new message into a workspace over A2A message/send, deduped on the Gmail Message-ID. Credentials are per-workspace — minted via a Google device grant (gmail-connect skill) and stored as the workspace's own secrets; nothing mailbox-specific is baked in.

Modeled on plugins/lark-channel. Discoverable + install-on-demand via the molecule-core manifest.json plugin catalog (NOT auto-installed).

Layout

Path Purpose
plugin.yaml Marketplace manifest — kind: channel, contributes the gmail-bridge daemon + gmail-connect skill.
gmail_channel_molecule/bridge.py Pure decision helpers (plan_message/to_envelope) + Gmail REST + A2A relay + poll loop.
gmail_channel_molecule/daemon.py Console entry — poll/daemon modes, env-wins credential loading, connect dispatch.
gmail_channel_molecule/onboard.py Google device-grant onboarding → writes GMAIL_* workspace secrets + restart.
skills/gmail-connect/SKILL.md Agent-driven connect flow (start → status → finalize).
daemon-bootstrap.sh contributes.daemons entry — installs delivered source, execs the daemon.

Connect

See skills/gmail-connect/SKILL.md. In short: create a Google OAuth client of type "TV and Limited Input devices", export GMAIL_CLIENT_ID/GMAIL_CLIENT_SECRET, then gmail-channel-molecule connect start | status | finalize.

Scope (v0.1.0)

  • Inbound only (gmail.readonly). Replies-to-email would be a v2 adding gmail.send.
  • The daemon runs from delivered source (no published wheel required). The connect onboarding CLI is pip installed on demand; the wheel is published to the org Gitea PyPI registry by auto-releasepublish (a green merge to main cuts tag v<version>, which builds + uploads the wheel), so pip install gmail-channel-molecule==0.1.0 resolves.
  • Unit-tested (pure helpers + onboarding finalize contract); a live OAuth + relay verification against a real mailbox is recommended before fleet rollout.

Diagnosing a silent channel

The state dir (GMAIL_CHANNEL_STATE_DIR, else /workspace/.gmail-channel, else ~/.gmail-channel) holds two files:

File Written Read it to answer
cursor.json only when mail moves where the high-water-mark is; which messages are deferred
status.json every tick, always is the loop still ticking, and what did the last tick fail on

cursor.json alone cannot distinguish "the daemon is wedged" from "the mailbox is quiet" — both look like a frozen mtime. status.json carries tick_finished_at and last_error, so a stale beat means wedged and a fresh beat with a last_error names the failure.

Poll-loop invariants worth knowing before debugging:

  • A tick cannot run forever: GMAIL_TICK_BUDGET_SECONDS (default 300) is a hard SIGALRM deadline. urlopen's timeout= is a per-socket-operation timeout, not a deadline, so it is not by itself a bound on a tick.
  • A single message can never wedge the channel: one that Gmail won't hand over is skipped, one whose sender hasn't materialized is deferred (MAX_DEFER ticks, then promoted with a fallback sender), and one the platform refuses is retried next tick. In all three cases newer mail keeps flowing.
  • The cursor is a commit frontier: it never advances past a message that was not relayed. Messages relayed ahead of the frontier are held in _promoted until it catches up, which is what makes flowing past a stuck message safe from duplicates.

Requirements

Requires Python: >=3.11
Details
PyPI
2026-07-28 20:50:01 +00:00
11
Molecule AI
Proprietary
48 KiB
Assets (2)
Versions (11) View all
0.3.3 2026-08-10
0.3.2 2026-08-08
0.3.1 2026-08-08
0.3.0 2026-08-08
0.2.0 2026-08-04