-
released this
2026-08-22 13:59:41 -05:00 | 8 commits to main since this releaseG2. The Gmail tenant can write.
update_message,move_messageanddelete_message,
behindMAIL_WRITABLE_FOLDERSand registered nowhere when it is empty — which it still is
in the stack file, because the setting does not go in until the live pass has run.The tool list changed, so reconnect the Gmail connector. Claude caches tool
descriptions per connector and does not refetch them because a container restarted.Added
-
update_message(message_id, read, starred). Two optional flags, neither defaulted;
passing neither is an error rather than a no-op reported as success.starred, where
the mail tenant saysflagged— Apple's clients draw a flag, Gmail draws a star and
has a Starred view a user asks for by name. Probe 10g confirmed the IMAP\Flaggedbit
and the[Gmail]/Starredlabel are the same thing, so the rename costs nothing
underneath. -
move_message(message_id, destination_folder), and it says what it really does.
Gmail has labels, not folders: this removes the source label and adds the destination,
and the message KEEPS every other label it had and stays in All Mail. The description
says so in those words, because a model that reports "moved" to a user who then finds
the message under another label has told them something false about their own mailbox.The destination goes through the same four-tier resolver the read tools got in 0.29.7,
sospam,trashandSent Mailall land correctly — and a name matching nothing is
an error, never a silent success. The source does not: it comes out of a handle this
server minted, and running that through a fuzzy matcher would let a forged near-miss
resolve onto a real label. -
delete_message(message_id), trash-only, no second argument, and none ever. Gmail's
delete_messageis born the way 0.30.0 made the mail tenant's, so the two connectors
never mean two things by one name.expunge_messageis G5's.
Changed
-
A move here is ONE command.
icloudmailmoves in three — COPY, flag\Deleted,
scopedUID EXPUNGE— because iCloud advertises noMOVE. Gmail does, probe 10b issued
one and read aCOPYUIDback, so that workaround is not ported. Its intermediate state
— a message flagged deleted but not expunged, hidden in most clients while still
counting against the label — cannot arise here. -
_trash_folderresolves the\Trashrole FIRST on this tenant, the opposite order
from next door, and the inversion is load-bearing rather than tidy.TRASH_FOLDERis
shared by both mail tenants and defaults to Apple'sDeleted Messages, which is not a
label on any Gmail account — so config-first would send every delete to a label that
does not exist, or, if a user happens to have made one by that name, to an ordinary
label Gmail's Bin view never shows while the tool reported success. Written up in
CLAUDE.mdunder A role folder resolves the way the provider guarantees it. -
The server instructions stop claiming to be read-only when they are not. The
sentence is now built from the same setting the tools are registered on, so the promise
in the initialize response and the surface behind it cannot drift apart. -
New preflight check
gmail_trash, silent when writes are off. Not a restatement of
mail_writable: that asks whether the write allowlist is readable, this asks whether
the one label every delete lands in is reachable at all. A deployment can pass every
other check and still refuse every delete.
Notes
-
probes/gmail_probe_write.pyran first, and G2 was scoped without it. Probes 1–9
read CAPABILITY, provedCOPYadditive and proved an expunge inside a label removes the
label — but never issued aMOVE, never read aCOPYUID, and never touched Trash,
which is three of the four things these tools are built out of. Findings in
docs/gmail-plan.mdunder Probe 10. The two that changed the code:A COPY to
[Gmail]/Trashremoves the source label, unlike a COPY to any other
label, so a delete really does take the message out of the mailbox and the description
may say so. And Trash HIDES a message's other labels rather than stripping them — a
two-label message put in Trash was invisible in both whileX-GM-LABELSstill reported
them, and moving it back out brought the untouched one with it. That is what lets
delete_messagepromise a reversible delete instead of hedging. -
Two of five new tests passed against deliberately broken code, and both were fixed
rather than trusted. One asserted a true thing the broken version also satisfied; the
other could not reach its own hazard because the fake ASSIGNED where imaplib APPENDS.
The rule is now inCLAUDE.mdunder A new guard is not proved until it has been
broken. -
Not yet run live. G2's pass is written up in
docs/operations.mdbeside M1–M5 and
G1 and is owed before this is trusted on real mail — including the absence check, which
no unit test can confirm on the deployed service.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
-