Using the New Google Docs API Suggestions and Comments to Build a Gemini Writing Coach in Apps Script

When we use generative AI to proofread our daily writing, whether technical reports, business proposals, or blog posts, it is easy to fall into the habit of simply copying and pasting AI-rewritten text without reflecting on what was changed or why. While that fixes the immediate draft, it rarely helps us grow as writers.

In our Q3 2026 Google Workspace Developer Release Notes, we highlighted the arrival of native comment and suggestion management in the Google Docs API (v1). Inspired by Romin Irani’s recent Google Cloud series on building ADK document reviewers and comment assistants, Kanshi Tanaike has released DocuMentor AI, an open-source Google Docs add-on built in Google Apps Script that turns those new endpoints into an interactive writing coach.

Developers who have worked with the Google Docs API will know the challenge of managing shifting startIndex and endIndex character offsets when inserting and removing content (and since DocumentApp doesn’t support Suggesting mode or comments, there is no avoiding the REST API here). If you’ve already explored the official WriteControl and suggestions guide, the guide simplifies this by only showing single-request examples, such as inserting a string at index: 1 with writeMode: "SUGGEST". Digging into Kanshi’s implementation reveals several practical patterns that aren’t covered in the official docs:

  • Applying Suggestions: You cannot propose a suggested edit and reply to it in the same batchUpdate call because the suggestion ID doesn’t exist until the edit is created. Kanshi solves this in two steps: first applying all suggested edits in reverse order (from the bottom of the document to the top) so character positions don’t shift, and then using the suggestion IDs returned in the response to attach the coaching notes (addCommentReply) in a second batchUpdate call.
  • Commenting on Tables & Images: Adding text suggestions immediately changes the character positions of everything further down the page. Before attaching review comments to charts or tables, the script fetches the document a second time to get their updated positions, and falls back to the surrounding paragraph if the API rejects anchoring a comment directly to an image.
  • Mapping Selections: The Docs REST API has no way to know what a user has highlighted on screen, while DocumentApp.getSelection() doesn’t return the startIndex and endIndex offsets the REST API requires. To let users review just a highlighted section, the script matches the selected DocumentApp elements (and any comments anchored to them) to their corresponding positions in the Docs API response.
  • Tracking Accepted or Edited: Because WriteMode.SUGGEST runs under the user’s own account and resolved suggestions disappear from the document body, the API doesn’t distinguish AI edits from human ones or track what the writer did with them. To work around this, the script saves each AI suggestion ID and its surrounding text in DocumentProperties, comparing them on later runs to see whether the suggestion was accepted as-is, edited further, or rejected.

Since publishing his original walkthrough, Kanshi has continued to iterate on the project, sharing a follow-up post, Beyond Passive AI Rewrites and Vibe Coding in Google Docs, along with several updates to the repository adding embedded code-block review, Google Drive rulebook grounding, and admin-friendly API key management. To explore the full walkthrough and the latest version of the code, check out the source post below and the tanaikech/DocuMentorAI repository on GitHub.

Source: Building a Multimodal, Suggestion-Based AI Writing Coach with Gemini and Google Docs – Kanshi Tanaike

Exploring Apps Script CacheService Limits: Empirical Findings and FIFO Eviction Gotchas

Caching is a critical strategy for optimizing performance in Google Apps Script properties, especially when dealing with slow APIs or heavy computations. The built-in CacheService provides a simple key-value store, but its documentation leaves several โ€œedge casesโ€ and failure scenarios vague. While the documentation states a maximum value size of 100KB, it doesnโ€™t explicitly detail what happens when you hit the Apps Script CacheService key length limit or throw odd types at it. In this post, weโ€™ll write a script to empirically test these limits … and explore how the service behaves under stress.

Google Workspace alum Justin Poehnelt (whose open-source work many in the community will recognise from the Google Workspace CLI (gws)) has shared a great investigation in Apps Script CacheService Limits. As noted by Justin, while the official CacheService documentation states some of the limits like key value size and the 1,000 cacheable item limit, it leaves out some important details. One finding I think every Apps Script developer should know about is the mechanics of cache eviction when you go over 1,000 items. When you reach this limit, rather than one-in, one-out, CacheService will drop approximately 100 of the oldest items.

For developers who use other caching tools like Redis or Memcached, which primarily rely on Least Recently Used (LRU) where frequently accessed keys stay alive, another key finding is that CacheService uses First-In, First-Out (FIFO). This means CacheService throws away your oldest data even if you are regularly using it in your script. Iโ€™m sure most developers are defensively using CacheService to cache values if not found. To keep “hot” keys from aging out of the queue, Justin shares a function in his post to manually remove and re-insert them.

What I really like about Justinโ€™s post is the empirical approach, writing a small test harness to verify how the Apps Script runtime behaves in practice rather than taking standard cache behaviour for granted. As more developers use the Gemini side panel in the Apps Script IDE or AI coding assistants to vibe-code Workspace automations, having Justinโ€™s posts and ones like it hopefully nudge these tools in the right direction regarding this nuanced behaviour. Understanding these runtime quirks upfront can save a lot of head-scratching when debugging intermittent cache misses in production.

Follow the source link for the full walkthrough and test outputs.

Source: Apps Script CacheService Limits โ€” Justin Poehnelt

Mark AI Agent OAuth Clients as Agentic for Google Workspace MCP by November 11, 2026

