Skip to content

Console + docs for the new Gmail states: read-only vs send-capable, and the write-consent gate #714

Closed

Description

@serge-ivo

Part of the Gmail epic. Follows the tool work — the plumbing has three new refusal states and none of them is currently expressible in the UI.

Why

Once Gmail can send, an owner has three independent switches to reason about, and today the console surfaces one of them:

  1. Is Gmail connected — shown now, AccountConnections.tsx (Preferences → Connections), backed by GET /v1/email/status.
  2. Does this agent have email permission — AgentState.permissions.email, enforced at lib/storage-tools.ts:553, toggled in Settings → Permissions & Connections.
  3. Was the connection granted send scope — new, and unrepresented. A connection made before the send work exists carries gmail.readonly only.
  4. Has this instance been write-consented for gmail ([connectors] Connector consent + write-scope safety + admin visibility #90) — newly applicable once scopes.write flips to true.

An agent that fails to send because of (3) or (4) reports a tool refusal into a chat transcript. That is the wrong place for a state the owner has to change in Settings.

Scope

  • GET /v1/email/status gains canSend; AccountConnections.tsx shows Gmail as "connected — read only" with a Reconnect to allow sending action when the stored grant predates the send scope.
  • The instance Settings → Permissions & Connections block distinguishes "read my mail" from "send mail as me" rather than presenting one email switch, since they are now genuinely different powers.
  • The header comment at the top of lib/connectors/connected-accounts.ts currently argues at length that Gmail's tools: [] is "the point, not an omission". Once the connector carries declared tools that reasoning is half-true — it remains correct about find_confirmation_link and its permission-flag grant model, and becomes wrong as a statement about the connector. Rewrite it to say which of the two it means, or it will mislead the next reader exactly where the security argument lives.
  • platform-docs/connectors.md gets the Gmail entry: what it reads, what it can send, and the two gates.

Done when

  • every refusal the tools can produce corresponds to something the owner can see and change in the console, without reading a chat transcript to discover it

Activity

  1. serge-ivo commented on Aug 19, 2026

    @serge-ivo
    ContributorAuthor

    Shipped in 8431765 (console + docs) and 3a1f the seed.

    Solved generically rather than as a Gmail special case: GET /v1/connectors now reports grantedScopes and missingScopes for every OAuth connector, comparing what the connector declares against what migration 0133 recorded. Any connector that gains a scope has this problem, not just Gmail.

    The distinction that matters: missingScopes: null means we never recorded this grant, which is not the same as nothing is missing — and is exactly the read-only population. needsReconnect treats unknown as stale, but only for a connector that declares write, since a reconnect adds nothing to a read-only one.

    The row reads "connected as you@example.com — read-only, reconnect to allow sending".

    The stale connected-accounts.ts header the issue flagged was rewritten back in #711 when Gmail moved out, so it no longer half-describes a connector it stopped applying to.

    platform-docs/connectors.md gets a Gmail section covering the two scopes and why gmail.modify is not requested, the five tools, the three gates on a send, why a reply's recipient is not the agent's choice, and what happens to a pre-existing connection.

  2. serge-ivo commented on Aug 21, 2026

    @serge-ivo
    ContributorAuthor

    Re-verified at `main` @ `8bf125c4` (2026-08-21) while filing #720/#721. The shipped half is real — `GET /v1/connectors` does report `grantedScopes`/`missingScopes` generically, and `accountConnections.ts` renders the read-only row.

    One scope bullet was not delivered and the closing comment does not claim it was:

    The instance Settings → Permissions & Connections block distinguishes "read my mail" from "send mail as me" rather than presenting one email switch, since they are now genuinely different powers.

    Measured in WebKit at 420px against production, on an instance whose only write connector is GitHub, that block still renders one generic paragraph over an unlabelled checkbox:

    Agent write access — "Lets this agent act as you — click, type, and navigate — through the connector on your machine."
    ☐ Github write access
    ☐ Allow this agent to read my inbox for sign-in links & codes

    31px between the two checkboxes, same card, no per-connector statement anywhere. Not reopening — the finding is carried forward:

    Related and separately owned: #717, #718.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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