When you connect a Google account from the dashboard, a window now opens over the page before
you go to Google. It shows screenshots of Google's own consent screens, with the two
boxes that matter marked:
Ongoing access. On the first screen, Google offers to let the connection keep working
without a review every six months. Tick it, or the connection stops at Google's review.
Select all. On the next screen, every service starts unticked. Tick Select all, then
continue.
Press Continue to Google when you are ready, or Not now to stay where you were. A connect
link opened from outside the dashboard, or in a new tab, shows the same screens on a page of
its own.
Notion now works inside your DataToRAG agent, with Gmail, Drive and Jira in the same conversation.
Connect it from the connections page.
Notion asks which pages to share, and the connector sees only those, children included. You can
share more later from a page's ••• menu, under Connections, without reconnecting.
Reading.notion_search finds pages and databases by title, notion_get_page returns a page's
properties as plain values and its content as markdown, and notion_query_data_source filters,
sorts and pages through a database, or runs one of its saved views.
Writing. Create pages and database rows, edit content in markdown, change properties, move,
duplicate, trash and restore pages, write comments, and create databases and views. In an Agent
conversation, every write asks for approval before it runs.
Workspaces. Each Notion workspace is its own connected account. account takes the email, or
the workspace name or id when one email has several.
Notion's API searches titles, not page content, so search here does too. The full list of tools,
limits and what is not possible is on the Notion docs page, and the
launch post walks through it.
The note on the Google Workspace card on your dashboard, the one that says what the connect
button opens and to tick every box, was drawn below the card's button row rather than in it.
Once you had an account connected it sat under Add account as a separate strip, cut off from
the card it belongs to.
It now sits inside the card, under the buttons, in the same band as Add account and Browse
tools (or under Connect, before you have connected anything). The wording is the same, and
hiding it works the same way: hide it once and it stays hidden on every device you sign in on.
Every day a test run calls the tools on production the way you would, with real accounts, and
checks what comes back: it sends an email and waits for it to arrive, creates a Jira issue and
deletes it, writes to a spreadsheet and reads it back. Until now only we saw the result.
It is public now, at /status. The page is the latest full run, grouped by service:
each check in plain words, whether it worked, and a strip of the 30 days before it. Under each
service are its tools and their state, including the ones no check exercises yet, listed as
exactly that.
If a check fails, it shows as failing in the latest check, and the service with it. If the last
full run is more than a day and a half old, the page says so at the top rather than showing an
old green as a current one.
It doubles as a list of what you can do with DataToRAG, each line backed by the latest run.
Claude's own Gmail, Calendar and Drive connectors could do a few things ours could not. Now
ours does them too.
Calendar.calendar_respond_to_event answers an invitation with accepted, declined or
tentative, and changes only your own response. calendar_suggest_time finds free slots for you
and the people you name, inside working hours, and says whose calendars it could not see.
calendar_list_calendars lists the calendars on the account.
Gmail.gmail_label_message takes a thread_id, so a label goes on or comes off a whole
conversation in one call. gmail_trash_thread and gmail_untrash_thread do the same for
Trash, and gmail_mark_spam and gmail_unmark_spam report a message as spam and take it back.
Drive.drive_share_file shares a file with one person as reader, commenter or writer,
drive_get_file_permissions lists who has access, and drive_list_recent_files lists what you
opened or changed most recently.
Every one of them takes an account, like the rest of the connector. In the Agent, the ones that
change something ask for approval before they run.
A Google Drive file can now be named by a file reference, the same way an email or one of its
attachments already could, so the tools that take a file take a Drive file too.
There are two new references. drive_file names a file as it is stored in Drive: a PDF, an
image, a spreadsheet someone uploaded. drive_export names a Google Docs, Sheets or Slides file
together with a format, such as pdf, docx, xlsx or pptx, and the file is exported to it.
With file_download_link, a Drive file or a Doc as a PDF goes to your computer through a link
that works once, with the SHA-256 of what was sent. With jira_add_attachment it goes onto a
Jira issue. With drive_upload_file and a reference naming another of your connected Google
accounts, it is copied from one account's Drive into another's. In every case the file's
content is not returned and does not enter the conversation.
A folder, a shortcut, a file in Trash, and a Google file asked for as a stored one are refused
before anything is read. Moving files between services lists the
formats each kind of Google file exports to.
Claude's own Atlassian connector logs work, links issues and comments inline on a Confluence
page. Ours does now too.
Jira.jira_add_worklog logs time on an issue in Jira's own duration format, such as
1h 30m, with an optional start time and comment, and jira_list_worklogs lists what has been
logged, with the total. jira_link_issues links two issues by a link type's name or by its
phrase, so "PROJ-1 blocks PROJ-2" is one call, and jira_list_issue_links lists an issue's
links from its own side along with the link types the site has.
Confluence.confluence_add_comment anchors an inline comment to text on the page with
inline_text, and replies to an inline comment as well as a footer one. confluence_get_comments
lists the replies in each thread, says which comment each one answers, and for an inline comment
the text it is anchored to and whether it is resolved.
In the Agent, logging work, linking and commenting ask for approval before they run, like every
other write.
The Google Workspace connector's raw API tool, gws_run, is no longer in the tool list your
client or the Agent sees. With the nine tools from the last release, the jobs it was being used
for have tools of their own, and a model that can see a generic tool sometimes picks it over the
named one and guesses at Google's request shape.
So a client now gets the named tools only: gmail_, calendar_, drive_, sheets_, docs_
and tasks_. A client still holding an older list that calls the raw tool gets a short answer
pointing at those, and that call does not count against your plan. The tool counts on this site
leave it out too.
If you were using the raw call for something no named tool covers, tell us what. That is how the
nine got built, and it is how the next one will.
The Google Workspace connector has one generic tool, gws_run, that sends a single request to
a Google API method by name. It is there for the calls nothing else covers. A call made that
way needs the caller to know Google's resource paths and parameters, and it fails in ways that
say little: a list of ranges handed to a method that takes one, a drafts listing refused for a
userId nobody mentioned, an attachment fetched whole and then rejected for its size.
Nine of those calls are now tools of their own.
Gmail.gmail_trash moves a message to Trash and gmail_untrash takes it back out.
gmail_list_drafts lists the mailbox's drafts with the IDs the other draft tools take.
gmail_get_attachment describes one attachment by its part ID, with its name, type and size,
and returns the content as text when it is a text file of up to 0.5 MB. Anything else, or
anything larger, comes back as a description that states the size, with no content. File bytes
are never returned as base64. To get a file somewhere you can open it,
gmail_save_attachment_to_drive still puts it in Drive.
Drive.drive_get_file describes a file or folder without reading it: name, type, size,
the folders it is in, owners, dates and link. drive_move_file moves it into another folder
and takes it out of the one it was in. drive_trash_file moves it to Trash.
Sheets.sheets_get_metadata returns a spreadsheet's tabs with their titles, sheet IDs,
grid sizes and frozen rows, and no cell data at any size. sheets_copy_tab_to copies a tab, by
title, into another spreadsheet.
Calendar.calendar_list_events has always returned a nextPageToken when there were
more events than it was asked for. It now takes that token back as page_token, so the next
page can be read.
Reading several ranges in one sheets_read call, with ranges, was already there.
gws_run itself does the same thing it did. Its description now says what it is: a custom
query tool for the Gmail, Calendar, Drive, Sheets, Docs, Slides, People and Tasks APIs, with a
link to Google's reference. In the Agent, the moving and trashing tools ask for approval
before they run, like every other write.
drive_upload_file takes the same file reference jira_add_attachment and file_download_link
take, an email or one of its attachments, and puts the file into Google Drive under its own name.
Pass a folder id to choose where it goes; without one it lands in the root of My Drive.
The receipt can say something the Jira one cannot: Drive computes its own SHA-256 of the file it
stored, and the receipt sets it beside the SHA-256 of what was sent, with checksum_match saying
whether they agree. If they do not, the call answers with an error and the full receipt, and the
file stays in Drive for you to look at.
The receipt also names the folder's owners, whether it is shared and whether it is in a shared
drive, next to the account that received the file, so a folder that belongs to someone else is
visible before you rely on it.
The email can come from one connected Google account and go into the Drive of another. The file's
content never enters the conversation and is never written to our disks.
A file reference can now go to your own disk. file_download_link takes the same reference
jira_add_attachment takes, an email or one of its attachments, and answers with a link that
saves the file to your computer.
The link opens a page with the file's name, its size and one button. The button saves the file.
A link works once and lasts ten minutes. If you work in a terminal, the receipt also carries a
one-line command that saves the file without the page.
The receipt gives the size in bytes and the SHA-256 of the file, so you can check your copy with
shasum -a 256, sha256sum or Get-FileHash. The file is the unmodified original: a message
exactly as Gmail returns it in raw form, or an attachment's own bytes. Before it is sent it is
read again and compared with the receipt, and if it no longer matches, nothing is sent.
The file's content never enters the conversation and is never written to our disks. It is held
in memory only while it is being read. For up to twenty minutes after a link is made we keep what
identifies the file (the message it names and the account it is in, its name, size and SHA-256),
and none of its content.
A link is for you. A call to any DataToRAG tool that carries one of your unused links is refused
and the link is cancelled. In a chat with the DataToRAG agent you are asked before a link is
made, and a skill run cannot make one.
Two changes to how a client finds out why a Google call was refused.
list_connected_accounts shows what each Google account granted. Google's consent screen
lets you untick services one at a time, so an account can be connected and still unable to
touch your sheets. Each Google Workspace account in the answer now carries two lists:
granted_services and missing_services, by name (Gmail, Drive, Calendar, Docs, Sheets,
Slides, Contacts, Tasks). When something is missing, the account also says where to reconnect
it. The fields the answer already had are unchanged, so nothing that reads it today breaks.
An account connected before grants were recorded says "not recorded" there. We would sooner
say that than tell you every service was granted when nobody checked.
gws_auth_setup is removed. It came from a time when the Google tools ran on your own
machine and had a login of their own. Behind the gateway there is nothing for it to log in
to, and for a while its only answer was that authentication is handled elsewhere. The Google
Workspace tool count goes from 68 to 67.
If Google refuses a token, the error now names the two things that help: call
list_connected_accounts to see what is connected, then reconnect the account on the
connections page.
If you have a prompt or a saved skill that calls gws_auth_setup, swap it for
list_connected_accounts. A client that cached the old tool list will pick up the new one
the next time it connects.
If you are on Pro, the Billing page in the dashboard failed to load, with an error that a
reload did not clear. It worked for Free accounts, which is how it went unnoticed.
The cause was ours and had nothing to do with your subscription or with Stripe: the page
could not draw the price on your own plan card. Your plan, your payment method and your
invoices were never affected. What you lost was the way to them from the dashboard, including
the button to manage or cancel, and we are sorry for that.
It is fixed, and the page now shows your plan card, your usage for the period, your card on
file and your recent invoices as intended. A check now runs with every change to the site for
the kind of mistake behind this one.
Google's consent screen shows its permission checkboxes unticked. If you press Continue
without ticking them, Google connects nothing, and until now that left you back on the
dashboard under a small banner. Four changes around that moment.
If Google connects nothing, you land on a page that says so. It names what happened,
shows the box to tick (Select all), lists the services it covers, and has one button: Try
again.
Try again goes straight back to the consent screen. It used to send you through
Google's account chooser first, which felt like signing in all over again. It now returns
to the consent screen for the account you just picked. You can still switch accounts there.
A note under the Google connect button says what the button opens, to tick every box,
and that you can disconnect any time. Hide it once and it stays hidden on every device you
sign in on. It comes back by itself if a connect returns with nothing granted.
The agent's first screen numbers its steps. For an account with nothing connected it
now reads "1. Connect an account" and "2. Once you connect, ask for something like", so the
first thing to do is not left to guesswork.
The monthly allowance of agent runs goes up on both plans. Pro goes from 100 to 400, and Free
goes from 25 to 40. Prices do not change.
The higher number applies to the period you are in now, on either plan. There is nothing to do.
The Billing page in the dashboard and the meter in the Agent show it against your usage.
Nothing else moves. The tool call allowances stay where they were, 10,000 a month on Pro and 250
on Free, and so does the ceiling on what a single run can use.
Every Get started, Start free, Sign in and Run this skill button on the site
now opens Google sign-in directly. There used to be a page in between with a single
"Continue with Google" button on it. It asked for a second click to do what the first one
already meant, and some people never made it past.
What changed around that:
The button shows it heard you. Handing over to Google takes a moment. The button now
dims while that happens and ignores a second click, where before it looked as if nothing
had happened.
You still land where you were going. A skill's Run button still ends in the agent with
that skill loaded, and the Pro button on the pricing page still comes back to pricing.
If sign-in does not finish, you get a way back. Closing Google's screen used to end on
a bare line of error text. It now returns to the sign-in page with a note and the button.
Terms and privacy are stated where you sign in. The sentence that lived on the old page
now sits beside the main sign-up buttons and on the first screen of the dashboard, with
links to both documents.
The sign-in page itself is still there. It is where you arrive if a session expires while a
dashboard page is open, or if a sign-in is interrupted.
The Pro plan's monthly allowance of tool calls goes from 2,000 to 10,000. The price does not
change, and neither does anything else on the plan: 100 agent runs a month, every connector and
every tool, and an approval on every write.
If you are already on Pro, the higher number applies to the period you are in now. There is
nothing to do. The Billing page in the dashboard shows it against your usage.
Pro has never stopped you at the allowance, and it still does not. The Free plan is unchanged:
250 tool calls and 25 agent runs a month.
Three changes to how a run looks in the dashboard agent while it works.
Each step says what it was called with. A step in the thread used to show a tool name
and a status. It now also shows a short line of what the call was made with, such as the
range it wrote or the search it ran, so a run of steps reads as a list of what happened.
The full parameters and result are still one click away.
An opened step stays inside its card. Opening a step with a large result, a long inbox
listing for example, used to push the rest of the conversation off the screen. The
parameters and the result now scroll inside the card.
A long wait counts. Once a step has been thinking or running for more than five
seconds, the progress line shows how long it has been going. It is a measurement of the
wait so far, not an estimate of what is left.
And one that was missing words:
"Interrupted" now says what it means. If a step's result never comes back, the run
stops at that step. The thread now says so under the message and offers Try again. It
also tells you to check first if the step was a write, because a call that was sent may
have gone through even though its result did not reach the page.
If your browser translates the dashboard into your own language, the agent page could be
replaced by a blank "this page couldn't load" screen in the middle of a run. It happened the
moment a tool step changed state: a step finishing, or a write waiting for your approval. The
run itself was fine and kept going on our side. The page drawing it was what failed.
The cause was ours. A translating browser rewrites the text on the page, and one small part of
each tool step (the status badge) was built in a way that could not survive being rewritten
while it changed. That part is rebuilt, and the whole conversation is now tested on a
translated page from the first message to the last.
Three things come with the fix:
A fault in the chat stays in the chat. If the conversation ever fails to draw again, for
any reason, you get a card where the conversation was, with Reload this conversation. The
rest of the dashboard stays on screen, and a run in progress carries on and is saved.
The dashboard has its own error page. A fault on any dashboard page now keeps the
navigation and offers Try again, where it used to replace the whole page.
Sending too quickly asks you to wait. A burst of requests is briefly refused. The chat
used to read that refusal as your run allowance being used up and hid the message box. It now
says to wait a moment and leaves the box where it was.
One limit to know about: on a translated page, an answer that is still streaming can show its
text in the original language until the browser translates it again. Nothing is lost, and
reloading the conversation shows the full answer.
When a tool call leaves out a required argument, or names one the tool does not have, the gateway now refuses it before the connector is called. The answer says which argument is missing or unknown, suggests the closest real name for a misspelling, lists what the tool requires, and ends with "Nothing was sent." Before this, such a call often reached the service and came back as an error that did not say what was wrong, and one search tool ran with no query at all.
The check covers the names of a tool's own arguments. The values, and anything nested inside an argument, are still judged by the connector.
sheets_append and sheets_update now say in their descriptions how numeric-looking text is typed: the way the Sheets UI types it, so 007 is stored as the number 7 and reads back as 7. To keep such a value as text, pass value_input_option: "RAW" for the call, or put a leading apostrophe on that one value. Nothing about the write changed; the description now states it.
jira_add_attachment now takes a second kind of file reference: one attachment of a Gmail message. Name the issue, the message and the attachment's part id, and the file lands on the issue under the sender's file name and type, without passing through the conversation or being downloaded.
The part id is the one to use, not the attachment id. Gmail issues a new attachment id every time a message is read, so an id copied from one read does not match the next; the part id stays the same, and gmail_read now lists it beside each attachment.
Each call moves one file, up to 25 MB, and answers with the same receipt as before: the attachment's name and size, the SHA-256 and byte count of what was sent, and the issue it went to. An email with three PDFs is three calls. See Moving files between services. The story behind it, and where the file is while it moves: Claude can file an email on a Jira issue now.
Putting an email on a Jira issue used to mean downloading the message from Gmail and uploading it to Jira by hand. jira_add_attachment does it in one call: name the issue and the Gmail message, and the email's original .eml file lands on the issue.
The file is the message exactly as Gmail returns it in raw form, unchanged by us. Its content never passes through the conversation. It is held in the gateway's memory only while the transfer runs, and is never written to our disks.
The answer is a receipt: the attachment's name and size, the SHA-256 and byte count of what was sent, and the issue's key, project and summary, so you can see what went where. One file per call, up to 25 MB.
When Claude ran several Gmail searches at the same time, Google sometimes refused one of them for being too many requests at once, and the search came back as an error. DataToRAG now waits a moment and tries that read again, up to three times in all, so the search normally returns its results. This applies to most reads across Gmail, Drive, Sheets, Docs and Calendar. Sends and other writes are never retried, so nothing can go out twice.
When Claude replied to an email for you, the reply went to whoever was in the From line. That is wrong in two common cases. A message with a Reply-To address, such as a booking system or a support desk, wants the answer somewhere else. And a reply to a message you sent yourself went back to you.
gmail_reply now addresses a reply the way Gmail's own Reply button does:
To the Reply-To address when the message has one, otherwise to the sender.
To the people you wrote to, when the message is one you sent.
To everyone on the original when you ask for it, with the new reply_all option. It is off unless you ask, and it leaves your own addresses out.
The response says who the reply went to. Because a Reply-To can point somewhere other than the sender you see, there is also a guard: pass expected_to with the address or addresses you mean to answer, and the reply is refused before anything is sent unless it would go to exactly those.
One more fix. gmail_mark_read used to mark a message read even when you only asked it to add a label. It now does exactly what you ask: with no labels given it marks the message read, and with labels given it applies those and nothing else.
Asking Claude to query a tab that did not exist used to return rows anyway. They came from the first tab of the spreadsheet, with no error, so a typo in a tab name looked like a real answer. A tab with an apostrophe in its name, such as Bob's, did the same thing.
sheets_query now checks the range against the spreadsheet's actual tabs before it runs:
A tab that does not exist is refused, and the refusal lists the tabs the spreadsheet has.
A tab name on its own works even when it also reads as a cell, so a tab called Q3 or Log is the tab, not cell Q3 or column LOG.
Tab names with apostrophes or exclamation marks resolve to the right tab. sheets_find_rows also reports the right row number on a tab with an exclamation mark in its name.
sheets_format_table and sheets_format_range resolve tabs the same way. If you ask sheets_format_table to trim the grid on a name that is both a tab and a cell reference, the call is refused with a note on how to say which one you meant.
One thing we measured and cannot change: when a column mixes numbers and text, Google's query endpoint reads it as whichever type most of its cells hold, and the others come back empty. The tool's description now says so. For a column like that, sheets_read or sheets_find_rows returns every cell.
Billing in the dashboard is rebuilt around four things you could not see there before.
Your plan, on the same cards as the pricing page. The three plans are shown side by side with the one you are on marked "Current plan". From Free, Upgrade to Pro is on the Pro card. On Pro, "Manage or cancel" is on your own card and "Downgrade" on the Free one, and both open the Stripe billing portal. If you cancel, Pro stays active until the end of the period you have paid for.
This period. Two meters, tool calls and agent and skill runs, each against your plan's allowance, with the date the allowance resets. They read the same counters the limit itself uses, so the page and the limit cannot disagree.
Payment method. The card on file, its brand, last four digits and expiry, with Update beside it.
Invoices. Your recent invoices with the date, the amount, the status and a PDF link, and "All invoices" for the full list in the portal.
Payment method and Invoices appear once the account has been billed through Stripe; a free account that has never paid sees the plans and its usage. If Stripe is slow to answer, those two sections say so and point to the portal, and the rest of the page still loads.
gmail_send, gmail_reply, gmail_forward, gmail_create_draft and gmail_update_draft take an attachments list. Each entry is a Drive file id. A PDF, an image or any other file is attached as it is. A Google Doc, Sheet or Slides deck passed by id alone goes in as a link in the body, the way Gmail's own compose does it; pass {file_id, as: "pdf"} to attach an export instead. Docs export as pdf, docx, txt, html, md, rtf, odt or epub; Sheets as pdf, xlsx, csv, tsv, html or ods; Slides as pdf, pptx, txt or odp. csv and tsv export one tab: add tab to choose it, and the response says which tab went.
Inline images. Reference a file in html_body as <img src="cid:FILENAME"> and it renders in place instead of as an attachment at the bottom, the same structure Gmail builds when you paste an image into a message.
Forwarding carries the original's files.gmail_forward now includes the forwarded message's own attachments, counted in the limit. Pass include_original_attachments: false to forward the text alone.
Limits and refusals. At most 10 files and 25 MB per message. A refusal comes before any download for files whose size Drive reports, and names the file and the cap; an export is counted as it downloads, and one over the cap stops the message before it is sent. Two attachments may not share a filename.
Drafts with files are signed.gmail_send_draft adds your Gmail signature to a draft that holds files, the way it already does for plain drafts. Updating a draft replaces it whole: files it held are dropped unless you pass them again.
The response says what happened. Each entry is reported as attached, inline, linked or exported, with its size or link.
Files come from Drive only. To send something that is not in Drive yet, put it there first and pass its id. The design, and why the bytes never pass through the model, is in Your Agent Can Attach Files to Email Now.
gmail_save_attachment_to_drive streams the attachment from Gmail into Drive instead of holding it in memory, so a 9 MB PDF arrives in Drive byte for byte with a matching checksum. Anything over 5 MB goes through Google's resumable upload. Before this, an attachment that size failed on a buffer limit.
Underneath, the Google Workspace connector now calls Google's APIs directly with your token on every call, rather than through a bundled command-line tool. You should notice nothing except that big files work and errors from Google come back with their real reason.
A mistyped address, or a link to something that has since moved, used to land on the bare
default page our framework ships. It said the page was not found and offered nothing else, in
type that did not match anything around it.
There is a proper page there now. It says what happened in a sentence and puts a link to the
home page under it, so a broken link is a detour rather than a dead end. It looks like the rest
of the site because it is now part of it.
Nothing else changes. Addresses that worked yesterday work today.
Every connector, pricing and docs page now ends with the questions people actually ask about it, over 180 answers in all, and there is a single page at /faq with all of them. Three published claims were corrected while writing them, including that the built-in Gmail connector sends, replies and forwards, which it does.
Asking sheets_read for the same range more than once in one ranges call used to leave the later copies empty, because Google returns one block for two identical requests. Each requested range now gets its data in its own slot, in request order. Found by our own test suite on its first run.
Email sent through the Gmail connector now ends with the signature you set in Gmail, the same
one Gmail adds when you write the message yourself. It applies to gmail_send, gmail_reply,
gmail_forward and gmail_send_draft. There is nothing to configure: the signature is read from
the address the message is sent from, so an alias gets its own.
Where it goes. On a new message the signature closes the body. On a reply or a forward it
sits under your note and above the quoted message, where Gmail puts it.
Drafts are signed when they are written.gmail_create_draft and gmail_update_draft add the
signature the way Gmail's own Compose does, so a draft you review in Gmail already carries it, and
sending it from Gmail or through gmail_send_draft never adds a second one; gmail_send_draft signs
only a draft that has none. Pass signature: false on the draft tools to leave it out.
Turning it off. Pass signature: false on any of the four send tools and the message goes out
exactly as written. Asking your assistant to "send this without my signature" does it.
The response says what happened. Every send returns a signature field: applied,
none_set when the account has no signature, suppressed when you turned it off,
already_present when the body already ended with it, unavailable when the signature could not
be read and the mail went out unsigned, and skipped_unsupported_draft when a draft's format is
one we send untouched rather than rewrite.
Replies and forwards also changed shape underneath. They are now sent with both a plain-text and
an HTML version, as new messages already were, so a plain-text reply keeps its plain-text part
when a signature is added. The signature itself lives in the HTML version only.
One thing you may notice on a phone: Gmail's mobile apps fold a signature they recognise behind
the three-dot button, including on mail you wrote by hand. That is Gmail's display, not a missing
signature.
Corrected September 18: drafts were unsigned when this shipped; they are signed from the same
day's follow-up release.
Pass a list where the API takes one.gws_run now accepts an array for any query parameter
the Google API repeats: ranges on a spreadsheet get, labelIds on a Gmail message list,
metadataHeaders on a message get. { "ranges": ["Sheet1!A1:B2", "Totals!A1:B5"] } fetches both
blocks in one call. Until today the call was refused with "Array-valued parameters are not
supported" and the only way through was one call per value.
Two per-item tools gained a batch form, so a routine that used to spend one model step per item
spends one.
tasks_create takes a list. Pass tasks (each with a title, optional notes, due date and
task list) and every task is created in one call, with a per-task result so a partial batch is
visible. The single-task shape still works. The morning brief uses this for its follow-ups.
sheets_read takes several ranges. Pass ranges and get one block per range, each labelled
with the range the API echoed, in the order you asked. A header row and a data block, or two tabs,
are one call instead of two. An empty range comes back as an empty block in its place.
Four changes to how a skill run behaves in the dashboard agent, all live today.
Stop means stop. Pressing Stop now ends the run on the server at the next step boundary. The
step already in flight finishes, no further model call starts, and the thread shows a card that
says you stopped it and what was saved. Before this, Stop only closed your browser's connection,
and a run that had been told to label mail and send a digest kept doing exactly that.
A long thinking step no longer ends as "network error". The stream stays alive while the
model thinks, so a step that streams nothing for two minutes still reaches your browser. Runs
that dropped mid-way on a seven-account brief now finish.
A run near its limit writes its report. At 85 percent of the run budget the model is told to
stop calling tools and write what it has. The budget itself now counts cached tokens at their real
weight, so a run is no longer cut short for reading the same prefix it read a step earlier.
Every run says what it cost. The last line of a run reads like 6 steps, 64k tokens, about $0.29, and the Usage page has an agent section with the same numbers per session. Thinking
tokens are counted; nothing about the content of the run is stored.
Skills are published routines for the tools you already connected: a morning brief across every
mailbox and calendar, inbox triage, a week-ahead, filing recurring attachments into Drive, a
Confluence retro into Jira tickets, and six more. Eleven so far, at /skills, the
morning brief first.
Run from the dashboard. Every skill page and every card on the dashboard's Skills page has a
Run button. It opens the agent with the skill loaded and starts the run on the accounts you have
connected; a multi-account skill covers every account of that service and never asks which.
Copy into Claude. Each skill is the actual file. Paste it into Claude and it runs the same
way through the gateway.
Fork and edit. Fork a published skill, change the steps, keep your own copy. Free on every
plan.
What changed under the hood to make a long run finish: a skill run sees only the tools it
declares, so its cached prefix is about a fifth of what it was; runs think at a lower effort
than chat; the stream stays alive while the model thinks; and at 85 percent of the run budget
the run is told to write its report. A seven-account morning brief that used to stop at the size
limit now completes in about three minutes.
The write-up, with one real run and its numbers: Skills are live.
gmail_label_message now leads with the batch form. Pass message_ids (up to
1,000) with add_labels and remove_labels and every message is modified by one
request, so an agent no longer works through a triage pile one message at a
time. The label-and-mark-read pair is a single call: add_labels set to the
label id, remove_labels set to ["UNREAD"].
The result now lists every id with its own outcome. When Gmail refuses the
batch request, each id is retried on its own and reported, so a partial batch is
visible instead of an all-or-nothing error.
The inbox-triage and morning-brief skills say the batch form explicitly.
The agent in your dashboard used to connect straight to the connector servers behind the
gateway. It had every connector tool that way, and none of the gateway's own, which is why it
could run a Gmail search for you but could not answer "which accounts am I connected to". The
one question it was most often asked about itself was the one question it had no tool for.
It is now a client of our MCP, the same surface your desktop client talks to. Concretely:
It can tell you what you have connected. Ask it, and it checks, the same way any other
client would.
It can hand you your MCP config. Ask for it in the thread instead of going to find the
setup page.
What it can do and what your own client can do no longer drift. There is one tool surface
and both of you are looking at it. A tool that appears for one appears for the other, on the
same day, because it is the same list.
The tool cards in the thread say what happened rather than which function ran: "Checking your
connected accounts" instead of a snake_case id. Connector calls keep their literal tool names,
deliberately, because someone auditing what the agent touched in their mailbox wants the exact
name.
Nothing changes about how you connect, what the agent is allowed to do, or which calls ask you
for approval first.
A failed Google Workspace call now shows you the real error. Open a tool in your dashboard's
usage view and each failed call carries a message. For a long time almost every one of those
read [redacted-content], which told you a call failed and nothing else.
The cause was our redaction rule, not the errors. It treated any quoted string over 40
characters as your content, and a JSON error envelope quotes everything. So a Google message
saying replacement text parameter is required but not specified was destroyed for being long.
Every diagnostic worth reading was over the limit by construction.
Redaction is now by field rather than by shape. A recognised error envelope is parsed and
rebuilt from an allowlist of diagnostic fields, so the code, the message and the reason survive.
Everything kept is still scrubbed by the old rules, so an email address, a long file id, or a
run of your document text quoted inside a diagnostic still gets redacted. Fields we do not
recognise are dropped rather than passed through, and anything that does not parse takes the old
blanket path unchanged. Ambiguity still resolves to "this is content".
The honest limit: only Google's envelope shape is recognised. Jira and Confluence return
errors in a different shape, and some of our own messages are plain prose rather than an envelope
at all. Both still take the blanket path, so a failed Atlassian call can still read
[redacted-content] in your usage log.
We are not going to fix that by teaching the parser one more shape, and then the next one. The
redaction rule exists to keep your content out of a third-party analytics tool, which is a real
constraint that is not going anywhere. It was never a reason to censor the copy we store for you
and show back to you, in a table only you can see, quoting an error you already received in full
at the time of the call. So the stored copy is going to stop being redacted at all. That fixes
Atlassian, our own messages, and every connector we add later, in one change.
sheets_find_rows no longer asks for approval in the agent. It searches a range and returns
matching row numbers, and it changes nothing, so the prompt was never a judgement anyone made:
the classifier fails closed on any tool it has not been told is a read, and this one had not
been reviewed yet. sheets_update, sheets_format_range, sheets_format_table and
sheets_batch_update still ask, and a tool the classifier does not recognise still asks.
Three changes, all of them prompted by real calls that failed.
docs_get can now read part of a document. Pass start_index and end_index and you get
that slice back. They are the same character indices mode: "index" reports and
docs_batch_update consumes, so a read and the edit that follows it speak one coordinate
system rather than two.
A ranged response also tells you where you are: totalEndIndex for the document's full length,
clipped for whether there is more, and nextStartIndex to continue from. That matters more
than the range itself. Without it, a few thousand characters coming back looks identical whether
the document ended or the answer was cut off, and those two need opposite next steps. With no
range given, nothing changes and you get the whole document as before.
docs_batch_update now shows what a request looks like. The description carries worked
examples for the common shapes, replaceAllText among them, including the detail that
matchCase belongs inside containsText and not at the top level. That nesting is easy to get
wrong and the API only tells you afterwards.
sheets_find_rows answers a bad tab name with the real ones. Ask for a range naming a tab
that does not exist and instead of a raw parse error you get told there is no tab of that name,
followed by the tabs the spreadsheet actually has. One round trip instead of a guess. The
examples in the range parameter no longer name a tab that most spreadsheets do not have, which
is where some of those wrong guesses were coming from in the first place.
Drive could search, read and create folders. It could not rename anything, and it could not
copy anything. Two tools close that.
drive_rename_file renames a file or folder. The name changes and nothing else does:
content, location and sharing are untouched. It works on any Drive item the account can edit,
Docs and Sheets and Slides and folders alike.
drive_copy_file copies a file and names the copy in the same call, optionally placing it
in a different folder with parent_id.
The copy is the more useful of the two, and the reason is templates. Ask Claude to rebuild a
template and you get something that looks close and drifts a little every time. Ask it to copy
one and you get the original's tabs, formatting and formulas exactly, because it is the same
file. Copy first, then fill in the copy.
One limit worth stating plainly: folders cannot be copied. Drive answers a folder copy with
a 403 saying the file cannot be copied by the user, which reads like a permissions problem you
should retry. It is not. It is how the API works, and no amount of access changes it.
Until today, every email sent through DataToRAG went out as plain text. If you asked Claude for
a formatted summary with links, the recipient got the HTML as visible tags.
gmail_send, gmail_create_draft and gmail_update_draft now take an html_body. The
message goes out as multipart/alternative with a plain-text fallback, so clients that render
HTML show your formatting and clients that do not still get something readable. Pass body as
well and that becomes the fallback part; leave it out and we derive one from the HTML.
gmail_reply and gmail_forward take html_body too, and behave differently in one way
worth knowing. They send single-part text/html with no plain-text alternative, because
those paths hand quoting and threading to a composer that builds the whole message. Same
parameter, same result in a normal mail client, but no fallback part. We would rather tell you
that than have you find it.
One smaller fix came with it: gmail_forward now accepts a body. It never did. You could
forward a message but not say anything above it.
Nothing changes if you were already sending plain text. html_body is optional everywhere and
no existing call behaves differently.
Writing values into a spreadsheet gives you no formatting at all. The default is columns 100
pixels wide with every long cell clipped to a slit, so a sheet with entirely correct data is
routinely unreadable, and the reader never learns there was more text.
Four tools fix that, and they are live now.
sheets_format_table does the whole readable pass in one call: column widths, wrapped and
top-aligned cells, a styled and frozen header row, hairline borders. This is the one to run on
any sheet a person is going to open.
sheets_format_range is for specific styling on top: fonts, colours, alignment, padding,
number formats, merges. It takes a list of instructions and applies them in one atomic call, so
a whole formatting pass is one call rather than one per range.
sheets_batch_update is the escape hatch beneath both, for anything they do not cover:
borders, banding, copy and paste, inserting or deleting columns, duplicating sheets.
sheets_find_rows is the one that saves the most work and is easiest to miss. It finds rows
by value and returns their row numbers, so you can update them directly instead of reading a
whole sheet and filtering it yourself. It searches many values in one call, so looking up twenty
customers is one call and not twenty, and values that matched nothing come back listed
separately, so an empty result cannot be mistaken for a broken one.
Nothing changes for existing calls. All four are additions.
If you connected Google and then found that nothing worked, this is why, and
it was our fault rather than yours.
Google's consent screen brings the service checkboxes up unticked. You had
just signed in, where clicking Continue was correct and sufficient, so clicking
Continue again was the natural thing to do. It granted us nothing. And we
recorded that as a successful connection, so your dashboard said Google was
connected while every tool call failed.
Two changes.
We now tell you what is coming before we hand you to Google. A short page
explains that the boxes come unticked and that "Select all" is the one control
that matters. It sits on the connect route itself, so every path to connecting
gets it: the dashboard, the connections page, the agent's inline prompt, links
from the docs.
A consent that grants no services is now refused rather than recorded. If
you continue without ticking anything, we do not write a connection at all. You
land back with a clear message and a retry, instead of a dashboard that claims
you are connected and a set of tools that quietly refuse.
A connection that granted only some services is unaffected and still works
for what you did grant. The change is specific to grants that cover nothing,
which we can now tell apart from a grant we simply could not read.
If you have connected more than one Google account, one of them is the
default: the account a tool call runs as when you do not name one. Until now
you could see which one it was and nothing more.
You can now change it. Each connected account carries a control to make it
the default, on both the connections overview and the per-service page. It asks
you to confirm first, because the default decides the identity every unqualified
call acts as, writes included, and a silent switch is not something you should
discover from a file appearing in the wrong Drive.
When the current default cannot serve anything and another account can, we say
so. One line names the account that would work, with the switch beside it. It
never suggests moving away from a default that grants at least one service,
since that may be exactly what you intended.
Two smaller honesty fixes came with it. A permission refusal now links straight
to the service page that offers the fix, instead of a page that redirects
somewhere else. And an account connected before we started recording
permissions now says its grant predates recording, rather than claiming every
service was granted.
A bug worth describing plainly, because if you hit it, nothing you did would
have fixed it.
When you connect more than one Google account, one of them is the default: the
account a tool call runs as when you do not name one. The first account you
ever connected became the default and nothing ever moved it. So if that first
account granted no services, every call failed, and connecting a second account
with full permissions did not help. The calls still ran as the first one.
The failure was silent and permanent, and it was worse than it sounds: our own
error message told you to grant the missing permissions, and doing exactly that
changed nothing.
Fixed. A default account whose grant covers no services now yields to one
that works. A default that grants at least one service is never touched, because
that may be a deliberate choice on a multi-account setup, and moving it would be
its own bug.
Scope errors also now name the account that can serve the call, so a refusal
points somewhere instead of repeating itself.
Connecting a Google account and granting it access to your Google services
are two different things, and until now the product treated them as one. If you
clicked through the consent screen without ticking the service boxes, we said
"Connected" and then failed every call.
Two changes, and the second is the one that matters.
The connections page now shows what each account actually granted, service
by service, rather than a single Connected badge. A connection is shown as
complete, partial, or identity-only, so "Connected" now means connected.
A failed call tells you which service was missing. Instead of a bare 403,
a tool that needs a scope you did not grant now says so by name, for example
Gmail not granted, and the connection state above tells you where to fix it.
If you connected an account weeks ago and have been wondering why a tool kept
refusing, open your connections page. The answer is probably on it now.
Frequently asked questions now have a home: the FAQ. It covers
getting set up (including why connecting an account comes before
copying your config), what the gateway can and can't do, safety topics
like the approval gate on writes and Google's verification of the app,
and account basics. Answers link into the docs and blog wherever
there's a longer story.
jira_search results now carry the fields a search is usually after:
each row includes the issue key, summary, status, priority, and
assignee, plus a browsable /browse/ URL that opens the issue in
Jira. Enough to report results, and link them, straight from the
search response.
Your assistant can now manage Gmail labels, not just search by them.
gmail_create_label creates a label (nest with / in the name, like
Alerts/Invoices) and returns it, including its ID.
gmail_list_labels lists every label on the account, system and
user-created alike, with ID, name, and type; those IDs are what
gmail_label_message, gmail_update_label, and gmail_delete_label
take. gmail_update_label renames a label or changes its visibility,
by ID rather than name, and a rename keeps the label on messages that
already carry it. gmail_delete_label deletes a label by ID and
removes it from every message carrying it; the messages themselves are
untouched, and system labels (INBOX, UNREAD, SENT) cannot be deleted.
The workhorse is gmail_label_message: add or remove labels on one
message or several in a single call. Since Gmail treats inbox state as
labels, this is also how you archive (remove INBOX) and mark read
(remove UNREAD).
When your assistant writes to a spreadsheet, a value beginning with
= is now stored as text, never run as a formula. A cell written as
=SUM(A1:A10) holds that string; nothing evaluates. Other values keep
Sheets' usual interpretation, so a numeric-looking string like 007
is still stored as the number 7.
If you want a live formula in a cell, enter it in the Sheets editor,
where it evaluates as always.
Tabs are now first-class. sheets_add_tab adds a tab to an existing
spreadsheet, with a title and an optional header row.
sheets_rename_tab renames a tab by its current title and leaves the
data untouched; saved ranges that name the old title stop resolving.
sheets_clear clears the values in a range while the tab and its
formatting stay; pass a bare tab name to clear the whole tab.
sheets_delete_tab deletes a tab and every row in it, and cannot be
undone through the API, so when "empty, but keep the tab" is what you
mean, sheets_clear is the non-destructive alternative.
There's a new Skills page. Each entry is a working agent
skill you can copy into Claude: triage your inbox, see the week ahead
across every calendar, keep a knowledge base in a Google Sheet, turn a
retro page into Jira tickets. They're the actual files we run, not
descriptions of what's possible. Paste one into Claude, connect your
account, and it runs against your own data through the gateway. Browse
the full grid, or start from a persona that matches how you work.
calendar_list_events now returns a compact view by default: per event
you get the id, title, times, location, a plain-text description (HTML
stripped and truncated, tune with max_description_chars), the
organizer, an attendee count plus your own response status, and the
video join link (Meet, or Zoom and friends from conference data).
Meetings with 10 or fewer people keep their full roster, so a 1:1
still tells you who it's with; bigger meetings collapse to the count.
Recurring events are flagged and attachments come through. What's
gone from the default payload: large-meeting rosters, reminders, and
raw conference metadata.
Why: on a busy calendar, a 7-day pull was returning ~55 KB for 25
events (mostly HTML meeting boilerplate and 100+ attendee objects) and
overflowing the tool response limit before your assistant saw a single
event. The compact view is roughly 85% smaller on the same calendar.
Need the raw Calendar API payload? Pass full: true.
calendar_get_event also converts descriptions to plain text now, with
the same full opt-out for the original HTML.
The dashboard now has a Playground. Example prompts don't just sit there
anymore: hit Run and a Claude-powered agent executes them against your
connected Google Workspace and Atlassian accounts, choosing tools and
streaming results live. It's a demo surface for trying the connectors
before you wire up your own client, with about 20 free runs per account.
Every response gets a thumbs up/down so you can tell us what worked and
what didn't.
The client setup wizard is rebuilt too, with step-by-step flows for
Claude web, Claude Desktop, Claude Code, Cursor, and ChatGPT. A live
status check flips to green when your first tool call comes through, so
you know the connection works before you close the tab.
gmail_mark_read now accepts message_ids (up to 1,000) to change labels
on a whole batch in one call, using the Gmail batchModify API. The
single-message path is unchanged. Small quality-of-life fix in the same
release: gws_run documentation now spells out dotted API resource paths
(users.drafts, not drafts).
gmail_read gains a text_only mode: flattened from/to/cc/subject/date
headers, the decoded plain-text body, and attachment metadata instead of
the raw MIME payload. On a typical marketing email that is about 2% of
the full response size. max_body_chars truncates long bodies with a
marker. Default behavior is unchanged.
gmail_search and gmail_list results are now flattened to
{id, threadId, from, to, subject, date, snippet, labelIds}. This also
fixes a bug where search and list results were missing From/Subject
headers entirely.
Two new tools, gmail_send_draft and gmail_delete_draft, complete the
draft lifecycle. Together with gmail_create_draft and
gmail_update_draft (shipped earlier), your assistant can now create a
draft, revise it across turns, and send or discard it when you give the
word. The human-in-the-loop flow this enables: AI writes, you review in
Gmail, AI sends.
Google approved DataToRAG's verification for all eight Workspace scopes
after passing the CASA Tier 2 security assessment. No more unverified
app warning. Read the announcement.
The experimental gmail_triage tool is removed. Its job is better done
by composing gmail_search, gmail_read (now with text_only), and
gmail_mark_read directly.
New gmail_mark_read tool for label modification: mark messages read,
and add or remove labels in the same call. Marking read always removes
the UNREAD label regardless of other labels you add.
docs_get responses now include metadata for inline images embedded in
a document, so assistants can see where images sit in the content flow
instead of silently skipping them.
Attachments now go straight from Gmail to Drive with
gmail_save_attachment_to_drive, instead of round-tripping base64
attachment data through the model context. gmail_get_attachment is
removed.