We will soon roll out Google Workspace Model Context Protocol (MCP) servers that expose new functionality to external AI agents across Gmail, Drive, Calendar, and other Workspace apps using the open MCP. Ahead of this launch, we are introducing an โ€œagenticโ€ setting (is_agentic) on Google OAuth clients, so that Google and Workspace administrators can differentiate AI agent traffic from traditional app traffic. Only OAuth clients marked as agentic will be able to call Workspace MCP servers. [emphasis mine]

In our recent review of the Q3 2026 Google Workspace Developer Release Notes, we looked at the expansion of remote Google Workspace MCP servers across Gmail, Drive, Docs, Sheets, Slides, Calendar, and Chat. At the time, I noted that while MCP is great for connecting local developer tools like Google Antigravity, giving external agents broad access across user documents raises real enterprise governance questions.

Google has now started sending developer notifications announcing a foundational change to address this, a mandatory agentic classification (is_agentic) for OAuth 2.0 clients. If you have configured OAuth clients in the Google Cloud console for AI agents or MCP servers, there is a tight one-month window to update your existing credentials.

A couple of key details and technical requirements from the announcement and the updated Manage OAuth Clients documentation are worth highlighting:

  • Hard Enforcement and Permanent Lock-In (November 11โ€“12, 2026): Starting October 12, 2026, developers can edit existing OAuth clients in the Google Cloud console (Google Auth Platform > Clients) and select the Use this client for an AI-powered agent checkbox. On November 11, 2026, Workspace MCP servers will begin rejecting requests from any OAuth client not marked as agentic. Crucially, on November 12, 2026, the is_agentic setting becomes permanent on existing clients, if you miss the November 11 window, you cannot toggle the setting on an existing client and will have to create a new OAuth Client ID and update your client configurations (such as ~/.gemini/config/mcp_config.json in Google Antigravity).
  • Separate OAuth Clients for Human vs. Agent Traffic: According to Googleโ€™s updated best practices for agent client isolation, if your solution provides both human-interactive features (calling standard Google REST APIs) and AI agent workflows, you must maintain separate OAuth 2.0 Client IDs for each workflow. Tagging an OAuth client as agentic does not grant extra scopes or bypass user consent, but it isolates agent traffic so Workspace administrators can apply dedicated agent access controls and security policies without disrupting human users on your standard app.
  • Traditional Apps Script and REST Integrations Are Unaffected: If your application or Apps Script project is not an AI agent and only calls standard Google Workspace REST APIs, no action is required. However, Google recommends marking any OAuth client used by an AI agent, even if that agent currently only calls Workspace REST APIs, so it is properly classified ahead of the November 12 lock-in. Romain Vialard has however highlighted that the client ID for Apps Script is not editable in GCP so it’s not possible to mark it as agentic. The only workaround at this point is using a standard GCP, creating your own client ID and using the OAuth2 Apps Script library.

Seeing this land makes a lot of sense. Before enterprise admins can confidently allow MCP integrations or external AI agents in production domains, they need a reliable way in the Admin console and Security Investigation Tool to distinguish an autonomous agent acting on behalf of a user from a conventional web app. Separating those identities at the OAuth client level is the logical first step toward granular agent governance.

If you have existing Google Cloud projects using Workspace MCP servers, Agent Development Kit (ADK) workflows, or Gemini Enterprise connectors, head over to the Google Auth Platform Clients page before 11 November 2026 to review and update your OAuth client settings.

Email Notifications for Impacted Projects: To help, developers should check their inbox for service communications from Google with the subject โ€˜[Action Required] Mark AI agent OAuth clients as agentic for Google Workspace MCP by Nov 11, 2026โ€˜, as these list the affected Google Cloud projects.

Source: Manage OAuth Clients: Configure OAuth Clients for AI Agents โ€” Google Cloud Platform Console Help

Build a Production-Ready Apps Script CI/CD Pipeline with GitHub Actions

In this project, the goal was to build a clean and practical CI/CD setup for Google Apps Script using GitHub Actions… Instead of stopping at a minimal demo, the project was developed into a working example with a real Apps Script automation flow, a GitHub Actions pipeline, a validation step before deployment, a web app health response, and spreadsheet bootstrap logic.

Weโ€™ve covered CI/CD pipelines with GitHub actions before in AppsScriptPulse, but given the advent of AI developer tools, like Google Antigravity, this comprehensive walkthrough and companion GitHub repository from Shivaji Bodkhe is very timely. A couple of architectural choices in Shivajiโ€™s template are particularly worth highlighting, especially for engineering teams seeking to standardize their internal tooling:

  • Pre-Deployment Validation: Rather than treating clasp push as a final deployment step, GitHub Actions separates execution into distinct validate and deploy jobs. There are some nice additions in the validation step including enforcing V8 runtime and Cloud Logging.
  • Credential Handling: Managing clasp credentials in CI often presents security friction. Shivajiโ€™s workflow isolates authentication by storing the contents of ~/.clasprc.json in GitHub Secrets. During the deployment phase, the workflow injects this file and generates a fresh .clasp.json using the secret APPS_SCRIPT_SCRIPT_ID.

As developers increasingly adopt agentic coding assistants like Google Antigravity, having versioned code becomes essential. Beyond individual developer workflows, this pattern opens up powerful opportunities for enterprise governance and team collaboration:

  • Centralized Deployments Without Shared Credentials: Internal automations and domain-wide Workspace Add-ons can be owned by a dedicated service identity (such as [email protected]). Contributors and AI agents submit improvements via standard GitHub Pull Requests, which are deployed without needing direct edit permissions to the script or access to the account credentials.
  • Custom Guardrails: Teams can easily extend Shivajiโ€™s validation step by adding TypeScript checks with @types/google-apps-script or lint rules.

Pipelines like this illustrate how standard software engineering hygiene can be applied directly to Workspace development. Teams looking to move beyond manual browser deployments can fork Shivajiโ€™s sanitized template as a starting foundation. You can inspect the full workflow configuration and template source code on GitHub: shivajibodkhe/google-apps-script-cicd-template

Source: How to Set Up Google Apps Script Deployment from GitHub Actions โ€” Shivaji Bodkhe

AppSheet Custom Steps for Google Workspace Studio

Before we jump in a quick backstory, if nothing else to prove this entire post wasnโ€™t written with Gemini assistance. Just over a year ago I was fortunate to be a Workspace Studio tester (or Flows as was it called then). I was particularly excited by the ability of Extending Google Workspace Flows with Custom Steps using Google Apps Script. As Workspace Studio moved through the Gemini Alpha program to general availability, custom steps disappeared. This is very understandable given Workspace Studio was a new product and Google wanted to make sure users got to access a stable platform. The great news Google has now launched Automate workflows with custom starters and steps, third-party integrations, and webhooks in Workspace Studio.

With custom steps officially back I thought it was revisit an integration I had been experimenting with combining Workspace Studio with AppSheet. The code for this solution is published in the AppSheet Custom Steps for Google Workspace Studio repo and in this post, we’ll walk through:

  1. Why connect Workspace Studio to AppSheet?
  2. A Real-World Example: Intelligent IT Ticket Triage with Gemini & AppSheet
  3. How custom steps are structured in Apps Script (appsscript.json)
  4. The secret sauce: Dynamic schema discovery via Custom Resources
  5. Handling Single vs. Multiple Results: A Two-Tier Approach
  6. Testing & Deployment with Clasp (and the Admin Setting gotcha)
  7. How this project was built using AI coding agents with .agents/ skills

Why Connect Workspace Studio and AppSheet?

Google Workspace Studio is great for automations across Google Workspace allowing you to use Gemini assistance. AppSheet serves as a no-code application platform making it easy to create solutions for your business data. AppSheet Enterprise customers can already use Gemini AI automations to extract, categorise and summarize data, but getting data from a Workspace automation into AppSheet often required intermediary webhooks, custom API scripts, or relying on Google Workspace integrations to Sheets, Forms and Gmail.

With my custom Studio steps, powered by the AppSheet REST API, you have the ability to extend your apps capabilities using the growing list of Workspace Studio starter steps integrating with your AppSheet app to:

  • Add Rows: Directly push structured records into AppSheet tables.
  • Update Rows: Modify records and trigger AppSheet bot workflows in real time.
  • Find Rows: Run AppSheet formula expressions (such as FILTER("Technicians", [On Call] = TRUE)) and feed those records back into downstream Studio steps.

A Real-World Example: Intelligent IT Ticket Triage with Gemini & AppSheet

To see how this works in practice, let’s look at a common scenario, an automated IT helpdesk flow using a slightly modified version of the AppSheet standard IT Ticketing template.

In the IT Ticketing app the schema includes:

  • The Tickets table tracks issues (Issue ID, First Name, Last Name, Email, Description, Symptom, Assigned Tech, Date Created, Resolved).
  • The Technicians table tracks staff (Name, Department, IT Email, On Call boolean, and Can Cover skills: General Issues, Network, Website, Apps). The primary key for this table is IT Email.
  • The Symptoms table stores the allowed categories (Name, Department), used as an AppSheet Ref dropdown in the app.

Rather than forcing users to fill out a form manually or relying on rigid routing rules, we can combine Workspace Studio’s Gmail starter, Gemini steps, and our AppSheet custom steps into an autonomous triage pipeline:

[ Gmail Starter: New Support Email ]
                 โ”‚
                 โ–ผ
[ Step 2 : Find Rows (Fetch On-Call Technicians) ]
                 โ”‚
                 โ–ผ
[ Step 3: Find Rows (Fetch the apps Symptoms list) ]
                 โ”‚
                 โ–ผ
[ Step 4: Extract (Gemini extracts the required data for our app) ]
                 โ”‚
                 โ–ผ
[ Step 5: Add Rows (Create Ticket with Assigned Tech) ]

Step-by-Step Flow Breakdown

  1. Starter (Gmail): Studio listens for incoming emails sent to [email protected] or flagged with [IT Support] in the subject line.
  2. AppSheet Custom Step (Find Rows):
    • Studio queries the Technicians table with the selector:FILTER("Technicians", [On Call] = TRUE)
  3. AppSheet Custom Step (Find Rows):
    • Studio queries the Symptoms table for the current list
  4. Gemini Extract (Smart Triage):
    • Studio passes both the cleaned ticket details, the on-call technician records and our apps symptoms list to Gemini:
  1. AppSheet Custom Step (Add Rows):
    • Studio inserts the new record into Tickets.
    • The step outputs addedRow, immediately exposing newly generated fields (like Ticket ID or calculated dates) for the rest of the flow.
 [
   {
     "Name": "{{Step 1.Starter.Sender Display Name}}",
     "Email": "{{Step 1.Starter.Sender Email}}",
     "Description": "{{Step 4.Gemini.Description}}",
     "Symptom": "{{Step 4.Gemini.Symptom}}",
     "Assigned Tech": "{{Step 4.Gemini.IT Email}}"
   }
 ]

This pattern demonstrates the true power of combining Workspace Studio and AppSheet. Studio orchestrates Workspace events and AI reasoning, while AppSheet provides validated, related business data.


The Anatomy of a Workspace Studio Custom Step

Under the hood, a Workspace Studio custom step is an extension of the Google Workspace Add-on architecture defined in appsscript.json.

Each step declares its inputs, outputs, and two primary Apps Script callback functions:

  1. onConfigFunction: Renders the configuration card displayed in the Studio sidebar when a user selects your step.
  2. onExecuteFunction: Receives input variable bindings at runtime, executes the business logic, and returns output variables back to the flow.

Here is an extract from appsscript.json defining the “Add Rows” step, featuring both bulk JSON outputs and the Dynamic Custom Resource (addedRow):

{
  "id": "appsheet_add_rows",
  "state": "ACTIVE",
  "name": "Add Rows in AppSheet",
  "description": "Adds one or more rows to a specified AppSheet table.",
  "workflowAction": {
    "inputs": [
      { "id": "appId", "cardinality": "SINGLE", "dataType": { "basicType": "STRING" } },
      { "id": "accessKey", "cardinality": "SINGLE", "dataType": { "basicType": "STRING" } },
      { "id": "tableName", "cardinality": "SINGLE", "dataType": { "basicType": "STRING" } },
      { "id": "rowsData", "cardinality": "SINGLE", "dataType": { "basicType": "STRING" } }
    ],
    "outputs": [
      {
        "id": "addedRow",
        "description": "The first newly added row with individual column fields.",
        "cardinality": "SINGLE",
        "dataType": {
          "resourceType": {
            "workflowResourceDefinitionId": "appsheet_row_resource"
          }
        }
      },
      {
        "id": "addedRows",
        "description": "The full rows added, including server-computed values.",
        "cardinality": "SINGLE",
        "dataType": { "basicType": "STRING" }
      }
    ],
    "onConfigFunction": "onConfigAddRows",
    "onExecuteFunction": "onExecuteAddRows"
  }
}

Notice that addedRow has a dataType pointing to appsheet_row_resource. At the top level of addOns.flows, we declare this custom resource alongside a dynamic definition provider:

"workflowResourceDefinitions": [
  {
    "id": "appsheet_row_resource",
    "name": "AppSheet Row",
    "providerFunction": "onDynamicAppSheetRowProvider",
    "resourceType": "DYNAMIC"
  }
],
"dynamicResourceDefinitionProvider": "onDynamicAppSheetRowDefinition"

Dynamic Schema Discovery via Custom Resources

One challenge with database integrations in no-code flow builders is usability. Asking users to hand-write raw JSON payloads or use secondary “Extract” steps to parse out field names isn’t straightforward.

Initially, I tried adding interactive buttons in the configuration card (e.g. a “Fetch Columns” button). However, Google Workspace Studio does not currently display interactive CardService action buttons or in-place card replacement widgets.

Whilst it is not possible to dynamically add input fields to a step, you can dynamically expose the outputs using Dynamic Custom Resources. With Dynamic Custom Resources, you can dynamically update the schemas to define individual column variables automatically.

How it Works Behind the Scenes

  1. Design-Time Schema Introspection (onDynamicAppSheetRowDefinition):
    When the user configures the step in Studio (entering their App ID, Access Key, and Table Name), Studio calls onDynamicAppSheetRowDefinition(e). Apps Script queries AppSheet using TOP(FILTER("Table", TRUE), 1) to discover existing column headers, registering each as an individual ResourceField:
function onDynamicAppSheetRowDefinition(e) {
  const resourceDefinitions = AddOnsResponseService.newDynamicResourceDefinition()
    .setResourceId("appsheet_row_resource");

  const inputs = e.workflow?.resourceFieldsDefinitionRetrieval?.inputs || {};
  const appId = inputs.appId?.stringValues?.[0];
  const accessKey = inputs.accessKey?.stringValues?.[0];
  const tableName = inputs.tableName?.stringValues?.[0];

  if (appId && accessKey && tableName) {
    const AppSheet = new AppSheetApp(appId, accessKey);
    // Fetch schema sample (cached for 6 hours to keep editor fast)
    const sample = AppSheet.Find(tableName, [], { "Selector": `TOP(FILTER("${tableName}", TRUE), 1)` });
    if (sample && sample.length > 0) {
      Object.keys(sample[0]).forEach(colName => {
        resourceDefinitions.addResourceField(
          AddOnsResponseService.newResourceField()
            .setSelector(colName)
            .setDisplayText(colName)
        );
      });
    }
  }

  const workflowAction = AddOnsResponseService.newResourceFieldsDefinitionRetrievedAction()
    .addDynamicResourceDefinition(resourceDefinitions);

  return AddOnsResponseService.newRenderActionBuilder()
    .setHostAppAction(AddOnsResponseService.newHostAppAction().setWorkflowAction(workflowAction))
    .build();
}

  1. Step Execution & Caching (onExecuteFunction):
    When the step runs, it executes the AppSheet API operation, caches the row data in CacheService under a unique UUID ("row_find_" + Utilities.getUuid()), and returns a resource reference variable alongside the standard JSON output:
const variables = {
  "firstRow": AddOnsResponseService.newVariableData().addResourceReference(resourceId),
  "foundRows": AddOnsResponseService.newVariableData().addStringValue(JSON.stringify(foundRows)),
  "rowCount": AddOnsResponseService.newVariableData().addIntegerValue(foundRows.length)
};

  1. Runtime Value Resolution (onDynamicAppSheetRowProvider):
    When a downstream step references a chip like Step 2 > First row > IT Email, Studio calls onDynamicAppSheetRowProvider(e) with the resourceId. The provider grabs the cached row and returns the requested column values on the fly.

Handling Single vs. Multiple Results: A Two-Tier Approach

When building steps that interact with databases, you inevitably face a question: What happens if the query returns one row versus ten rows versus zero rows?

In Google Workspace Studio’s currently, custom resources strictly mandate "cardinality": "SINGLE":

“The output variable has a dataType with the property resourceType. The value of cardinality must be SINGLE.”

Because Studio does not yet support repeated arrays of custom resource chips, our custom steps implement a two-tier output design:

StepOutput VariableType & CardinalityBest ForBehavior
Find RowsfirstRowDynamic Custom Resource (SINGLE)Single result / First matchExposes individual column chips (Email, Name, ID, etc.) directly to downstream steps.
foundRowsString (JSON Array) (SINGLE)Multiple resultsContains the full JSON array [ {...}, {...} ] of all matching rows.
rowCountInteger (SINGLE)Conditionals & branchingThe total number of rows found (0, 1, 5, etc.).
Add RowsaddedRowDynamic Custom Resource (SINGLE)Single record addedExposes column chips of the newly created row (useful for generated IDs or computed columns).
addedRowsString (JSON Array) (SINGLE)Bulk additionsFull JSON array of all rows inserted.
Update RowsupdatedRowDynamic Custom Resource (SINGLE)Single record updatedExposes column chips of the updated record.
updatedRowsString (JSON Array) (SINGLE)Bulk updatesFull JSON array of all updated rows.

How Flows Use This in Practice:

  • Single Record Workflows: Use firstRow, addedRow, or updatedRow chips directly in downstream steps (Gmail, Google Docs, Slack, Chat) without any formula or extraction step. If 0 rows match, chips safely resolve to empty strings ("").
  • Multi-Record Collections: Pass foundRows (JSON string) directly into the rowsData input of another step or iterate over the collection using Studio list actions.
  • Conditional Logic: Add a Studio branch on rowCount > 0 to safeguard downstream actions when records might not exist.

Testing & Deployment with Clasp

Because Studio custom steps run on Google Workspace Add-on infrastructure, testing is fast:

  1. Either Copy with Apps Script project or follow the steps to clone the repo and push via clasp:
  2. Install the Test Deployment: Open the Apps Script project, go to Deploy > Test deployments, select Google Workspace Add-on, and click Install.
  3. Use in Studio: Head to studio.workspace.google.com, add a step to any flow, and search for “AppSheet Utilities for Studio”.

[!IMPORTANT] Admin Setting Required for Google Workspace Accounts:
As announced in the Google Workspace Updates, custom steps are OFF by default for Google Workspace accounts.

If you see a lock icon stating “๐Ÿ”’ Access to these steps is restricted by your Workspace admin”, have a domain admin navigate to:
Google Admin Console > Apps > Google Workspace > Settings for Workspace Studio > Custom steps settings
Turn custom steps ON and check “Allow unpublished (test) custom steps”.

AI-Assisted Development with .agents/

An interesting aspect of developing for newly released or evolving APIs like Workspace Studio is that public LLMs often have knowledge cutoffs or hallucinate manifest formats and Card Service specifications.

To build this project efficiently, the repository includes a curated .agents/ directory containing specialized runbooks, rules, and reference specs:

  • Contract Parity: Enforces that input/output IDs in appsscript.json match Code.js execution handlers.
  • Real-time API Adaptation: When testing revealed that Studio sidebar cards don’t render interactive card buttons, the agent used the reference docs to quickly pivot to native Dynamic Custom Resources (dynamicResourceDefinitionProvider).
  • Platform Constraints: Encodes crucial platform invariantsโ€”like the requirement that dataType.resourceType outputs mandate "cardinality": "SINGLE"โ€”saving hours of trial and error.
  • AppSheet Selectors: Pre-validated AppSheet formula expressions (FILTER, SELECT, TOP) for REST API calls.

When working with tools like Gemini Code Assist or AI coding agents, these in-repo skills guide the model to write accurate, production-ready code on the first attempt and navigate rapid API evolutions.

Summary and Next Steps

Having custom steps and starters back in Workspace Studio opens up huge possibilities for developers. Google Apps Script acts as the glue code, letting you build custom integrations for internal systems, specialized SaaS platforms, or databases like AppSheet.

You can find the complete source code and clasp setup instructions on GitHub: ๐Ÿ‘‰ mhawksey/appsheet-custom-studio-step-example

Scale a 3,000-user web app on Google Apps Script and Google Sheets

I built a web application used by more than 3,000 people. The backend was Google Apps Script. It ran for almost two years while we kept improving the application. We eventually moved it to AWS โ€” not because Apps Script couldnโ€™t handle the application, but because changes around Googleโ€™s authentication model gave us the opportunity to move to a more conventional backend and database architecture. Hereโ€™s how I built it, what problems we ran into, and why we didnโ€™t build a traditional backend from the beginning.

In Pulse weโ€™ve featured a couple of examples and tips on scaling Apps Script Web Apps. One of the most extensive solutions weโ€™ve shared is Zig Mandelโ€™s open-source Apps Script Website Integration Framework. Partha Sahoo has recently shared how his team used Google Sheets and Google Apps Script to develop a client facing frontend for over 3,000 users. The model they adopted is one Iโ€™ve not seen before. Itโ€™s a clever distributed model which combines a central database and script library with individual Google Sheets and Web Apps for each client. With this model workloads are shared across individual web apps:

There are some clever features in this solution which you can get an overview of in Parthaโ€™s post. A couple I would like to highlight are:

  • Exponential Backoff Polling: To stay comfortably below Apps Scriptโ€™s quotas, the frontend avoided aggressive continuous polling. The client would initially poll every 5 minutes and if there were no changes to the data scaled down via exponential backoff to 30 minutes.
  • Central Library Multi-Tenancy: To avoid the burden of maintaining hundreds of individual web app deployments, core business logic lives in a versioned central Apps Script library (paired with a staging library for testing). This allowed Sahoo to ship bug fixes and feature rollouts fleet-wide instantly without redeploying individual client projects.

After nearly two years in production, the platform migrated to AWS. As Partha explains, the move was not driven by Apps Script reaching an operational bottleneck, but by evolving Google Workspace authentication policies, which made a conventional cloud backend more practical for long-term compliance. As noted in Parthaโ€™s post, the migration of the Apps Script code to AWS was easily refactored with AI assistance.

Weโ€™re in interesting times. On the one hand the beta Gemini side panel in the Apps Script Editor makes it easy to deploy web apps, on the other tools like Google AI Studio make it easy to vibe code applications to run in Googleโ€™s cloud infrastructure. Both introduce new risks, but also opportunities.

Source: How I Built a 3,000-User Web Application With Google Apps Script | by Partha S Sahoo | Sep, 2026 | Medium

Google Workspace Developer Release Notes Q3 2026: The Shift Toward Agentic Collaboration

Looking across the Google Workspace developer release notes throughout 2026 it looks like there is a strategic evolution with moves to make Google Workspace an agent-ready, collaborative platform. Three areas stand out: standardising external agent integration via MCP, APIs to allow agents to comment and suggest, and expanding Google Chat into an interactive operational hub.

1. Standardising Agent Integration via MCP: But Is It the Right Model?

Following the initial rollout of Chat and Gmail Model Context Protocol (MCP) servers in Q2, Q3 expanded remote MCP servers to Google Docs, Sheets, and Slides (alongside new membership and read-state tools in Chat). The promise of MCP is attractive, providing a standardised connector that allows AI agents to query and manipulate Workspace resources as the user.

However, as the broader tech community is increasingly pointing out, MCP raises serious architectural and security questions in enterprise environments. I feel while MCP excels as a developer protocol for local sandboxes, questions remain whether this is the right abstraction for enterprise workspaces. Giving an external agent broad access across entire document trees for me creates an uncomfortable blast radius. 

2. Programmatic Collaboration: AI & Bots Entering the Review Loop

Historically, Workspace APIs focused on inserting and editing document content. Recently new APIs are unlocking the entire editorial feedback layer with programmaticย comments and suggestionsย across theย Docs,ย Sheets, andย Slidesย APIs. This is a major enhancement for AI copy-editing solutions. Bots and agents no longer have to overwrite or add content, they can suggest changes and leave contextual comments for human approval.

3. Google Chat as the Universal Workflow Hub

Google Chat received major quality-of-life upgrades in Q3, includingย native Markdown formattingย (MARKUP_SYNTAX_MARKDOWN), interactiveย citations and footer sources, context-menuย message actions, and simplified read-only OAuth (GCP not required). This lowers integration friction for internal tools while elevating Chat bots into interactive enterprise assistants.

Gemini Side Panel in the Apps Script Editor (Beta)

Outside of these three areas Q3 also saw the release of the Gemini side panel in the Apps Script editor. This development is making it easier for users to collaborate with Gemini to author solutions with context or the document and other script files in your project. One area I see this already being beneficial is co-author Workspace and Editor Add-ons with Gemini. This allows businesses to deploy domain solutions in a managed way.

Summary

Q3 2026 for me marks a decisive shift from data manipulation to agent-ready co-authoring across Google Workspace. Between standardized MCP server endpoints, non-destructive suggestion APIs, and upgraded Chat interactivity, it looks like the platform is laying the groundwork for agentic collaboration.

Explore the full list of changes and migration guides on the official release notes page, or subscribe to the feed to stay informed on upcoming releases.

Source:ย Google Workspace developer release notes โ€” Google Workspace Developers

Breaking the Limits of Apps Script: Kanshi Tanaike on Direct Cloud-to-Cloud Streaming with Gemini Managed Agents

While Google Apps Script (GAS) is a powerful tool for Google Workspace automation, platform and computational constraints often limit its ability to handle advanced workloads. Gemini Managed Agents provide remote Linux sandboxes equipped with bash execution. This article introduces an architecture integrating GAS with a Linux sandbox to execute tasks beyond the capabilities of Apps Script alone. By streaming generated artifacts directly from within the Linux sandbox to Google Drive, this approach bypasses API payload limits, eliminates token overhead, and achieves high-throughput cloud automation.

Following on from our recent post exploring Gemini Managed Agents and the Google Workspace CLI, Google Developer Expert Kanshi Tanaike has shared a number of examples of how Gemini Managed Agents can be used to overcome some of the limitations of Google Apps Script. The cornerstone of these solutions is leaning into the dedicated Linux sandbox created with Managed Agents and using ggsrun CLI tool to enable direct cloud-to-cloud streaming between the sandbox and Google Drive, negating any limitations with UrlFetchApp.

Some key highlights from Tanaike’s post are:

  • Heavy Compute Offloading: Offloads tasks impossible in Apps Script such as dynamic screenshots and JSON data generation with Playwright, audio synthesis with FFmpeg, and TypeScript compilation viaย esbuild.
  • Persistent Multi-Client Sandboxes: A single sandbox (environmentId) can be shared across Apps Script triggers and local Node.js workstations, preserving pre-installed toolchains and shared datasets.
  • Proven Performance Gains: Avoiding 50 MB response payload limits by streaming binary artifacts directly to Drive at high speeds.

Follow the source link for the complete technical breakdown and benchmark data.

Source: Taking Advantage of Gemini Managed Agents with Google Apps Script โ€” Kanshi Tanaike

Gemini in the Apps Script IDE: 8 Practical Developer Workflows by Stรฉphane Giron

Summer 2026 has been huge for Google Apps Script developers, marked by two major milestones. First, Apps Script officially graduated to a Google Workspace Core Service … Second, Gemini is now natively integrated into the Apps Script IDE side panel. No more juggling browser tabs, context-switching to Google AI Studio, or copy-pasting prompts back and forth. To help you take full advantage of this workflow upgrade, here are 8 things you can do with Gemini directly inside Apps Script.

In August we highlighted the news Google Apps Script Editor: Gemini Side Panel Rolling Out!. This is a major feature update and as part of the beta you can read the latest information on Google’s Use the Gemini side panel in the Apps Script editor support page. A couple of requirements to headline.

Consumer accounts

  1. You have Google AI Pro / Ultra subscription
  2. Your account language is set to English

Google Workspace account

  1. The account has a Business Standard, Business Plus, Enterprise Standard, Enterprise Plus, Workspace Gemini Add-on, or Google AI Pro for Education licence
  2. Your account has been included in theย Gemini Beta programย by your admin
  3. Your account language is set to English

If you do have access to this feature then Stรฉphane Giron highlights 8 quick tips for getting started with Gemini in the side panel. These include:

  • Full project scaffolding & modification: Prompting Gemini to create multi-file architectures from scratch (such as generating pairedย .gsย script logic andย EmailTemplate.htmlย templates).
  • Modernizing legacy code: Refactoring large script projects into clean, modular files with improved helper functions and error handling.
  • Language translation & unit tests: Converting legacy VBA macros automations directly into Apps Script, as well as creating automated unit tests.
  • One-click log debugging: A standout feature – clicking a button directly within execution logs to have Gemini diagnose and propose fixes for errors on the spot.

Follow the source link to explore Stรฉphane’s full walkthrough and visual breakdown of each prompt in action.

Source: Google Apps Script just got Gemini: 8 practical ways to use it in IDE โ€” Stรฉphane Giron

Adding a Spark of Intelligence to Google Workspace: Exploring Gemini Managed Agents and the Google Workspace CLI

Gemini Spark, announced at Google I/O 2026, was launched as “your 24/7 personal AI agent that helps you work more efficiently by autonomously taking action on your behalf, under your direction… Spark operates in a fully managed, secure runtime on Google Cloud, meaning you get enterprise-grade security without ever having to manage the underlying infrastructure.”

If you have access to Gemini Spark, you will already know it has deep integrations to read and write your Google Workspace data. Like most of Google’s products, the infrastructure used by Gemini Spark is also accessible to developers. In the case of Gemini Spark, a key component is Managed Agents:

Managed agents on the Gemini API give you a configurable agent harness. A single API call provisions a Linux sandbox where the agent reasons, executes code, manages files, and browses the web autonomously.

The particular flavour of Managed Agents I was interested in was:

Antigravity agent: General-purpose managed agent powered by Gemini 3.7 Flash. Runs code, manages files, and searches the web inside a secure Linux sandbox hosted by Google. You can extend it with your own instructions, skills, and data to build a custom agent.

To replicate Gemini Spark’s integration with Google Workspace, this demo project installs the Google Workspace CLI (gws) into an agent orchestrated from a Google Apps Script web app.

Turning Raw Drive Docs into Executive Briefings

The setup is deliberately modest. Imagine a Google Drive folder containing raw Google Docs. in my case, copies of Google Workspace Updates and Gemini Enterprise announcements. I want to convert this growing folder into structured, evidence-backed briefings for Workspace developers and business stakeholders, a clean source register, and visual summaries.

Setup

This repo has all the code you need to deploy this demo. In terms of what it does:

  1. An Apps Script web app runs as the accessing user.
  2. The user supplies a source folder ID and an output folder ID.
  3. Apps Script starts a Managed Agent interaction.
  4. A virtual environment is prepared with:
    • the gws Google Workspace CLI;
    • a Python document and analysis toolchain including python-pptx, python-docx, matplotlib, and pandas;
    • an agent policy (AGENTS.md) and workflow skill (SKILL.md);
    • a per-run .env file containing the current user’s OAuth access token, approved folder IDs, and optional date timestamps.
  5. The agent accesses Drive through gws to find and retrieve relevant source documents using server-side queries.
  6. It generates multi-format deliverables (Word, PowerPoint, chart, CSV) locally in /workspace/output.
  7. It uploads the final reports to the selected output folder.

One of the biggest advantages of a Managed Agent over a basic API call is the ability to provision a full Linux sandbox, preconfigured with Python 3.12 and Node.js 22. You can also install additional libraries and binaries dynamically. In this project, the agent creates the following outputs before uploading them:

Output AssetTooling / LibrariesPre-installed vs. RuntimePurpose
source-register.csvpandasPre-installedAggregates metadata, sorts, and filters document sources.
updates-summary-chart.pngmatplotlibInstalled via pipVisualizes update frequencies and product area breakdowns.
executive-presentation.pptxpython-pptxInstalled via pipCompiles an executive presentation deck formatted into structured slides.
executive-briefing.docxpython-docxInstalled via pipGenerates a styled Word document with headers, callouts, and structured tables.
executive-briefing.mdPlain Text / MarkdownNative FilesystemProvides a lightweight narrative briefing summary.
run-manifest.jsonJSON / jqPre-installedAudit record of all actions taken during the run.

Screenshots

Creating a Managed Agent

To allow the agent to interact with Drive on the user’s behalf without an interactive login prompt, Apps Script fetches the user’s OAuth token:

const userToken = ScriptApp.getOAuthToken();

To limit the potential blast radius, the appsscript.json manifest strictly scopes requested permissions:

{
  "oauthScopes": [
    "https://www.googleapis.com/auth/script.external_request",
    "https://www.googleapis.com/auth/drive.readonly",
    "https://www.googleapis.com/auth/drive.file"
  ]
}

Using drive.file ensures that write access is scoped strictly to files created or explicitly opened by the application, preventing modification of other Google Drive files.

Seamless Credential Delegation to gws

A common challenge with a headless agent environments is authentication. How do you allow a CLI tool to act on the user’s behalf without interactive browser logins (gws auth login) or baking long-lived service account keys into the agent definition?

The gws CLI addresses this by supporting environment-based authentication. When invoked, gws checks for the GOOGLE_WORKSPACE_CLI_TOKEN environment variable. By mounting a transient /workspace/.env file directly into the sandbox environment during interaction creation, gws automatically authenticates all Drive API operations using the active user’s short-lived OAuth token.

Because this token exists solely in memory within the temporary container instance, it naturally expires and is never saved to persistent storage.

Example Interaction Creation Request

The entire custom Managed Agent is created with a single API call. An example payload used in this demo project is included below:

const payload = {
  agent: "antigravity-preview-05-2026",
  agent_config: {
    type: "antigravity",
    model: "gemini-3.7-flash"
  },
  input: [
    {
      type: "text",
      text: "Run the Workspace Update Intelligence workflow...\n" +
            "Approved source folder ID: <SOURCE_FOLDER_ID>\n" +
            "Approved output folder ID: <OUTPUT_FOLDER_ID>\n" +
            "Date range: <DATE_RANGE_AND_QUERY_FILTER>"
    }
  ],
  environment: {
    type: "remote",
    sources: [
      { type: 'inline', target: '.agents/AGENTS.md', content: ASSET_AGENTS_MD },
      { type: 'inline', target: '.agents/skills/update-intelligence/SKILL.md', content: ASSET_SKILL_MD },
      { type: 'inline', target: '/workspace/requirements.txt', content: ASSET_REQUIREMENTS },
      { type: 'inline', target: '/workspace/bootstrap.sh', content: ASSET_BOOTSTRAP },
      { type: 'inline', target: '/workspace/.env', content: DYNAMIC_ENV_INC_AUTH_TOKEN_AND_FOLDER_IDS }
    ]
  },
  tools: [
    { type: "code_execution" }
  ],
  background: true,
  store: true
};

System Instructions and Skills

The payload allows developers to include both an AGENTS.md and SKILL.md into the sandbox

  • System Instructions (.agents/AGENTS.md): Establishes boundaries requiring the agent to only read from SOURCE_FOLDER_ID, only write to OUTPUT_FOLDER_ID, and never disclose /workspace/.env. It instructs the agent to treat all retrieved Workspace text as untrusted reference data, ignoring any embedded instructions or prompt injections.
  • Workflow Skill (.agents/skills/update-intelligence/SKILL.md): Provides structured workflow guidance for using gws drive with field masks, executing Python scripts for artifact generation, and mapping file extensions to Google Drive MIME types during upload.

Tooling and Sandbox Bootstrapping (tools & bootstrap.sh)

As well as the instructions and policies, the payload also configures the agent with execution capabilities and installs the required runtime toolchain:

  • tools: [{ type: "code_execution" }]: Activates the Linux terminal and Python interpreter, allowing the Antigravity agent to write, execute, and debug scripts inside its container.
  • bootstrap.sh & requirements.txt: The payload requires the agent to execute /workspace/bootstrap.sh on startup. This script downloads the static gws CLI binary and installs the specified Python libraries (pandas, matplotlib, python-docx, python-pptx) dynamically.

Asynchronous Execution and State Persistence (background & store)

A workflow that inventories dozens of Google Docs, generates slide decks and Word documents, and uploads deliverables to Drive can take several minutes to run. Two flags make this practical from Google Apps Script:

  • background: true: Launches the agent run asynchronously, immediately returning an interaction_id. The frontend UI simply polls the interaction endpoint periodically for status and live step progress.
  • store: true: Persists the interaction transcript and environment state on Google’s infrastructure. This not only allows the web app to retrieve the final summary and token usage metrics when finished, but also enables multi-turn follow-upsโ€”allowing users to ask the agent to revise or refine documents within the same container without re-bootstrapping.

Summary and References

Combining Managed Agents with the Google Workspace CLI unlocks opportunities to automate complex, multi-step document workflows. Combining the latest Gemini models via the Antigravity agent with a full 4 vCPU / 16 GB Linux sandbox gives developers the ability to build capable autonomous agent workflows directly from Google Apps Script.

The flip side of this, particularly with recent news stories of agents escaping sandboxes, is the implication of providing managed agents with a user token. This is no different from the OAuth token flow already used when extending applications; the difference here is that it is being passed to an agent that can “think” and “reason”. In Google Workspace, it is positive to see that agentic security and governance is being surfaced to administrators for built-in services, but it feels to me that the protocols and standards are still catching up. For users, my advice is to pause and think before you click continue in authentication flows.

A reminder that all the demo project code is in the Adding a Spark of Intelligence to Google Workspace Development: Exploring Gemini Managed Agents in Google Apps Script Repo.

Additional documentation links:

Special thanks to Ryota Tokodai (ryotat7) whose early work inspired this experimental architecture.