<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Tanaike</title>
    <description>The latest articles on Forem by Tanaike (@tanaike).</description>
    <link>https://forem.com/tanaike</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3701430%2F3d517296-9b96-418b-ad29-24e735edd1df.png</url>
      <title>Forem: Tanaike</title>
      <link>https://forem.com/tanaike</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/tanaike"/>
    <language>en</language>
    <item>
      <title>Next-Generation Google Workspace Automation</title>
      <dc:creator>Tanaike</dc:creator>
      <pubDate>Mon, 27 Apr 2026 01:52:43 +0000</pubDate>
      <link>https://forem.com/gde/next-generation-google-workspace-automation-1h22</link>
      <guid>https://forem.com/gde/next-generation-google-workspace-automation-1h22</guid>
      <description>&lt;p&gt;&lt;strong&gt;A Comparative Study of Agentic Frameworks and Multi-Agent Orchestration&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Abstract
&lt;/h2&gt;

&lt;p&gt;The transition from passive chatbots to autonomous execution environments was cemented at Google Cloud Next '26 with the introduction of the Gemini Enterprise Agent Platform. This paper evaluates four cutting-edge AI agent methodologies for Google Workspace automation, developed by leading developers Martin Hawksey, Bruce Mcpherson, and Kanshi Tanaike. We deconstruct their structural approaches—CLI skill chaining, advanced emulation sandboxing, dynamic code generation, and A2A remote delegation—demonstrating how these community-driven innovations anticipated native Next '26 features like the official Agent Skills repository and Model Context Protocol (MCP) support. Building upon these foundations, we propose two novel frameworks: the Federated Context-Aware Routing Architecture (Federated CARA) for zero-trust, multi-cloud task routing, and the Self-Optimizing Tool Caching Network (SOTCN) to eliminate Tool Space Interference using dynamic semantic caching. This comparative synthesis maps existing and proposed models against Google's new enterprise standards, offering a scalable roadmap for secure, highly dynamic multi-agent orchestration.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Introduction
&lt;/h2&gt;

&lt;p&gt;Historically, automating tasks within Google Workspace relied heavily on static, hardcoded macros defined via Google Apps Script (GAS) and rigidly scheduled cloud triggers. While highly effective for predictable workflows, this paradigm lacked the adaptability required for complex, context-dependent enterprise operations. The advent of Large Language Models (LLMs) catalyzed the transition toward the "Agentic Enterprise," wherein AI entities act as autonomous orchestration layers capable of interacting dynamically with vast API ecosystems. At Google Cloud Next '26, this shift was cemented through the introduction of &lt;em&gt;Workspace Intelligence&lt;/em&gt;, a semantic unifying layer that allows agents to autonomously execute multi-step tasks across Gmail, Docs, Sheets, and Drive without manual context provisioning.&lt;/p&gt;

&lt;p&gt;However, bridging LLM reasoning engines with Google Workspace APIs introduces profound architectural challenges, notably regarding execution latency, security perimeters, and Tool Space Interference (TSI). TSI—officially recognized by Google as "context bloat"—is a phenomenon where an agent's reasoning accuracy degrades, and token costs skyrocket, when its context window is overloaded with a massive library of predefined functions.&lt;/p&gt;

&lt;p&gt;This paper analyzes four prominent, recently published developer methodologies that sought to solve these challenges before they were addressed natively. By evaluating these frameworks against Next '26 announcements like the &lt;em&gt;GKE Agent Sandbox&lt;/em&gt; , native &lt;em&gt;Agent Registry&lt;/em&gt; , and the &lt;em&gt;Agent Gateway&lt;/em&gt;, we identify key strengths and limitations. Subsequently, we propose advanced hybrid frameworks—Federated CARA and SOTCN—tailored to leverage Google's new native security and orchestration layers for the next generation of highly secure, scalable enterprise deployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Architectural Analysis of Existing Methodologies
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn9j75q1kzurknjt6jjzf.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn9j75q1kzurknjt6jjzf.jpg" alt="Architectural Analysis of Existing 4 Methodologies" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The automation of Google Workspace using AI agents is an emerging field characterized by highly divergent architectural philosophies. The following sections provide an exhaustive deconstruction of four primary paradigms.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.1 Skill-Based Prototyping Using CLI Integrations (Martin Hawksey)
&lt;/h3&gt;

&lt;p&gt;Ref: &lt;a href="https://www.linkedin.com/pulse/exploring-workspace-intelligence-skills-using-cli-gemini-hawksey-kqihe/" rel="noopener noreferrer"&gt;Exploring Workspace Intelligence Skills using the Workspace CLI and Gemini CLIs with Apps Script API Executables&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ref: &lt;a href="https://github.com/mhawksey/gws-web-to-doc/" rel="noopener noreferrer"&gt;gws-web-to-doc&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Martin Hawksey’s project (&lt;code&gt;gws-web-to-doc&lt;/code&gt;) demonstrates how discrete, legacy command-line tools can be wrapped into modular AI skills. By combining local Node.js execution with the Google Workspace CLI (&lt;code&gt;gws&lt;/code&gt;) and remote GAS deployment, Hawksey creates a linear execution pipeline. For instance, in his "Web-to-Doc" workflow, local scripts extract web content, the CLI natively converts the Markdown to a Google Document, and an API Executable GAS script (&lt;code&gt;resizer.gs&lt;/code&gt;) handles precise image formatting.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Primary Strength:&lt;/strong&gt; Excellently bridges legacy scripting and modern LLM orchestration, making isolated tasks readily accessible to AI.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2.2 Local Natural Language Execution via Emulation (Bruce Mcpherson)
&lt;/h3&gt;

&lt;p&gt;Ref: &lt;a href="https://ramblings.mcpher.com/gas-fakes-agent/" rel="noopener noreferrer"&gt;gas-fakes agent: local natural language requests against workspace resources&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ref: &lt;a href="https://github.com/brucemcpherson/gas-fakes/tree/main/gf_agent" rel="noopener noreferrer"&gt;gf_agent - Google Apps Script Local Automation Agent&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bruce Mcpherson addresses iteration latency and cloud security through his &lt;code&gt;gas-fakes-agent&lt;/code&gt; framework. By utilizing the &lt;code&gt;gas-fakes&lt;/code&gt; emulation layer, Mcpherson enables an LLM to dynamically generate GAS syntax and execute it within a Node.js environment that can be run locally or containerized in any cloud platform. Because it uses Google APIs under the hood, standard network and API latencies still apply, and the files manipulated remain cloud-based just like native GAS. The framework is highly versatile—it can be deployed across multiple cloud platforms (aligning with the modern emphasis on sovereign clouds) and can operate and mix multiple backends, such as Microsoft OneDrive and Office files. Crucially, the &lt;code&gt;gf_agent&lt;/code&gt; approach is made possible by continuous learning from over 10,000 tests that &lt;code&gt;gas-fakes&lt;/code&gt; uses to ensure its consistency with live Apps Script. This foundation allows the agent to self-augment through continuous cyclical feedback as new methods are introduced.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Primary Strength:&lt;/strong&gt; Advanced execution sandboxing and robust permission management. Its security paradigm emphasizes secure sandboxing rather than authentication per se. While it utilizes the same authentication mechanisms available to any OAuth2 protected app—such as Application Default Credentials (ADC), Domain Wide Delegation (DWD), and keyless workload identity federation—it uniquely takes care of the permission complications associated with them. Furthermore, its native compatibility with the Model Context Protocol (MCP) sets a standardized foundation for AI-to-tool interfacing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2.3 Dynamic Tool Creation to Combat Tool Space Interference (Kanshi Tanaike)
&lt;/h3&gt;

&lt;p&gt;Ref: &lt;a href="https://medium.com/google-cloud/empowering-autonomous-ai-agents-through-dynamic-tool-creation-550683f255a4" rel="noopener noreferrer"&gt;Empowering Autonomous AI Agents through Dynamic Tool Creation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ref: &lt;a href="https://github.com/tanaikech/autonomous-google-workspace-agent" rel="noopener noreferrer"&gt;autonomous-google-workspace-agent&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To solve the cognitive bottleneck of Tool Space Interference (TSI) in enterprise LLMs, Kanshi Tanaike’s &lt;code&gt;autonomous-google-workspace-agent&lt;/code&gt; introduces a fully autonomous, self-healing multi-agent architecture. When faced with an edge case lacking a predefined solution, a Senior Orchestrator coordinates five sub-agents (Environment Checker, Script Writer, Script Executor, Script Uploader, and Summary Agent) to write, sandbox-test (using &lt;code&gt;gas-fakes&lt;/code&gt;), deploy (via &lt;code&gt;clasp&lt;/code&gt;), and execute custom tools in real-time.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Primary Strength:&lt;/strong&gt; Fundamentally eliminates TSI by relying on dynamic tool generation rather than a saturated context window. It serves as a secure "kill switch" against reasoning drift by isolating untrusted code generation within a sandbox before cloud deployment.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2.4 Remote Subagent Integration via the A2A Protocol (Kanshi Tanaike)
&lt;/h3&gt;

&lt;p&gt;Ref: &lt;a href="https://medium.com/google-cloud/integrating-remote-subagents-built-by-google-apps-script-with-gemini-cli-0ee6b54a658d" rel="noopener noreferrer"&gt;Integrating Remote Subagents Built by Google Apps Script with Gemini CLI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ref: &lt;a href="https://github.com/tanaikech/gemini-cli-gas-a2a-subagents" rel="noopener noreferrer"&gt;gemini-cli-gas-a2a-subagents&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In a subsequent approach (&lt;code&gt;gemini-cli-gas-a2a-subagents&lt;/code&gt;), Tanaike solves TSI through remote delegation rather than dynamic generation. A primary LLM offloads a massive repository of over 160 established Workspace skills to a specialized Google Apps Script Web App using the Agent-to-Agent (A2A) protocol. Tanaike elegantly bypasses strict Google Cloud cross-domain (CORS) authentication hurdles by predefining "agent cards" locally within the Gemini CLI.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Primary Strength:&lt;/strong&gt; Preserves the primary agent's reasoning stability without the compute overhead of writing new code, allowing frictionless access to massive legacy macro libraries.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Proposed Novel Methodologies for Advanced Workspace Automation
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxhyw4r5r4mxhksvww64u.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxhyw4r5r4mxhksvww64u.jpg" alt="Proposed Novel 2 Methodologies for Advanced Workspace Automation" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Based on the strengths and limitations of the analyzed frameworks, and aligning with the latest native paradigms introduced at Google Cloud Next '26, we propose two novel architectural approaches intended for advanced enterprise use cases.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.1 Federated Context-Aware Routing Architecture (Federated CARA)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Concept:&lt;/strong&gt; A zero-trust hybrid orchestration network that dynamically routes AI tasks based on a real-time assessment of data sensitivity, computational demand, and cross-platform interoperability requirements.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Architecture:&lt;/strong&gt; A central LLM routing agent acts as a security triage engine. If a natural language prompt involves sensitive organizational data or requires orchestration across mixed backends (e.g., interacting simultaneously with Google Workspace and Microsoft OneDrive), the orchestrator routes the execution to an &lt;strong&gt;advanced sandboxed emulation layer&lt;/strong&gt;. Synthesizing Mcpherson's &lt;code&gt;gas-fakes&lt;/code&gt; approach, this layer utilizes keyless workload identity federation and Application Default Credentials (ADC) to securely manage complex permissions. It natively supports multi-cloud deployments—including sovereign clouds—ensuring that while external APIs are accessed under the hood, the execution environment itself remains strictly controlled and continuously validated through self-augmenting feedback loops. Conversely, if the task requires heavy bulk processing over established legacy macros, the execution is delegated to a &lt;strong&gt;remote A2A subagent&lt;/strong&gt; (synthesizing Tanaike's Web App protocol).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Enterprise Value:&lt;/strong&gt; Maximizes cross-platform versatility and infrastructure flexibility while enforcing strict compliance and data governance perimeters. By focusing on advanced execution sandboxing rather than relying solely on traditional authentication barriers, it securely bridges distinct enterprise ecosystems.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3.2 Self-Optimizing Tool Caching Network (SOTCN)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Concept:&lt;/strong&gt; An advanced solution to Tool Space Interference (TSI) that bridges the gap between dynamic code creation, static remote delegation, and newly standardized enterprise skill registries.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Architecture:&lt;/strong&gt; Instead of writing code from scratch (which incurs API latency) or loading 160+ tools simultaneously (which inevitably degrades LLM reasoning), the SOTCN utilizes a massive "cold storage" repository of pre-validated scripts. Crucially, this architecture is designed to integrate seamlessly with Google's newly announced official &lt;strong&gt;Agent Skills repository&lt;/strong&gt;. By treating both officially published Agent Skills and custom-built Workspace scripts as modular assets, SOTCN acts as a dynamic curator. When a user issues a command, an ultra-fast semantic vector search identifies the top 3–5 most relevant skills. A local "Injection Agent" then dynamically injects &lt;em&gt;only&lt;/em&gt; those specific functions into the primary LLM's active Model Context Protocol (MCP) context window for the duration of that specific session.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Enterprise Value:&lt;/strong&gt; Eliminates TSI entirely by maintaining a pristine, minimal active context window. By leveraging both community-driven repositories and official Google Agent Skills, SOTCN avoids the latency and debugging failure rates of real-time code generation while effectively future-proofing enterprise deployments against evolving native ecosystem standards.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Comparative Analysis
&lt;/h2&gt;

&lt;p&gt;The table below synthesizes the structural and functional nuances of the four original methodologies alongside our two newly proposed frameworks.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Discussion and Conclusion
&lt;/h2&gt;

&lt;p&gt;The evolution of Google Workspace automation reflects a broader industry shift toward "Agentic" design. Hawksey’s foundational work establishes how legacy scripts can be seamlessly bridged to LLMs, preempting Google's recent Next '26 announcement of the official Agent Skills repository. Mcpherson's integration of the &lt;code&gt;gas-fakes&lt;/code&gt; emulation layer combined with the Model Context Protocol (MCP) redefines enterprise security and interoperability. Rather than simply isolating execution, Mcpherson demonstrates how advanced sandboxing, managed via mechanisms like keyless workload identity federation, enables multi-cloud versatility (supporting sovereign clouds) and cross-platform backend integration (e.g., Microsoft OneDrive). Furthermore, powered by continuous learning from over 10,000 tests, this approach proves that agents can reliably self-augment through cyclical feedback. Tanaike pushes the envelope of scalability; his dual approaches to Tool Space Interference (TSI) demonstrate that AI systems must either possess the autonomy to self-generate capabilities or the communicative protocols (A2A) to delegate them.&lt;/p&gt;

&lt;p&gt;The proposed frameworks, Federated CARA and SOTCN, represent the logical next steps in this evolution, deeply aligning with the latest native Google Cloud capabilities. In particular, the SOTCN methodology provides a powerful extension to Google's newly introduced Agent Skills paradigm by offering a semantic caching mechanism that programmatically eliminates context bloat while standardizing tool invocation. By optimizing for latency, context window preservation, multi-cloud versatility, and strict data compliance, these advanced methodologies outline a robust, future-proof roadmap for deploying enterprise-grade, autonomous AI coworkers that are as reliable as they are dynamic.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Evolution of Automation:&lt;/strong&gt; Workspace automation has officially shifted from rigid Google Apps Script macros to the "Agentic Era," powered by the new Gemini Enterprise Agent Platform, which natively supports the building, scaling, and governance of autonomous agents.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skill Chaining (Hawksey):&lt;/strong&gt; Utilizes the Workspace CLI to combine local Node.js execution with remote GAS deployment. This foundational approach preempted Google's newly announced &lt;em&gt;Agent Skills&lt;/em&gt; repository, which formalizes skills as compact, agent-first documentation to mitigate context bloat.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local Sandboxing (Mcpherson):&lt;/strong&gt; Employs the &lt;code&gt;gas-fakes&lt;/code&gt; emulation layer and MCP to securely execute LLM-generated code locally or containerized in any cloud platform. This focus on secure isolation and standardized tooling is now mirrored at the enterprise level by Google's native &lt;em&gt;MCP&lt;/em&gt; support and the highly secure &lt;em&gt;GKE Agent Sandbox&lt;/em&gt; utilizing gVisor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic Generation (Tanaike):&lt;/strong&gt; Utilizes a sophisticated 5-agent orchestrator to write, sandbox-test, and cloud-deploy custom tools in real-time, effectively solving Tool Space Interference (TSI). This mirrors the capabilities of Google's newly announced &lt;em&gt;Long-running agents&lt;/em&gt;, which autonomously execute multi-step workflows inside secure cloud sandboxes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Remote Delegation (Tanaike):&lt;/strong&gt; Leverages the A2A protocol to offload massive libraries of over 160 predefined skills to remote GAS Web Apps. This community-built solution directly anticipated Google's native &lt;em&gt;A2A (Agent-to-Agent) Orchestration&lt;/em&gt; and &lt;em&gt;Agent Registry&lt;/em&gt;, which now allow enterprise agents to natively discover and delegate tasks to one another.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Proposed Method 1 (Federated CARA):&lt;/strong&gt; A zero-trust architecture that routes AI tasks to either containerized emulation or remote A2A subagents based on the data's security classification. This framework is perfectly positioned to integrate with the newly announced &lt;em&gt;Agent Gateway&lt;/em&gt; and &lt;em&gt;Agent Identity&lt;/em&gt;, natively enforcing IAM access control policies and guarding against data exfiltration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Proposed Method 2 (SOTCN):&lt;/strong&gt; A semantic caching network that stores predefined tools in "cold storage" and dynamically injects only the most relevant functions into the agent's active context window. This architecture enhances Google's new &lt;em&gt;Agent Skills&lt;/em&gt; paradigm by programmatically eliminating context bloat without the latency of generative code writing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  7. Explanatory video
&lt;/h2&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/27bZ1aXwfFQ"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>ai</category>
      <category>googleworkspace</category>
      <category>googleappsscript</category>
      <category>gemini</category>
    </item>
    <item>
      <title>Empowering Autonomous AI Agents through Dynamic Tool Creation</title>
      <dc:creator>Tanaike</dc:creator>
      <pubDate>Fri, 24 Apr 2026 07:36:01 +0000</pubDate>
      <link>https://forem.com/gde/empowering-autonomous-ai-agents-through-dynamic-tool-creation-3pfm</link>
      <guid>https://forem.com/gde/empowering-autonomous-ai-agents-through-dynamic-tool-creation-3pfm</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fecwfzv59swalkgbrjjs9.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fecwfzv59swalkgbrjjs9.jpg" alt="Infographic" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Abstract
&lt;/h2&gt;

&lt;p&gt;Welcome to the Agentic Enterprise era. This article explores a paradigm shift in generative AI workflows by introducing an autonomous agent capable of dynamically creating, testing, and executing original tools. Utilizing Google Apps Script, Node.js emulation, and multi-agent orchestration, this architecture overcomes traditional limitations, enabling highly adaptable task execution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;At Google Cloud Next 2026, a clear mandate was delivered: the era of generative AI as a passive assistant is over. We have entered the age of the Agentic Enterprise, where AI has transitioned from a software tool you deploy into an autonomous coworker you onboard. This identity shift is staggering. With models processing over 16 billion tokens per minute via direct API use, we are witnessing an industrial-scale migration toward autonomous workflows. In this new ecosystem, Workspace Intelligence eliminates tab-hopping, allowing users to seamlessly query across Google Drive, Gmail, and third-party platforms. Data has transformed from a reactive archive into a "System of Action," driven by Deep Research Agents that bridge structured and unstructured data to prevent hallucinations.&lt;/p&gt;

&lt;p&gt;However, this massive scale introduces new vulnerabilities and operational bottlenecks. As organizations adopt these highly autonomous coworkers to execute a wide variety of tasks, a vast multitude of tools is required. Yet, as the number of available tools in a Model Context Protocol (MCP) server increases, Large Language Models (LLMs) face a critical issue: inference accuracy and tool selection reliability significantly degrade. Researchers refer to this phenomenon as "Tool Space Interference" (TSI). &lt;a href="https://www.microsoft.com/en-us/research/blog/tool-space-interference-in-the-mcp-era-designing-for-agent-compatibility-at-scale/" rel="noopener noreferrer"&gt;Ref&lt;/a&gt; When an LLM's context window becomes saturated with excessive tool definitions, semantic overlaps and irrelevant metadata hinder decision-making. Current technical guidelines recommend a "soft limit" of approximately 20 functions to maintain high accuracy. Exceeding this threshold often leads to increased hallucinations and failures in executing complex instructions.&lt;/p&gt;

&lt;p&gt;To address this, I previously published the article "Nexus-MCP: A Unified Gateway for Scalable and Deterministic MCP Server Aggregation." &lt;a href="https://medium.com/google-cloud/nexus-mcp-a-unified-gateway-for-scalable-and-deterministic-mcp-server-aggregation-3211f0adc603" rel="noopener noreferrer"&gt;Ref&lt;/a&gt; In that piece, I introduced Nexus-MCP, a concept resolving Tool Space Interference by aggregating multiple MCP servers into a single deterministic gateway. Yet, even with this optimized architecture, a hard limit is eventually reached when attempting to execute an increasingly diverse array of edge-case tasks.&lt;/p&gt;

&lt;p&gt;Furthermore, relying strictly on static tools presents a severe security risk. The 2026 summit highlighted the emergence of machine-speed, "Living off the Land" AI attacks, where internal AI CLI tools are hijacked by rogue processes. Treating AI simply as software leaves systems vulnerable; they must be managed as identities with strict minimum privileges, cryptographic IDs, and robust "Kill Switches" to prevent reasoning drift from turning agents into digital predators.&lt;/p&gt;

&lt;p&gt;This article tackles both the TSI limitation and the security imperative directly by building an agent that dynamically creates, safely tests, and executes original scripts to process varied tasks on the fly. When an AI encounters an edge-case task lacking a pre-existing tool, a true paradigm shift occurs if the AI can automatically generate the exact tools it needs in real-time. By dynamically generating code and executing it in a secure, least-privilege sandbox, we protect the enterprise from unverified execution paths while expanding the spectrum of successfully executable tasks exponentially. I have previously explored this groundbreaking concept in the following articles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://medium.com/google-cloud/dynamic-tool-creation-for-google-workspace-automation-with-gemini-cli-f9618166aaed" rel="noopener noreferrer"&gt;Dynamic Tool Creation for Google Workspace Automation with Gemini CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/google-cloud/a-new-era-for-google-apps-script-unlocking-the-future-of-google-workspace-automation-with-natural-a9cecf87b4c6" rel="noopener noreferrer"&gt;A New Era for Google Apps Script: Unlocking the Future of Google Workspace Automation with Natural Language&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In those articles, I demonstrated how tools could be dynamically created, safely executed in a sandbox, and thoroughly evaluated. &lt;a href="https://github.com/brucemcpherson/gas-fakes" rel="noopener noreferrer"&gt;Ref&lt;/a&gt; The execution results were retrieved using &lt;code&gt;gas-fakes&lt;/code&gt;, a powerful emulation layer that allows Google Apps Script (GAS) projects to run natively on Node.js, effectively acting as an MCP server. We have advanced &lt;code&gt;gas-fakes&lt;/code&gt; into the robust &lt;code&gt;gas-fakes CLI&lt;/code&gt;. Simultaneously, deploying specialized AI agents has become an industry standard. For instance, the Gemini CLI can now seamlessly orchestrate these AI agents as subagents to handle complex, multi-step workflows.&lt;/p&gt;

&lt;p&gt;Recently, I also published a comprehensive guide, "Orchestrating Agents via ADK for TypeScript and Gemini CLI."&lt;a href="https://medium.com/google-cloud/orchestrating-agents-via-adk-for-typescript-and-gemini-cli-8629a86b0500" rel="noopener noreferrer"&gt;Ref&lt;/a&gt; I detailed practical scaffolding patterns, sophisticated multi-agent coordination strategies, and seamless integration techniques for deploying remote subagents within the Gemini CLI ecosystem. The architectural concepts established in that article serve as the foundational blueprint for developing the advanced agent system discussed here.&lt;/p&gt;

&lt;p&gt;Specifically, I have engineered a robust AI agent equipped with a multi-agent framework designed to handle the entire lifecycle of a tool: writing the code, executing the script, validating the output, and summarizing the final results. I rigorously tested this framework as a subagent orchestrated by the Gemini CLI. For the tool's programming language, I selected Google Apps Script. While generative AI is often equipped with code interpreters capable of executing Python, I chose Google Apps Script because it is a low-code language featuring native integration with Google Workspace APIs, enabling seamless cloud automation. &lt;a href="https://workspace.google.com/intl/en/products/apps-script?utm_campaign=deveco_gdemembers&amp;amp;utm_source=deveco" rel="noopener noreferrer"&gt;Ref&lt;/a&gt; For the execution platform, I utilized &lt;code&gt;gas-fakes&lt;/code&gt; to ensure rapid, secure, and local runtime capabilities. &lt;a href="https://github.com/brucemcpherson/gas-fakes" rel="noopener noreferrer"&gt;Ref&lt;/a&gt; Looking ahead, I speculate that AI will eventually generate and execute tasks using entirely novel programming languages—languages highly optimized for AI comprehension, even if difficult for humans to read.&lt;/p&gt;

&lt;h2&gt;
  
  
  Technological Foundations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Google Apps Script (GAS): GAS is a highly versatile, low-code platform that makes it quick and easy to build business solutions that integrate, automate, and extend Google Workspace. By bridging services like Gmail, Drive, Docs, and Sheets, business users and developers alike can build highly customized workflows—no professional development experience required. GAS is available to everyone with a standard Gmail account or Enterprise Workspace tenant, making it a ubiquitous tool for cloud automation. &lt;a href="https://workspace.google.com/intl/en/products/apps-script?utm_campaign=deveco_gdemembers&amp;amp;utm_source=deveco" rel="noopener noreferrer"&gt;Ref&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/brucemcpherson/gas-fakes" rel="noopener noreferrer"&gt;gas-fakes&lt;/a&gt;: A powerful emulation layer that lets you run Apps Script projects on Node.js as if they were native. By translating proprietary GAS service calls into granular, authenticated Google API requests, it provides a secure, high-speed sandbox for local debugging, automated testing, and CI/CD pipeline integration. This eliminates the traditional latency of cloud-based GAS deployments and opens the door for AI agents to write, test, and execute Apps Script entirely within a localized Node environment.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Project Setup and Prerequisites
&lt;/h2&gt;

&lt;p&gt;You can view the complete repository of sample scripts at &lt;a href="https://github.com/tanaikech/autonomous-google-workspace-agent" rel="noopener noreferrer"&gt;https://github.com/tanaikech/autonomous-google-workspace-agent&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To follow along with this guide, ensure your environment meets the following requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node.js is installed and configured on your system.&lt;/li&gt;
&lt;li&gt;Gemini CLI is installed and accessible via your terminal.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Install &lt;code&gt;autonomous-google-workspace-agent&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;To retrieve and initialize the scripts, execute the following commands in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/tanaikech/autonomous-google-workspace-agent
&lt;span class="nb"&gt;cd &lt;/span&gt;autonomous-google-workspace-agent
npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To use this agent, you must configure your Gemini API key as an environment variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GEMINI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;YOUR_API_KEY_HERE&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install gas-fakes
&lt;/h3&gt;

&lt;p&gt;Detailed installation instructions can also be found at&lt;a href="https://github.com/brucemcpherson/gas-fakes/blob/main/gas-fakes-cli.md" rel="noopener noreferrer"&gt;https://github.com/brucemcpherson/gas-fakes/blob/main/gas-fakes-cli.md&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @mcpher/gas-fakes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are using a consumer account (standard Gmail), use the Application Default Credentials (ADC) authorization. Run the following command in the &lt;code&gt;autonomous-google-workspace-agent&lt;/code&gt; directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gas-fakes init &lt;span class="nt"&gt;--auth-type&lt;/span&gt; adc
gas-fakes auth
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check the &lt;code&gt;.env&lt;/code&gt; file created by &lt;code&gt;gas-fakes init --auth-type adc&lt;/code&gt;. Required scopes might need to be manually added to &lt;code&gt;EXTRA_SCOPES&lt;/code&gt; if you encounter permission errors.&lt;/p&gt;

&lt;p&gt;If you are using a Google Workspace enterprise account, you can use either ADC or Domain Wide Delegation (DWD). The DWD type is the default.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gas-fakes init &lt;span class="nt"&gt;--auth-type&lt;/span&gt; adc
gas-fakes auth
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or simply:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gas-fakes init
gas-fakes auth
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install clasp
&lt;/h3&gt;

&lt;p&gt;If you do not need to upload the generated Google Apps Script to Google Drive, you can skip this step. Official documentation is available at &lt;a href="https://github.com/google/CLASP" rel="noopener noreferrer"&gt;https://github.com/google/CLASP&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @google/clasp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;clasp login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Multi-Agent Architecture
&lt;/h2&gt;

&lt;p&gt;You can review the complete architecture in &lt;a href="https://github.com/tanaikech/autonomous-google-workspace-agent" rel="noopener noreferrer"&gt;my repository&lt;/a&gt;. This section details the agent structure.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;src/agent.ts&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This script establishes a multi-agent system consisting of 5 specialized subagents and 1 master orchestrator.&lt;/p&gt;

&lt;p&gt;The comprehensive agent instructions are defined as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AGENT_INSTRUCTIONS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;ENVIRONMENT_CHECKER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`You are 'environment_checker'. Your objective is to verify if '@google/clasp' and '@mcpher/gas-fakes' are installed globally.
Use the 'check_cli_installation' tool to perform this check.
Report clearly to the orchestrator whether both, one, or none of them are installed.`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="na"&gt;SCRIPT_WRITER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`You are 'script_writer', an expert Google Apps Script (GAS) developer.
Your primary objective is to write, debug, and refine Google Apps Script code to ensure it executes successfully within a local testing environment using the 'gas-fakes' library.

### Tool Usage Guidelines
1. Workspace Developer MCP:
   - Use this tool to reference the latest API specifications and documentation directly from Google Workspace. Ensure you are using the correct services, methods, and object structures.

2. Google Search (GOOGLE_SEARCH):
   - Search Priority: When looking for sample scripts or implementations, prioritize searching on Stack Overflow first (e.g., by appending "site:stackoverflow.com" to your query).
   - Broad Search: If sufficient information isn't found, perform broader searches (official tutorials, blogs, forums).
   - Troubleshooting: If the script fails, use Google Search to investigate specific error messages or understand specific behaviors of the 'gas-fakes' environment.

### Code Generation &amp;amp; Output Rules
1. Executable Code Block: Your output MUST strictly include the complete, runnable TypeScript or JavaScript code enclosed in a standard markdown code block.
2. 'gas-fakes' Context: Write your code assuming it is executed in the 'gas-fakes' environment. Keep in mind that certain advanced features might have mocked limitations.
3. Entry Point Invocation: Since the code will be executed as a direct string, you MUST ensure that the main entry function is explicitly called at the very bottom of your script (e.g., &lt;/span&gt;&lt;span class="se"&gt;\`&lt;/span&gt;&lt;span class="s2"&gt;function main() { /* logic */ } main();&lt;/span&gt;&lt;span class="se"&gt;\`&lt;/span&gt;&lt;span class="s2"&gt;).

### Error Handling &amp;amp; Iteration
- When reported a failure from the previous step, carefully analyze the provided stderr/stdout execution logs.
- Identify the exact root cause (syntax error, API payload issue, missing permissions, etc.).
- Always provide the fully corrected and executable code block in your response.`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="na"&gt;SCRIPT_EXECUTOR&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="na"&gt;schemaStr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`You are 'script_executor', an expert testing agent responsible for verifying Google Apps Script (GAS) code.
Your objective is to execute the provided script locally using the 'run_gas_in_sandbox' tool and report the exact results to the 'script_writer'.

### Tool Usage Guidelines ('run_gas_in_sandbox')
1. Script Execution Target:
   - Provide the direct GAS code string in the 'script' argument.
   - IMPORTANT: Ensure the entry function is called at the end of the string.

2. Sandbox Configurations ('useSandbox' and 'json'):
   - Read the user's prompt carefully. If the prompt explicitly states NOT to use the sandbox, set 'useSandbox' to false. Otherwise, you MUST set 'useSandbox' to true (default behavior).
   - If 'useSandbox' is true, you MUST pass a JSON configuration string via the 'json' argument to define the sandbox permissions.
   - Construct the 'json' argument strictly according to this JSON schema:
&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;schemaStr&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
   - Include all necessary method names in 'whitelistServices' to avoid permission errors.
   - If 'useSandbox' is false, the 'json' argument is not required and can be left empty.

### Evaluation &amp;amp; Output Rules
1. Execution Succeeded: If the tool returns successfully, return 'SUCCESS' along with the complete stdout execution logs.
2. Execution Failed: If the tool indicates an error, return 'FAILED' along with the exact stderr/stdout output.
3. Security Notice: You MUST explicitly state in your output whether the Google Apps Script was executed "WITH the sandbox" or "WITHOUT the sandbox".`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="na"&gt;SCRIPT_UPLOADER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`You are 'script_uploader', an expert at managing Google Apps Script projects on Google Drive using the 'clasp' CLI via MCP.
Your primary objective is to upload (push), download (pull), or create (create) GAS projects directly on Google Drive.

### Usage Guidelines &amp;amp; Strict File Operation Rules:
- The orchestrator will invoke you only if '@google/clasp' is confirmed to be installed.
- **Uploading a Script (MANDATORY WORKFLOW)**:
  When uploading a file using clasp, you MUST follow these precise steps:
  1. Create the project via clasp (if a new directory is needed).
  2. **Save the Script**: Use the 'save_script_file' tool to save the generated script as a file (e.g., .js or .gs) inside the directory created by clasp.
  3. **Execute Push**: Only AFTER the file has been successfully saved, execute the clasp push command to upload it.
- Ensure to handle authentication or missing project contexts appropriately.
- Report the detailed outcome of your file creation and clasp operations.`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="na"&gt;SUMMARY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Summarize the final deliverables in the following format:
1. Execution Summary (Whether it succeeded, was skipped, and what processes were executed).
2. Final Script Code (Clean code block, ready to be copied and used).
3. Execution Results / Data. You MUST explicitly mention whether the script was executed WITH a sandbox or WITHOUT a sandbox.
4. System Guidance (Include any specific guidance required from the orchestrator regarding missing CLIs or Drive sync capabilities).`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="na"&gt;ORCHESTRATOR&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`You are a Senior Multi-Agent Orchestrator and the leader coordinating multiple sub-agents. Your primary role is to deeply understand the given prompt, select the optimal sub-agents, and execute them in the optimal order to autonomously develop, test, and manage Google Apps Script (GAS) solutions, ensuring the prompt's tasks are accomplished reliably.

### Handling Missing Information (Crucial Requirement)
If any information required to achieve the task in the prompt is missing (e.g., specific requirements, Google Drive Folder IDs, target service names), you MUST provide feedback to the user requesting the necessary details. Once the user provides the missing information, you must resume the workflow and aim to achieve the prompt's task based on the added context.

### Available Sub-Agents &amp;amp; Expertise:
- "environment_checker" (agent0): Checks if '@google/clasp' and '@mcpher/gas-fakes' are installed.
- "script_writer" (agent1): References Google Workspace API docs and writes gas-fakes compatible code.
- "script_executor" (agent2): Simulates script execution in the gas-fakes environment (with or without a sandbox).
- "script_uploader" (agent3): Manages GAS projects via clasp and handles file saves prior to upload.
- "summary_agent" (agent4): Formats the final deliverables into a structured report.

### Operational Protocols:
1. **Selection &amp;amp; Purpose**: Clearly identify which agent(s) you are using and why. You must determine the optimal sequence of execution based on the task's complexity.
2. **Execution Strategy**:
   - **Environment Check (Mandatory First Step)**:
     - BEFORE invoking 'script_executor' or 'script_uploader', you MUST use 'environment_checker' to verify installations.
     - **If '@mcpher/gas-fakes' is NOT installed**: Skip execution, return ONLY the generated script, and instruct the user to install it via &lt;/span&gt;&lt;span class="se"&gt;\`&lt;/span&gt;&lt;span class="s2"&gt;npm -g install @mcpher/gas-fakes&lt;/span&gt;&lt;span class="se"&gt;\`&lt;/span&gt;&lt;span class="s2"&gt;.
     - **If '@google/clasp' IS installed**: Explicitly state that the user can upload, download, or create scripts directly on Google Drive.
     - **Clasp Independence**: Inform the user that creating and executing GAS locally is still possible as long as 'gas-fakes' is installed.

   - **Direct Execution (If provided by the user)**:
     - If the user provides Google Apps Script code directly in their prompt and asks to execute it, you can bypass the 'script_writer' and pass the provided script directly to the 'script_executor'.

   - **Iterative Workflow (If gas-fakes is installed)**:
     1. Ask 'script_writer' to generate code.
     2. Pass the code to 'script_executor' for simulation.
     3. If 'FAILED', pass the details back to 'script_writer' for regeneration.
     4. **Constraint**: The cycle has a MAXIMUM limit of 5 retries.

   - **Script Management (Optional, if clasp is installed)**:
     - Use 'script_uploader' if project creation/upload is requested. Ensure you communicate that files will be generated before pushing.

   - **Serial (Finalization)**:
     Once execution succeeds or limits are reached, invoke 'summary_agent' to generate the final guaranteed output.

3. **Reporting (Strict Requirement)**: You MUST start your response with an "Execution Log".

### Mandatory Output Format (in English):
---
## Execution Log
- **Agents Involved**:[List names of agents used]
- **Execution Strategy**:[Iterative / Serial / Direct Execution / Awaiting User Input]
- **Purpose &amp;amp; Logic**:[Briefly explain the coordination, environment check results, retry cycles, or reason for requesting missing information]

## Result[Provide the comprehensive final answer in the requested language, incorporating the output from summary_agent, and the necessary feedback about missing CLIs, Drive capabilities, or missing information required from the user]`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;code&gt;environment_checker&lt;/code&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;environmentCheckerAgent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LlmAgent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;environment_checker&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DEFAULT_MODEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Checks if the required CLI tools (@google/clasp and @mcpher/gas-fakes) are installed globally.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;instruction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AGENT_INSTRUCTIONS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ENVIRONMENT_CHECKER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;checkCliInstallationTool&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This agent verifies whether the necessary dependencies are properly installed in the host environment.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;script_writer&lt;/code&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;scriptWriterAgent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LlmAgent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;script_writer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DEFAULT_MODEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;References Google Workspace API specifications via MCP and generates code for the gas-fakes environment. Analyzes and fixes errors.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;instruction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AGENT_INSTRUCTIONS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SCRIPT_WRITER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MCPToolset&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;StreamableHTTPConnectionParams&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://workspace-developer.goog/mcp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="nx"&gt;GOOGLE_SEARCH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;generateContentConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;toolConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;includeServerSideToolInvocations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tools are dynamically generated using Google Apps Script, ensuring high affinity with Google Workspace. To enable &lt;code&gt;GOOGLE_SEARCH&lt;/code&gt; alongside custom capabilities, &lt;code&gt;includeServerSideToolInvocations: true&lt;/code&gt; must be specified.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;script_executor&lt;/code&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;scriptExecutorAgent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LlmAgent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;script_executor&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DEFAULT_MODEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Simulates script execution securely in the gas-fakes sandbox environment and handles error reporting.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;instruction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AGENT_INSTRUCTIONS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SCRIPT_EXECUTOR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SANDBOX_PERMISSION_SCHEMA&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;runGasInSandboxTool&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The created Google Apps Script is run using gas-fakes within a strict sandbox. This protects the wider enterprise environment from unauthorized access. &lt;code&gt;gas-fakes&lt;/code&gt; is run by the gas-fakes CLI. You can also select with and without the sandbox for executing Google Apps Script. In some cases, the sandbox might not be required to be used.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;script_uploader&lt;/code&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;scriptUploaderAgent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LlmAgent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;script_uploader&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DEFAULT_MODEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Uploads, downloads, or creates Google Apps Script projects on Google Drive using clasp. Used only when @google/clasp is installed.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;instruction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AGENT_INSTRUCTIONS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SCRIPT_UPLOADER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MCPToolset&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;StdioConnectionParams&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;serverParams&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;clasp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mcp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="nx"&gt;saveScriptFileTool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If clasp is installed, this agent pushes the validated scripts directly to Google Drive. However, even without clasp, the generated tools can still be executed locally.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;summary_agent&lt;/code&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;summaryAgent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LlmAgent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;summary_agent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DEFAULT_MODEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Formats the final deliverables into a structured report.&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="na"&gt;instruction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AGENT_INSTRUCTIONS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SUMMARY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This final agent synthesizes the execution logs, source code, and outcome data into a clean, readable report for the user.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;autonomous_gas_orchestrator&lt;/code&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;autonomousGoogleWorkspaceAgent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LlmAgent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;autonomous-google-workspace-agent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DEFAULT_MODEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Senior Orchestrator managing GAS creation, environment check, execution, clasp integration, and up to 5 retries.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;instruction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AGENT_INSTRUCTIONS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ORCHESTRATOR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;subAgents&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;
    &lt;span class="nx"&gt;environmentCheckerAgent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;scriptWriterAgent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;scriptExecutorAgent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;scriptUploaderAgent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;summaryAgent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the central agent that intelligently delegates tasks and manages the lifecycle of the entire dynamic generation process.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;src/a2aserver.ts&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This script is used for launching &lt;code&gt;autonomous-google-workspace-agent&lt;/code&gt; as an A2A server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;
&lt;span class="cm"&gt;/**
 * A2A server
 */&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;LlmAgent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;toA2a&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@google/adk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;autonomousGasOrchestratorAgent&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;targetAgent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./agent.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;host&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;localhost&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;startServer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`[&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;] &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// For A2A&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;toA2a&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;targetAgent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;basePath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Server started on http://&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Try: http://&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/.well-known/agent-card.json`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;startServer&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Launching the Agent System
&lt;/h2&gt;

&lt;p&gt;This framework can function both as a standalone web server and as a subagent linked to the Gemini CLI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Launch the Web server:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run web
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm run web

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; adk-full-samples@1.0.0 web
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; npx adk web src/agent.ts


+-----------------------------------------------------------------------------+
| ADK API Server started                                                      |
|                                                                             |
| For &lt;span class="nb"&gt;local &lt;/span&gt;testing, access at http://localhost:8000.                         |
+-----------------------------------------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now interact with the web interface by navigating to &lt;code&gt;http://localhost:8000&lt;/code&gt; in your browser.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Launch the A2A server:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run a2a
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Upon execution, you will see a confirmation output in your terminal indicating the server has started successfully:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm run a2a

&amp;gt; adk-full-samples@1.0.0 a2a
&amp;gt; npx tsx src/a2aserver.ts

Server started on http://localhost:8000
Try: http://localhost:8000/.well-known/agent-card.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To configure this A2A server as a subagent for the Gemini CLI, create or update &lt;code&gt;.gemini/agents/autonomous-google-workspace-agent.md&lt;/code&gt; with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
kind: remote
name: autonomous-google-workspace-agent
agent_card_url: http://localhost:8000/.well-known/agent-card.json
---
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can inspect the agent card specifications by opening the provided URL (&lt;code&gt;http://localhost:8000/.well-known/agent-card.json&lt;/code&gt;) in your browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing and Use Cases
&lt;/h2&gt;

&lt;p&gt;Once correctly configured, launch the Gemini CLI. You can now delegate complex natural language instructions to your &lt;code&gt;autonomous-google-workspace-agent&lt;/code&gt;. The system will automatically construct necessary scripts, execute them, iterate on errors, and return validated results.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/7Ki-nA1Z1c0"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Dynamic Exchange Rate Retrieval via GOOGLEFINANCE
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Prompt:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Create a new Google Spreadsheet by putting a formula `=GOOGLEFINANCE("CURRENCY:USDJPY")` in cell "A1" of the first sheet. Then, get and show the value of cell "A1". (Note: `gas-fakes` has no `getActiveSheet()` method. In this case, use `getSheets()[0]`.)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The system successfully generated the script, ran it safely within the sandbox, and fetched the financial data directly from Google Sheets.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9mxjivm538i4s5mme4a0.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9mxjivm538i4s5mme4a0.jpg" alt="fig2a" width="800" height="623"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Automated Spreadsheet Initialization with Dummy Data
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Prompt:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;In this case, the script is not required to be executed in a sandbox. Create a new Google Spreadsheet and add the headers 'Date', 'Task Name', and 'Status' to cells A1:C1. Then, populate the next 3 rows with dummy task data. Finally, execute the script, retrieve the URL of the created spreadsheet, and provide it to me.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Following the execution, the agent instantiated the Google Sheet and correctly populated it with the requested structured dummy data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpifn3rvnvnbn156ba20u.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpifn3rvnvnbn156ba20u.jpg" alt="fig2b" width="800" height="468"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Dynamic Calendar Event Scheduling with Autonomous Error Correction
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Prompt:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**Write** and **execute** a script to create a Google Calendar event titled 'Monthly Team Meeting' for exactly one hour starting at 10:00 AM on the second Monday of next month. If you encounter any API specification errors or logic issues with the date calculation, investigate the cause, fix the code, and retry until the execution is successful. The calendar ID is '{your calendar ID}'.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The orchestrator dynamically calculated the date logic, interfaced with the Calendar API, handled temporary validation failures gracefully via the &lt;code&gt;script_writer&lt;/code&gt;, and successfully scheduled the event.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. GAS Development Workflow: Document Highlighter and Google Drive Deployment
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Prompt:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Create a GAS custom function that highlights a specific keyword (e.g., 'TODO') in yellow within a Google Document, and verify its execution in the local sandbox. Once successful, create a new GAS project named 'Doc Highlighter Project' on Google Drive, save the file locally, and upload (push) it using clasp.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The script successfully manipulated the Google Document and utilized the &lt;code&gt;script_uploader&lt;/code&gt; agent to push the project securely to Google Drive.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx126nx4xa3nl9xm1yomt.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx126nx4xa3nl9xm1yomt.jpg" alt="fig2c" width="800" height="520"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Automated Weekly Drive Report: Filtered File Aggregation and Gmail Synchronization
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Prompt:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;In this case, the script is not required to be executed in a sandbox. Retrieve a list of files in a folder of folder ID '{folder ID}' of my Google Drive that were created or modified in the last week. Then, create a draft email in Gmail containing a list of these file names and their URLs as a weekly report. Set the recipient to 'tanaike@hotmail.com' and the subject to 'Weekly Drive Files Report'.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result was an accurately compiled draft email directly saved to Gmail, complete with proper formatting and links.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Weekly Drive Files Report

The following files were created or modified in the last 7 days:

- Name: sample slide 1
  URL: https://docs.google.com/presentation/d/{file ID 1}/edit?usp=drivesdk

- Name: sample spreadsheet 1
  URL: https://docs.google.com/spreadsheets/d/{file ID 2}/edit?usp=drivesdk

- Name: sample document 1
  URL: https://docs.google.com/document/d/{file ID 3}/edit?usp=drivesdk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deployment Considerations
&lt;/h2&gt;

&lt;p&gt;While this article demonstrates running the A2A server locally for testing, deploying this multi-agent architecture to fully managed serverless environments—such as Google Cloud Run—will vastly increase its operational capacity. Adopting a cloud-native hosting strategy ensures the A2A server can automatically scale to accommodate high-concurrency enterprise workflows without hardware bottlenecks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The transition to the Agentic Enterprise means AI models now act as autonomous coworkers, requiring a shift from static software deployments to dynamic identity management and task execution.&lt;/li&gt;
&lt;li&gt;Tool Space Interference (TSI) degrades inference accuracy when LLMs are overloaded with predefined tools, a limitation effectively bypassed by enabling agents to dynamically write and execute their own scripts in real-time.&lt;/li&gt;
&lt;li&gt;Utilizing Google Apps Script alongside the gas-fakes emulation layer provides AI agents with a secure, high-speed, and sandboxed local runtime to safely develop and test enterprise workflows.&lt;/li&gt;
&lt;li&gt;A robust multi-agent architecture seamlessly orchestrated via the Gemini CLI can independently handle the entire tool lifecycle: code generation, secure sandbox testing, execution validation, and Google Drive deployment.&lt;/li&gt;
&lt;li&gt;Expanding this framework into serverless cloud environments not only addresses the massive computational scale of modern AI but also fortifies security by isolating dynamic tool execution from core organizational infrastructure.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>gemini</category>
      <category>agents</category>
      <category>googleappsscript</category>
    </item>
    <item>
      <title>Orchestrating Agents via ADK for TypeScript and Gemini CLI</title>
      <dc:creator>Tanaike</dc:creator>
      <pubDate>Tue, 21 Apr 2026 05:22:52 +0000</pubDate>
      <link>https://forem.com/gde/orchestrating-agents-via-adk-for-typescript-and-gemini-cli-jco</link>
      <guid>https://forem.com/gde/orchestrating-agents-via-adk-for-typescript-and-gemini-cli-jco</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnbux4nzfwesadhy5g05d.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnbux4nzfwesadhy5g05d.jpg" alt="fig1a" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Abstract
&lt;/h2&gt;

&lt;p&gt;Explore how to build and orchestrate production-ready, type-safe AI agents using Google's TypeScript Agent Development Kit (ADK). This guide provides practical scaffolding patterns, multi-agent coordination strategies, and seamless integration techniques for deploying remote subagents within the Gemini CLI ecosystem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;As the artificial intelligence landscape rapidly evolves, modern generative AI increasingly relies on autonomous agents equipped with sophisticated components, including system instructions, specialized skills, and Model Context Protocol (MCP) servers. To facilitate the development of such AI-driven applications, Google has released the Agent Development Kit (ADK) across multiple programming languages &lt;a href="https://adk.dev/" rel="noopener noreferrer"&gt;Ref&lt;/a&gt;. Among these, the ADK for TypeScript &lt;a href="https://github.com/google/adk-js" rel="noopener noreferrer"&gt;Ref&lt;/a&gt; offers distinct advantages for modern engineering paradigms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Full-Stack Synergy:&lt;/strong&gt; Essential for modern web applications (e.g., Next.js or React), allowing developers to share types and logic between the frontend and backend to streamline the development lifecycle.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability &amp;amp; Reliability:&lt;/strong&gt; Crucial for large-scale enterprise systems, where static typing and robust refactoring tools ensure long-term maintainability and minimize runtime errors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High Concurrency:&lt;/strong&gt; Highly effective for agents that must efficiently handle numerous asynchronous events, streaming responses, and real-time user interactions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Despite these architectural merits, a critical gap exists in ecosystem maturity. While Python remains the "Gold Standard" with first-class support in AI research, TypeScript is often viewed as an emerging platform. Although there is a rising demand for integrating AI agents into enterprise web applications, quantitative data indicates that TypeScript-specific ADK resources account for less than 5% of the total search volume compared to the Python-centric ecosystem. This overwhelming scarcity of documentation and community-driven knowledge presents a significant barrier to entry for full-stack developers.&lt;/p&gt;

&lt;p&gt;To fill this critical information void and catalyze the development of type-safe, production-ready AI agents, this article provides a comprehensive framework and practical scaffolding patterns using the TypeScript ADK. Furthermore, it introduces advanced methodologies for establishing a multi-agent architecture. Specifically, this article demonstrates how to seamlessly integrate these custom-built TypeScript agents as remote subagents within the Gemini CLI, leveraging agent-to-agent protocols to enable scalable, interconnected AI workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Setup and Prerequisites
&lt;/h2&gt;

&lt;p&gt;You can view the complete repository of sample scripts at&lt;a href="https://github.com/tanaikech/ts-multi-agent-scaffolding" rel="noopener noreferrer"&gt;https://github.com/tanaikech/ts-multi-agent-scaffolding&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To follow along with this guide, ensure your environment meets the following requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node.js is installed and configured on your system.&lt;/li&gt;
&lt;li&gt;Gemini CLI is installed and accessible via your terminal.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To retrieve and initialize the sample scripts, execute the following commands in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/tanaikech/ts-multi-agent-scaffolding
&lt;span class="nb"&gt;cd &lt;/span&gt;ts-multi-agent-scaffolding
npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Building Specialized AI Agents
&lt;/h2&gt;

&lt;p&gt;The following samples demonstrate how to construct specialized, single-purpose agents using the TypeScript ADK. Each agent is designed to handle a distinct operational domain.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. General Logic Analyst (Sample 1)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Focus:&lt;/strong&gt; Logical analysis, summarization, drafting, and evaluation.&lt;/p&gt;

&lt;p&gt;This foundational agent focuses on parsing text and validating logical structures without relying on external API tools. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;sample1/agent.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;LlmAgent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@google/adk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rootAgent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LlmAgent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;general_logic_analyst&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Handles general reasoning, text summarization, and logical validation of information.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gemini-3-flash-preview&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;instruction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`You are a Senior Logic Analyst and General Assistant. 
Your role is to process general queries and synthesize information from various sources.

### Key Responsibilities:
1. **Summarization**: Condense long texts or technical logs into concise, actionable insights.
2. **Logical Validation**: Check if a given statement or piece of code follows logical consistency.
3. **Drafting**: Create professional emails, reports, or documentation based on raw data.
4. **Knowledge Retrieval**: Answer general knowledge questions using your internal training data.

### Constraints:
- Keep responses professional and structured.
- If you receive data from other agents (like weather or file logs), focus on explaining the *implications* of that data.
- Do not invent facts; if information is missing, clearly state so.

### Output Style:
Use bullet points for clarity and always provide a brief "Conclusion" or "Next Steps" section at the end of long responses.`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Launch the agent as a local web server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run sample1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Access &lt;code&gt;http://localhost:8000&lt;/code&gt; in your browser to interact with the web interface. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F38ogdh89hhrbit4i9d89.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F38ogdh89hhrbit4i9d89.jpg" alt="fig2a" width="800" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. API Manager for Real-Time Data (Sample 2)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Focus:&lt;/strong&gt; Real-time data retrieval via external APIs (Weather, Exchange Rates).&lt;/p&gt;

&lt;p&gt;This agent leverages custom tools built with Zod schema validation to dynamically fetch external data, demonstrating how AI can interact with the real world.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sample2/agent.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * agent.ts
 * AI Agent definition with dynamic date context and Tool definitions.
 *
 * npx adk web
 */&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;LlmAgent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FunctionTool&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@google/adk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;zod&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ==========================================&lt;/span&gt;
&lt;span class="c1"&gt;// 1. Dynamic Date Helper&lt;/span&gt;
&lt;span class="c1"&gt;// ==========================================&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;currentDateTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ja-JP&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;year&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;numeric&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;month&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2-digit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;day&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2-digit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;hour&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2-digit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;minute&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2-digit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;timeZone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Asia/Tokyo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// ==========================================&lt;/span&gt;
&lt;span class="c1"&gt;// 2. Tools Definition&lt;/span&gt;
&lt;span class="c1"&gt;// ==========================================&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getExchangeRateTool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FunctionTool&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;get_exchange_rate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Use this to get current exchange rate between currencies.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;currency_from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;USD&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Source currency (major currency).&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;currency_to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;EUR&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Destination currency (major currency).&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;currency_date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;latest&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Date of the currency in ISO format (YYYY-MM-DD) or 'latest'.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="na"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;currency_from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;currency_to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;currency_date&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s2"&gt;`https://api.frankfurter.app/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;currency_date&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;?from=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;currency_from&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;to=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;currency_to&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`API status: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rates&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;currency_to&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s2"&gt;`The raw data from the API is &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;.`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;`The currency rate at &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;currency_date&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; from "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;currency_from&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;" to "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;currency_to&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;" is &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`Error retrieving exchange rate: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getCurrentWeatherTool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FunctionTool&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;get_current_weather&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Use this to get the weather using the latitude and the longitude.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;latitude&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The latitude of the inputed location.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;longitude&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The longitude of the inputed location.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Date for searching the weather. Format: 'yyyy-MM-dd HH:mm'&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;timezone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The timezone (e.g., 'Asia/Tokyo').&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="na"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;latitude&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;longitude&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;timezone&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;codeMap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Clear sky&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Mainly clear, partly cloudy, and overcast&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Mainly clear, partly cloudy, and overcast&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Mainly clear, partly cloudy, and overcast&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Fog and depositing rime fog&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Fog and depositing rime fog&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="mi"&gt;51&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Drizzle: Light, moderate, and dense intensity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="mi"&gt;53&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Drizzle: Light, moderate, and dense intensity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="mi"&gt;55&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Drizzle: Light, moderate, and dense intensity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="mi"&gt;56&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Freezing Drizzle: Light and dense intensity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="mi"&gt;57&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Freezing Drizzle: Light and dense intensity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="mi"&gt;61&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Rain: Slight, moderate and heavy intensity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="mi"&gt;63&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Rain: Slight, moderate and heavy intensity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="mi"&gt;65&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Rain: Slight, moderate and heavy intensity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="mi"&gt;66&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Freezing Rain: Light and heavy intensity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="mi"&gt;67&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Freezing Rain: Light and heavy intensity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="mi"&gt;71&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Snow fall: Slight, moderate, and heavy intensity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="mi"&gt;73&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Snow fall: Slight, moderate, and heavy intensity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Snow fall: Slight, moderate, and heavy intensity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="mi"&gt;77&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Snow grains&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Rain showers: Slight, moderate, and violent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="mi"&gt;81&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Rain showers: Slight, moderate, and violent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="mi"&gt;82&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Rain showers: Slight, moderate, and violent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="mi"&gt;85&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Snow showers slight and heavy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="mi"&gt;86&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Snow showers slight and heavy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="mi"&gt;95&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Thunderstorm: Slight or moderate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="mi"&gt;96&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Thunderstorm with slight and heavy hail&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="mi"&gt;99&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Thunderstorm with slight and heavy hail&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;endpoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`https://api.open-meteo.com/v1/forecast?latitude=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;latitude&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;longitude=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;longitude&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;hourly=weather_code&amp;amp;timezone=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timezone&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;targetTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;T&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;widx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hourly&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;targetTime&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;widx&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;codeMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hourly&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;weather_code&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;widx&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unknown condition.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;No weather data found for the specified time.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`Error retrieving weather: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// ==========================================&lt;/span&gt;
&lt;span class="c1"&gt;// 3. Agent Definition&lt;/span&gt;
&lt;span class="c1"&gt;// ==========================================&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rootAgent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LlmAgent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;api_manager_agent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;An agent that manages currency and weather API tools.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gemini-3-flash-preview&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;instruction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`You are a professional API Manager.
Current date and time is &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;currentDateTime&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;. Use this information to calculate relative dates.
1. Use 'get_exchange_rate' for currency queries.
2. Use 'get_current_weather' for weather queries. "date" is required to be "yyyy-MM-dd HH:00".
3. Provide precise, helpful responses based on tool outputs.`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;getExchangeRateTool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getCurrentWeatherTool&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Launch the agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run sample2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Access &lt;code&gt;http://localhost:8000&lt;/code&gt; to interact with this API-connected agent.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fya6jh3v7n80q42jm1bqm.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fya6jh3v7n80q42jm1bqm.jpg" alt="fig2b" width="800" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Local Filesystem Expert via MCP (Sample 3)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Focus:&lt;/strong&gt; Local filesystem operations via MCP.&lt;/p&gt;

&lt;p&gt;By integrating the Model Context Protocol (MCP), this agent gains secure, managed access to the local filesystem. For this sample, target files should be placed in the &lt;code&gt;sample3/sample&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sample3/agent.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;LlmAgent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MCPToolset&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@google/adk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rootAgent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LlmAgent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;local_file_expert&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gemini-3-flash-preview&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;instruction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;You are a local file manager. Help users organize and understand their files. Here, you can access only a directory of 'sample' given by the MCP server.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MCPToolset&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;StdioConnectionParams&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;serverParams&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;npx&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;-y&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@modelcontextprotocol/server-filesystem&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sample3/sample&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Launch the agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run sample3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Access &lt;code&gt;http://localhost:8000&lt;/code&gt; to instruct the agent to read and organize your local files.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8sps4hiup3z6oasna32o.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8sps4hiup3z6oasna32o.jpg" alt="fig2c" width="800" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Google Workspace Technical Guide via MCP (Sample 4)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Focus:&lt;/strong&gt; Technical support for Google Workspace APIs and Apps Script (GAS).&lt;/p&gt;

&lt;p&gt;This agent utilizes a remote MCP server to stream up-to-date Workspace documentation, creating a highly specialized technical support assistant.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sample4/agent.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;LlmAgent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MCPToolset&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@google/adk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rootAgent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LlmAgent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;workspace_doc_guide&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gemini-3-flash-preview&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;instruction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;You are a Google Workspace expert. Use the provided tools to answer questions about Apps Script and Workspace APIs.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MCPToolset&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;StreamableHTTPConnectionParams&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://workspace-developer.goog/mcp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Launch the agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run sample4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Access &lt;code&gt;http://localhost:8000&lt;/code&gt; to query the agent regarding complex Workspace developer documentation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiai3uo1io1o9w2zhoyvq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiai3uo1io1o9w2zhoyvq.jpg" alt="fig2d" width="800" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Orchestrating Multi-Agent Workflows
&lt;/h2&gt;

&lt;h3&gt;
  
  
  5. Multi-Agent Orchestrator (Sample 5)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Focus:&lt;/strong&gt; Coordination of multiple agents using serial, parallel, and iterative execution strategies.&lt;/p&gt;

&lt;p&gt;Once individual subagents are established, they can be orchestrated by a primary agent. This orchestrator acts as a dynamic manager, delegating tasks to the specialized subagents (Agents 1 through 4) based on the user's prompt.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sample5/agent.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;LlmAgent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@google/adk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rootAgent&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;agent1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../sample1/agent.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rootAgent&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;agent2&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../sample2/agent.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rootAgent&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;agent3&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../sample3/agent.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rootAgent&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;agent4&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../sample4/agent.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rootAgent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LlmAgent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;multi_agent_orchestrator&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Advanced orchestrator capable of serial, parallel, and iterative task execution.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gemini-3-flash-preview&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;instruction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`You are a Senior Multi-Agent Orchestrator. Your role is to analyze user prompts and delegate tasks to the most suitable sub-agents.

### Available Sub-Agents &amp;amp; Expertise:
- "general_logic_analyst" (agent1): Logic validation, summarization, and final report drafting.
- "api_manager_agent" (agent2): Real-time currency exchange and weather data retrieval.
- "local_file_expert" (agent3): Local file system operations within the workspace.
- "workspace_doc_guide" (agent4): Google Workspace APIs and Apps Script documentation.

### Operational Protocols:
1. **Selection &amp;amp; Purpose**: Clearly identify which agent(s) you are using and why.
2. **Execution Strategy**:
   - **Serial**: When one agent's output is needed as input for another.
   - **Parallel**: When multiple independent data points are needed.
   - **Iterative**: When you need to re-run an agent or call a new one based on fresh findings.
3. **Reporting (Strict Requirement)**: You MUST start your response with an "Execution Log".

### Mandatory Output Format (in English):
---
## Execution Log
- **Agents Involved**: [List names of agents used]
- **Execution Strategy**: [Single / Serial / Parallel / Iterative]
- **Purpose &amp;amp; Logic**:[Briefly explain why these agents were chosen and how they were coordinated]

## Result[Provide the comprehensive final answer in the language requested by the user]
---`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;subAgents&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="nx"&gt;agent1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;agent2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;agent3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;agent4&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Launch the orchestrator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run sample5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Access &lt;code&gt;http://localhost:8000&lt;/code&gt; to witness complex routing and multi-agent problem-solving in action.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx4vttp6mq946rxfk35xv.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx4vttp6mq946rxfk35xv.jpg" alt="fig2e" width="800" height="750"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Agent-to-Agent (A2A) Integration with Gemini CLI
&lt;/h2&gt;

&lt;h3&gt;
  
  
  6. A2A Server Implementation (Sample 6)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Focus:&lt;/strong&gt; Exposing the multi-agent system to external clients via an A2A server.&lt;/p&gt;

&lt;p&gt;To fully integrate these TypeScript agents into enterprise workflows, we can expose them as an Agent-to-Agent (A2A) service. This allows tools like the Gemini CLI to communicate directly with our orchestrator.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sample6/a2aserver.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * sample6/a2aserver.ts
 *
 * A2A server that dynamically loads agents.
 * Usage: SAMPLE_TYPE=5 npx tsx sample6/a2aserver.ts
 */&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;LlmAgent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;toA2a&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@google/adk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dotenv/config&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rootAgent&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;agent1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../sample1/agent.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rootAgent&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;agent2&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../sample2/agent.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rootAgent&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;agent3&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../sample3/agent.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rootAgent&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;agent4&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../sample4/agent.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rootAgent&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;agent5&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../sample5/agent.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;host&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;localhost&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;agents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;LlmAgent&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;agent1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;agent2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;agent3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;4&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;agent4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;agent5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;startServer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SAMPLE_TYPE&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;targetAgent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;agents&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;targetAgent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Invalid SAMPLE_TYPE: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`[&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;] &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// For A2A&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;toA2a&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;targetAgent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;basePath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Server started on http://&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Try: http://&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/.well-known/agent-card.json`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;startServer&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Launch the A2A server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run sample6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Upon execution, you will see a confirmation output in your terminal indicating the server and MCP roots have started successfully:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm run sample6

&amp;gt; adk-full-samples@1.0.0 sample6
&amp;gt; npx tsx sample6/a2aserver.ts

Secure MCP Filesystem Server running on stdio
Client does not support MCP Roots, using allowed directories set from server args:[ '/{your directory}/sample3/sample' ]
Server started on http://localhost:8000
Try: http://localhost:8000/.well-known/agent-card.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To configure this A2A server as a subagent for the Gemini CLI, create or update &lt;code&gt;.gemini/agents/sample-adk-agent.md&lt;/code&gt; with the following configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
kind: remote
name: sample-adk-agent
agent_card_url: http://localhost:8000/.well-known/agent-card.json
---
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once configured, launch the Gemini CLI. You will now be able to delegate complex tasks directly to your &lt;code&gt;sample-adk-agent&lt;/code&gt; subagent:&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/p2CIkz3ORdg"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Additionally, you can inspect the agent card specifications directly by navigating to the provided URL (&lt;code&gt;http://localhost:8000/.well-known/agent-card.json&lt;/code&gt;) in your browser. &lt;/p&gt;

&lt;p&gt;While this article demonstrates running the A2A server in a local environment for testing purposes, deploying this architecture to fully managed serverless platforms—such as Google Cloud Run or similar services—will significantly increase its scalability. Cloud-native hosting ensures the A2A server can automatically scale to meet the demands of high-concurrency enterprise workloads.&lt;/p&gt;

&lt;h2&gt;
  
  
  Future Outlook
&lt;/h2&gt;

&lt;p&gt;It is important to note that the TypeScript version of the ADK is still actively under development. As the framework evolves, developers can anticipate frequent updates that will introduce further usability improvements, streamlined APIs, and robust new features, continuing to close the maturity gap with its Python counterpart.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Google's TypeScript ADK provides an optimal foundation for building highly concurrent, type-safe AI agents tailored for modern full-stack web architectures.&lt;/li&gt;
&lt;li&gt;Specialized, single-purpose subagents drastically improve output reliability, efficiently handling discrete tasks ranging from logical validation to real-time API integrations.&lt;/li&gt;
&lt;li&gt;The Model Context Protocol (MCP) securely extends agent capabilities, enabling direct interactions with local filesystems and remote knowledge bases without compromising security.&lt;/li&gt;
&lt;li&gt;Advanced orchestration models allow complex workflows to be dynamically distributed across multiple agents using serial, parallel, or iterative execution strategies.&lt;/li&gt;
&lt;li&gt;Implementing an Agent-to-Agent (A2A) server allows seamless external integration, transforming custom TypeScript agents into scalable remote subagents executable natively within the Gemini CLI.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>gemini</category>
      <category>ai</category>
      <category>typescript</category>
      <category>adk</category>
    </item>
    <item>
      <title>Integrating Remote Subagents Built by Google Apps Script with Gemini CLI</title>
      <dc:creator>Tanaike</dc:creator>
      <pubDate>Mon, 13 Apr 2026 05:21:33 +0000</pubDate>
      <link>https://forem.com/gde/integrating-remote-subagents-built-by-google-apps-script-with-gemini-cli-h36</link>
      <guid>https://forem.com/gde/integrating-remote-subagents-built-by-google-apps-script-with-gemini-cli-h36</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi6v6pinzvbgowpfcpgno.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi6v6pinzvbgowpfcpgno.jpg" alt="fig1a" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Abstract
&lt;/h2&gt;

&lt;p&gt;This article explores integrating remote subagents built with Google Apps Script into the Gemini CLI using the Agent-to-Agent (A2A) protocol. It demonstrates how bypassing standard authentication via local agent cards enables seamless execution of complex workflows while effectively overcoming Tool Space Interference (TSI) for massive toolsets.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Recently, remote subagent support was introduced to the Gemini CLI. &lt;a href="https://geminicli.com/docs/core/remote-agents/" rel="noopener noreferrer"&gt;Ref&lt;/a&gt; With this feature, the Gemini CLI connects to remote subagents using the Agent-to-Agent (A2A) protocol, expanding its capabilities by delegating tasks to external services. I have previously published several articles discussing the A2A server architecture:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://medium.com/google-cloud/building-agent2agent-a2a-server-with-google-apps-script-d3efd32c7ca7" rel="noopener noreferrer"&gt;Building Agent2Agent (A2A) Server with Google Apps Script&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/google-cloud/enabling-collaborative-agent-systems-through-google-apps-script-based-agent2agent-a2a-network-19e3d0472eaa" rel="noopener noreferrer"&gt;Enabling Collaborative Agent Systems through Google Apps Script-based Agent2Agent (A2A) Network&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/google-cloud/consolidating-generative-ai-protocols-a-single-server-solution-for-mcp-and-a2a-84e1e75ccbcf" rel="noopener noreferrer"&gt;Consolidating Generative AI Protocols: A Single Server Solution for MCP and A2A&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/google-cloud/overcoming-tool-space-interference-bridging-google-adk-and-a2a-sdk-via-google-apps-script-44e9f161e235" rel="noopener noreferrer"&gt;Overcoming Tool Space Interference: Bridging Google ADK and A2A SDK via Google Apps Script&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These articles introduce A2A servers built with Google Apps Script (GAS) Web Apps. GAS serves as an ideal foundation for A2A servers because its low-code environment is easily navigable by both human developers and generative AI. Furthermore, GAS is accessible to anyone with a Google account and offers native affinity with Google Workspace. It simplifies complex operations by facilitating seamless OAuth scope authentication and providing direct access to Google APIs via Advanced Google Services.&lt;/p&gt;

&lt;p&gt;By utilizing GAS, developers can rapidly deploy lightweight, category-specific agents that communicate via the A2A protocol. This forms a robust mesh of capabilities without the infrastructure overhead of traditional server environments.&lt;/p&gt;

&lt;p&gt;An excellent foundational article on the basic methods for using subagents with the Gemini CLI was recently published by Romin Irani. &lt;a href="https://medium.com/google-cloud/mastering-gemini-cli-subagents-part-1-a4666091c154" rel="noopener noreferrer"&gt;Ref&lt;/a&gt; Building on that foundation, this article introduces a specific approach for securely and natively integrating remote subagents built by Google Apps Script Web Apps with the Gemini CLI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demonstration
&lt;/h2&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/GE0C8QygPV8"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F41r7imhys6shwclrgzri.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F41r7imhys6shwclrgzri.jpg" alt="Workflow" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites and Repository
&lt;/h2&gt;

&lt;p&gt;This article assumes the following prerequisites:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You have installed and configured the latest Gemini CLI.&lt;/li&gt;
&lt;li&gt;You have an active API key for the Gemini API.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can view all the sample scripts used in this article at the following repository:&lt;a href="https://github.com/tanaikech/gemini-cli-gas-a2a-subagents" rel="noopener noreferrer"&gt;https://github.com/tanaikech/gemini-cli-gas-a2a-subagents&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Basic Integration: Connecting Gemini CLI to a GAS-based A2A Server
&lt;/h2&gt;

&lt;p&gt;This section demonstrates a simple test to confirm the connection between the Gemini CLI and a remote subagent (A2A server) built with Google Apps Script.&lt;/p&gt;

&lt;h3&gt;
  
  
  1.1 Building the A2A Server
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1.1.1 Google Apps Script Preparation
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Copy Google Apps Script&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Log in to your Google account and access the following URL to view the Google Apps Script project dashboard. Click the copy icon in the top right corner to copy the standalone script to your root folder:&lt;a href="https://script.google.com/home/projects/1vcbr7E7XeJafVGdV6QKEgsr9H0-Vl_zLOQSjgysDCs2olWlrE43HGOne" rel="noopener noreferrer"&gt;https://script.google.com/home/projects/1vcbr7E7XeJafVGdV6QKEgsr9H0-Vl_zLOQSjgysDCs2olWlrE43HGOne&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Manual Preparation of Google Apps Script&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you prefer to create the sample A2A server manually, follow these steps:&lt;/p&gt;

&lt;p&gt;Create a new standalone Google Apps Script project. &lt;a href="https://developers.google.com/apps-script/guides/projects#create-standalone" rel="noopener noreferrer"&gt;Ref&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;appsscript.json&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Overwrite &lt;code&gt;appsscript.json&lt;/code&gt; with the following JSON. Adjust &lt;code&gt;timeZone&lt;/code&gt; to your local timezone.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"timeZone"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Asia/Tokyo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"enabledAdvancedServices"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"libraries"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"userSymbol"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MCPA2Aserver"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"libraryId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1xRlK6KPhqp374qAyumrtVXXNEtb7iZ_rD7yRuYxccQuYieKCCao9VuB6"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"developmentMode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"webapp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"executeAs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USER_DEPLOYING"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"access"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ANYONE_ANONYMOUS"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"exceptionLogging"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"STACKDRIVER"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"runtimeVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"V8"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"oauthScopes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"https://www.googleapis.com/auth/script.external_request"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;MCPA2Aserver&lt;/code&gt; is a Google Apps Script library designed to consolidate Generative AI protocols into a single server solution. It enables developers to easily build and deploy servers supporting both the Model Context Protocol (MCP) and the Agent-to-Agent (A2A) protocol. The repository is available at&lt;a href="https://github.com/tanaikech/MCPA2Aserver-GAS-Library" rel="noopener noreferrer"&gt;https://github.com/tanaikech/MCPA2Aserver-GAS-Library&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this manifest file, only a scope &lt;code&gt;https://www.googleapis.com/auth/script.external_request&lt;/code&gt; is set for using sample 2 skills. However, if you wish to use other scopes, please modify this accordingly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;code.gs&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Copy and paste the following script into &lt;code&gt;code.gs&lt;/code&gt;. Set your API key for using the Gemini API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// --- Your variables ---&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;{apiKey}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Your API key for using Gemini API.&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;models/gemini-3-flash-preview&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;accessKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sample&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// If you want to use an access key for requesting Web Apps, please use this.&lt;/span&gt;
  &lt;span class="c1"&gt;// logSpreadsheetId: "{spreadsheetId}", // If you use this, the logs are stored to Google Spreadsheet.&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// --- Entry Points ---&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;doGet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;doPost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Main Dispatcher Function
 * Routes the request to either A2A handler or MCP handler based on the payload or path.
 *
 * @param {EventObject} e - The event object from doGet/doPost
 * @return {ContentService.TextOutput} The JSON response
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createServerContext_&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Load sample tools.&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;MCPA2Aserver&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a2a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apiKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;accessKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;accessKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;accessKey&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logSpreadsheetId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logSpreadsheetId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logSpreadsheetId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Please get the agent card from the following function.
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getAgentCard&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createServerContext_&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;agentCard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;A2AObj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;agentCard&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;disp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;agentCard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`  &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;disp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;agent.gs&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create another script file named &lt;code&gt;agent.gs&lt;/code&gt; and paste the following code. Make sure to update the &lt;code&gt;url&lt;/code&gt; within &lt;code&gt;agentCard&lt;/code&gt; with your Web App URL later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createServerContext_&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;params_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;get_exchange_rate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Use this to get current exchange rate.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;currency_from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Source currency (major currency). Default is USD.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;currency_to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Destination currency (major currency). Default is EUR.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;currency_date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Date of the currency. Default is latest. It should be ISO format (YYYY-MM-DD).&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;currency_from&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;currency_to&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;currency_date&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;

      &lt;span class="na"&gt;get_current_weather&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Use this to get the weather using the latitude and the longitude.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;At that time, convert the location to the latitude and the longitude and provide them to the function.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="s2"&gt;`The date is required to be included. The date format is "yyyy-MM-dd HH:mm"`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="s2"&gt;`If you cannot know the location, decide the location using the timezone.`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;latitude&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The latitude of the inputed location.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;longitude&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The longitude of the inputed location.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Date for searching the weather. The date format is "yyyy-MM-dd HH:mm"`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;timezone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`The timezone. In the case of Japan, "Asia/Tokyo" is used.`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;latitude&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;longitude&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;date&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;timezone&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;

    &lt;span class="cm"&gt;/**
     * Ref: https://github.com/google/A2A/blob/main/samples/python/agents/langgraph/agent.py#L19
     */&lt;/span&gt;
    &lt;span class="na"&gt;get_exchange_rate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Run the function get_exchange_rate.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Check arguments.&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;currency_from&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;USD&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;currency_to&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;EUR&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;currency_date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;latest&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;resStr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;UrlFetchApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="s2"&gt;`https://api.frankfurter.app/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;currency_date&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;?from=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;currency_from&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;to=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;currency_to&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;getContentText&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resStr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="s2"&gt;`The raw data from the API is &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;resStr&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;. The detailed result is as follows.`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="s2"&gt;`The currency rate at &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;currency_date&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; from "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;currency_from&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;" to "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;currency_to&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;" is &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rates&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;currency_to&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="s2"&gt;.`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;stack&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Check response.&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;mcp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;jsonrpc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt; &lt;span class="na"&gt;isError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;a2a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;

    &lt;span class="cm"&gt;/**
     * This function returns the current weather.
     * The API is from https://open-meteo.com/
     *
     * { latitude = "35.681236", longitude = "139.767125", date = "2025-05-27 12:00", timezone = "Asia/Tokyo" } is Tokyo station.
     */&lt;/span&gt;
    &lt;span class="na"&gt;get_current_weather&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Run the function get_current_weather.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Check arguments.&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;latitude&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;35.681236&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;longitude&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;139.767125&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2025-05-27 12:00&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;timezone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Asia/Tokyo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Ref: https://open-meteo.com/en/docs?hourly=weather_code&amp;amp;current=weather_code#weather_variable_documentation&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Clear sky&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Mainly clear, partly cloudy, and overcast&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Mainly clear, partly cloudy, and overcast&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Mainly clear, partly cloudy, and overcast&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Fog and depositing rime fog&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Fog and depositing rime fog&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="mi"&gt;51&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Drizzle: Light, moderate, and dense intensity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="mi"&gt;53&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Drizzle: Light, moderate, and dense intensity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="mi"&gt;55&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Drizzle: Light, moderate, and dense intensity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="mi"&gt;56&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Freezing Drizzle: Light and dense intensity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="mi"&gt;57&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Freezing Drizzle: Light and dense intensity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="mi"&gt;61&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Rain: Slight, moderate and heavy intensity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="mi"&gt;63&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Rain: Slight, moderate and heavy intensity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="mi"&gt;65&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Rain: Slight, moderate and heavy intensity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="mi"&gt;66&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Freezing Rain: Light and heavy intensity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="mi"&gt;67&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Freezing Rain: Light and heavy intensity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="mi"&gt;71&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Snow fall: Slight, moderate, and heavy intensity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="mi"&gt;73&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Snow fall: Slight, moderate, and heavy intensity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Snow fall: Slight, moderate, and heavy intensity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="mi"&gt;77&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Snow grains&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Rain showers: Slight, moderate, and violent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="mi"&gt;81&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Rain showers: Slight, moderate, and violent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="mi"&gt;82&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Rain showers: Slight, moderate, and violent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="mi"&gt;85&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Snow showers slight and heavy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="mi"&gt;86&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Snow showers slight and heavy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="mi"&gt;95&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Thunderstorm: Slight or moderate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="mi"&gt;96&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Thunderstorm with slight and heavy hail&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="mi"&gt;99&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Thunderstorm with slight and heavy hail&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;endpoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`https://api.open-meteo.com/v1/forecast?latitude=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;latitude&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;longitude=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;longitude&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;hourly=weather_code&amp;amp;timezone=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nx"&gt;timezone&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;resObj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;UrlFetchApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;muteHttpExceptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resObj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getResponseCode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resObj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getContentText&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;hourly&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;weather_code&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;widx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;T&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
          &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;widx&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;weather_code&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;widx&lt;/span&gt;&lt;span class="p"&gt;]];&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;No value was returned. Please try again.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;No value was returned. Please try again.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;stack&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Check response.&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;mcp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;jsonrpc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt; &lt;span class="na"&gt;isError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;a2a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="cm"&gt;/**
   * If you want to return the file content to MCP client, please set the return value as follows.
   * {
   *   jsonrpc: "2.0",
   *   result: {
   *    content:[
   *      {
   *        type: "text",
   *         text: "sample text",
   *       },
   *       {
   *         type: "image",
   *         data: "base64 data",
   *         mimeType: "mimetype",
   *       },
   *     ],
   *     isError: false,
   *   }
   * }
   *
   * If you want to return the file content to A2A client, please set the return value as follows.
   * {
   *   result: {
   *     type: "file",
   *     kind: "file",
   *     file: {
   *       name: "filename",
   *       bytes: "base64 data",
   *       mimeType: "mimetype",
   *     },
   *     metadata: null
   *   }
   * }
   *
   */&lt;/span&gt;

  &lt;span class="c1"&gt;// for A2A&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;agentCard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;API Manager&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="s2"&gt;`Provide management for using various APIs.`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;`- Run with exchange values between various currencies. For example, this answers "What is the exchange rate between USD and GBP?".`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;`- Return the weather information by providing the location and the date, and the time.`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;organization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Tanaike&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://github.com/tanaikech&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1.0.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`https://script.google.com/macros/s/{deploymentId}/exec?accessKey=sample`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;--- Please replace this to your Web Apps URL.&lt;/span&gt;
    &lt;span class="na"&gt;defaultInputModes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text/plain&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;defaultOutputModes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text/plain&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;streaming&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;pushNotifications&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;stateTransitionHistory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;skills&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;get_exchange_rate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Currency Exchange Rates Tool&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Helps with exchange values between various currencies&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;currency conversion&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;currency exchange&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="na"&gt;examples&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;What is exchange rate between USD and GBP?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="na"&gt;inputModes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text/plain&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="na"&gt;outputModes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text/plain&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;get_current_weather&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Get current weather&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;This agent can return the weather information by providing the location and the date, and the time.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;weather&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="na"&gt;examples&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Return the weather in Tokyo for tomorrow's lunchtime.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Return the weather in Tokyo for 9 AM on May 27, 2025.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="na"&gt;inputModes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text/plain&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="na"&gt;outputModes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text/plain&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;A2AObj&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;agentCard&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;agentCard&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  1.1.2 Deploying Google Apps Script as a Web App
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Open the script editor.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Deploy&lt;/strong&gt; &amp;gt; &lt;strong&gt;New deployment&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Web App&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execute as&lt;/strong&gt;: Me.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Who has access&lt;/strong&gt;: Anyone.&lt;/li&gt;
&lt;li&gt;Copy the &lt;strong&gt;Web App URL&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  1.1.3 Configuration
&lt;/h4&gt;

&lt;p&gt;Update the &lt;code&gt;url&lt;/code&gt; property inside the &lt;code&gt;agentCard&lt;/code&gt; variable in your &lt;code&gt;agent.gs&lt;/code&gt; script with your copied Web App URL. Make sure to redeploy the Web App after updating the code to apply the changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  1.2 Configuring the Gemini CLI
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1.2.1 Setting the GAS A2A Server as a Subagent
&lt;/h4&gt;

&lt;p&gt;Despite the advantages of using Google Apps Script, a technical hurdle persists: standard A2A clients cannot natively interact with GAS-based servers automatically. This is because retrieving the agent card dynamically requires a GET request to &lt;code&gt;https://script.google.com/macros/s/{deploymentId}/exec/.well-known/agent.json&lt;/code&gt;. Currently, this endpoint requires access token authorization. While Google Application Default Credentials (ADC) can be used for installing the subagents on Gemini CLI, they are restricted to &lt;code&gt;*.googleapis.com&lt;/code&gt; and &lt;code&gt;*.run.app&lt;/code&gt; endpoints. GAS Web App endpoints are not yet supported for automated retrieval. &lt;a href="https://geminicli.com/docs/core/remote-agents/#google-application-default-credentials-google-credentials" rel="noopener noreferrer"&gt;Ref&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fortunately, remote subagents in the Gemini CLI allow developers to directly define the agent card locally. This elegant workaround bypasses the authentication process entirely and reduces the network overhead of loading the agent card from the GAS Web App.&lt;/p&gt;

&lt;p&gt;To generate the agent card JSON, run the &lt;code&gt;getAgentCard()&lt;/code&gt; function in your &lt;code&gt;code.gs&lt;/code&gt; script. This prints the necessary JSON object to the Apps Script execution console.&lt;/p&gt;

&lt;p&gt;Save the obtained JSON to define the subagent in your working directory. Create a file at &lt;code&gt;.gemini/agents/sample-gas-agent.md&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;remote&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sample-gas-agent&lt;/span&gt;
&lt;span class="na"&gt;agent_card_json&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
  &lt;span class="s"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;"name": "API Manager",&lt;/span&gt;
    &lt;span class="s"&gt;"description": "Provide management for using various APIs.\n- Run with exchange values between various currencies. For example, this answers \"What is the exchange rate between USD and GBP?\".\n- Return the weather information by providing the location and the date, and the time.",&lt;/span&gt;
    &lt;span class="s"&gt;"provider": {&lt;/span&gt;
      &lt;span class="s"&gt;"organization": "Tanaike",&lt;/span&gt;
      &lt;span class="s"&gt;"url": "https://github.com/tanaikech"&lt;/span&gt;
    &lt;span class="s"&gt;},&lt;/span&gt;
    &lt;span class="s"&gt;"version": "1.0.0",&lt;/span&gt;
    &lt;span class="s"&gt;"url": "https://script.google.com/macros/s/{your deployment ID}/exec?accessKey=sample",&lt;/span&gt;
    &lt;span class="s"&gt;"defaultInputModes":[&lt;/span&gt;
      &lt;span class="s"&gt;"text/plain"&lt;/span&gt;
    &lt;span class="s"&gt;],&lt;/span&gt;
    &lt;span class="s"&gt;"defaultOutputModes":[&lt;/span&gt;
      &lt;span class="s"&gt;"text/plain"&lt;/span&gt;
    &lt;span class="s"&gt;],&lt;/span&gt;
    &lt;span class="s"&gt;"capabilities": {&lt;/span&gt;
      &lt;span class="s"&gt;"streaming": false,&lt;/span&gt;
      &lt;span class="s"&gt;"pushNotifications": false,&lt;/span&gt;
      &lt;span class="s"&gt;"stateTransitionHistory": false&lt;/span&gt;
    &lt;span class="s"&gt;},&lt;/span&gt;
    &lt;span class="s"&gt;"skills":[&lt;/span&gt;
      &lt;span class="s"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;"id": "get_exchange_rate",&lt;/span&gt;
        &lt;span class="s"&gt;"name": "Currency Exchange Rates Tool",&lt;/span&gt;
        &lt;span class="s"&gt;"description": "Helps with exchange values between various currencies",&lt;/span&gt;
        &lt;span class="s"&gt;"tags":[&lt;/span&gt;
          &lt;span class="s"&gt;"currency conversion",&lt;/span&gt;
          &lt;span class="s"&gt;"currency exchange"&lt;/span&gt;
        &lt;span class="s"&gt;],&lt;/span&gt;
        &lt;span class="s"&gt;"examples":[&lt;/span&gt;
          &lt;span class="s"&gt;"What is exchange rate between USD and GBP?"&lt;/span&gt;
        &lt;span class="s"&gt;],&lt;/span&gt;
        &lt;span class="s"&gt;"inputModes": [&lt;/span&gt;
          &lt;span class="s"&gt;"text/plain"&lt;/span&gt;
        &lt;span class="s"&gt;],&lt;/span&gt;
        &lt;span class="s"&gt;"outputModes":[&lt;/span&gt;
          &lt;span class="s"&gt;"text/plain"&lt;/span&gt;
        &lt;span class="s"&gt;]&lt;/span&gt;
      &lt;span class="s"&gt;},&lt;/span&gt;
      &lt;span class="s"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;"id": "get_current_weather",&lt;/span&gt;
        &lt;span class="s"&gt;"name": "Get current weather",&lt;/span&gt;
        &lt;span class="s"&gt;"description": "This agent can return the weather information by providing the location and the date, and the time.",&lt;/span&gt;
        &lt;span class="s"&gt;"tags":[&lt;/span&gt;
          &lt;span class="s"&gt;"weather"&lt;/span&gt;
        &lt;span class="s"&gt;],&lt;/span&gt;
        &lt;span class="s"&gt;"examples":[&lt;/span&gt;
          &lt;span class="s"&gt;"Return the weather in Tokyo for tomorrow's lunchtime.",&lt;/span&gt;
          &lt;span class="s"&gt;"Return the weather in Tokyo for 9 AM on May 27, 2025."&lt;/span&gt;
        &lt;span class="s"&gt;],&lt;/span&gt;
        &lt;span class="s"&gt;"inputModes": [&lt;/span&gt;
          &lt;span class="s"&gt;"text/plain"&lt;/span&gt;
        &lt;span class="s"&gt;],&lt;/span&gt;
        &lt;span class="s"&gt;"outputModes":[&lt;/span&gt;
          &lt;span class="s"&gt;"text/plain"&lt;/span&gt;
        &lt;span class="s"&gt;]&lt;/span&gt;
      &lt;span class="s"&gt;}&lt;/span&gt;
    &lt;span class="s"&gt;]&lt;/span&gt;
  &lt;span class="s"&gt;}&lt;/span&gt;
&lt;span class="s"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  1.3 Testing the Connection
&lt;/h3&gt;

&lt;p&gt;Launch the Gemini CLI. The application will detect the new subagent as shown below. Select &lt;code&gt;Acknowledge and Enable&lt;/code&gt; to activate it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feqybuflyuazoiq6tndtn.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feqybuflyuazoiq6tndtn.jpg" alt="fig2a" width="800" height="309"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Running the &lt;code&gt;/agents&lt;/code&gt; command in the chat displays the installed subagents. Your installed &lt;code&gt;sample-gas-agent&lt;/code&gt; will appear under remote agents.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fauvf91nkzzni8w0espyt.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fauvf91nkzzni8w0espyt.jpg" alt="fig2b" width="800" height="329"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also invoke the agent directly using &lt;code&gt;@sample-gas-agent&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz99j3d3422lpb0spyjmm.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz99j3d3422lpb0spyjmm.jpg" alt="fig2c" width="800" height="141"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Input the following sample prompts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What is exchange rate between USD and GBP?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Return the weather in Tokyo for tomorrow's lunchtime.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The following results are returned for each prompt, confirming that the responses were generated securely through the GAS-based &lt;code&gt;sample-gas-agent&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5yxb62wbq6d4n65p8jpy.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5yxb62wbq6d4n65p8jpy.jpg" alt="fig2d" width="800" height="501"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When combining these requests into a single prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I’m planning a trip from London to Japan and need to finalize my budget and itinerary; could you tell me the current USD to GBP exchange rate so I can manage my funds, and also let me know tomorrow's lunchtime weather in Tokyo so I can decide whether to book an outdoor terrace for my arrival meal?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fic826327m4m6fqm5gnqg.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fic826327m4m6fqm5gnqg.jpg" alt="fig2e" width="800" height="363"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The subagent successfully processes both requests and generates the correct response.&lt;/p&gt;

&lt;p&gt;Alternatively, you can direct a specific prompt exclusively to the subagent by prefixing it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@sample-gas-agent What is exchange rate between USD and GBP?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Advanced Integration: Orchestrating Google Workspace with Subagents
&lt;/h2&gt;

&lt;p&gt;As an enhanced test, we will install the &lt;code&gt;google-workspace-orchestrator&lt;/code&gt; subagent, which integrates heavily with Google Workspace to perform complex cross-application tasks.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.1 Building the Advanced A2A Server
&lt;/h3&gt;

&lt;h4&gt;
  
  
  2.1.1 Copying the Google Apps Script
&lt;/h4&gt;

&lt;p&gt;For this advanced setup, copy the following Google Apps Script project by clicking the copy button on the dashboard:&lt;a href="https://script.google.com/home/projects/1xIwskiWAychSp3JN25s7AVbpJf9aRlSvCE8C9szIxPnFHZBeeX3Eo7vT" rel="noopener noreferrer"&gt;https://script.google.com/home/projects/1xIwskiWAychSp3JN25s7AVbpJf9aRlSvCE8C9szIxPnFHZBeeX3Eo7vT&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  2.1.2 Deploying as a Web App
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Open the script editor.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Deploy&lt;/strong&gt; &amp;gt; &lt;strong&gt;New deployment&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Web App&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execute as&lt;/strong&gt;: Me.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Who has access&lt;/strong&gt;: Anyone.&lt;/li&gt;
&lt;li&gt;Copy the &lt;strong&gt;Web App URL&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  2.1.3 Configuration
&lt;/h4&gt;

&lt;p&gt;Update &lt;code&gt;webAppsUrl&lt;/code&gt; within the &lt;code&gt;object&lt;/code&gt; variable in the &lt;code&gt;code.gs&lt;/code&gt; script. Make sure to redeploy the Web App after updating the code.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.2 Configuring the Gemini CLI
&lt;/h3&gt;

&lt;h4&gt;
  
  
  2.2.1 Setting the Advanced Subagent
&lt;/h4&gt;

&lt;p&gt;To define the agent card for this advanced subagent, run the &lt;code&gt;getAgentCard()&lt;/code&gt; function in &lt;code&gt;code.gs&lt;/code&gt;. This will create a text file containing the JSON of the agent card directly in your Google Drive root folder.&lt;/p&gt;

&lt;p&gt;Create a file named &lt;code&gt;.gemini/agents/google-workspace-orchestrator.md&lt;/code&gt; in your working directory and paste the generated JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;remote&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;google-workspace-orchestrator&lt;/span&gt;
&lt;span class="na"&gt;agent_card_json&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
  &lt;span class="s"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;"name": "Google Workspace Orchestrator",&lt;/span&gt;
    &lt;span class="s"&gt;"description": "This agent acts as a comprehensive interface for the Google Workspace ecosystem and associated Google APIs. It provides extensive capabilities to manage and automate tasks across Gmail (sending, organizing, retrieving), Google Drive (file management, search, permission handling, content generation), and Google Calendar (schedule management). It features deep integration with Google Classroom for managing courses, assignments, and rosters, as well as Google Analytics for reporting. Additionally, it controls Google Docs, Sheets, and Slides for document creation and data manipulation. Advanced features include RAG (Retrieval-Augmented Generation) via File Search stores, image generation, YouTube video summarization, and Google Maps utilities. It serves as a central hub for executing complex workflows involving multiple Google services.",&lt;/span&gt;
    &lt;span class="s"&gt;"provider": {&lt;/span&gt;
      &lt;span class="s"&gt;"organization": "Tanaike",&lt;/span&gt;
      &lt;span class="s"&gt;"url": "https://github.com/tanaikech"&lt;/span&gt;
    &lt;span class="s"&gt;},&lt;/span&gt;
    &lt;span class="s"&gt;"version": "1.0.0",&lt;/span&gt;
    &lt;span class="s"&gt;"url": "https://script.google.com/macros/s/{your deployment ID}/exec?accessKey=sample",&lt;/span&gt;
    &lt;span class="s"&gt;"defaultInputModes":[&lt;/span&gt;
      &lt;span class="s"&gt;"text/plain"&lt;/span&gt;
    &lt;span class="s"&gt;],&lt;/span&gt;
    &lt;span class="s"&gt;"defaultOutputModes":[&lt;/span&gt;
      &lt;span class="s"&gt;"text/plain"&lt;/span&gt;
    &lt;span class="s"&gt;],&lt;/span&gt;
    &lt;span class="s"&gt;"capabilities": {&lt;/span&gt;
      &lt;span class="s"&gt;"streaming": false,&lt;/span&gt;
      &lt;span class="s"&gt;"pushNotifications": false,&lt;/span&gt;
      &lt;span class="s"&gt;"stateTransitionHistory": false&lt;/span&gt;
    &lt;span class="s"&gt;},&lt;/span&gt;
    &lt;span class="s"&gt;"skills":[&lt;/span&gt;
      &lt;span class="s"&gt;// ...&lt;/span&gt;
      &lt;span class="s"&gt;// 160 skills&lt;/span&gt;
      &lt;span class="s"&gt;// ...&lt;/span&gt;
   &lt;span class="s"&gt;]&lt;/span&gt;
  &lt;span class="s"&gt;}&lt;/span&gt;
&lt;span class="s"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2.3 Testing the Advanced Workflows
&lt;/h3&gt;

&lt;p&gt;Launch the Gemini CLI and select &lt;code&gt;Acknowledge and Enable&lt;/code&gt; for the newly detected &lt;code&gt;google-workspace-orchestrator&lt;/code&gt; subagent.&lt;/p&gt;

&lt;p&gt;To avoid interference, disable the previous subagent by running the following command in the chat:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/agents disable sample-gas-agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running the &lt;code&gt;/agents&lt;/code&gt; command will now show that the &lt;code&gt;google-workspace-orchestrator&lt;/code&gt; subagent has 160 skills enabled. You can view the full list of detailed skills at &lt;a href="https://github.com/tanaikech/ToolsForMCPServer" rel="noopener noreferrer"&gt;https://github.com/tanaikech/ToolsForMCPServer&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; &amp;gt; /agents

Local Agents

  - Codebase Investigator Agent (codebase_investigator)
    The specialized tool for codebase analysis...
  - CLI Help Agent (cli_help)
    Specialized agent for answering questions about the Gemini CLI...
  - Generalist Agent (generalist)
    A general-purpose AI agent with access to all tools...

Remote Agents

  - google-workspace-orchestrator
    Agent Description: This agent acts as a comprehensive interface for the Google Workspace ecosystem...
    Skills:
    .
    .
    160 skills
    .
    .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Test 1: Generating a Cooking Roadmap&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Input the following prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I want to cook miso soup.
To achieve this goal, create a new Google Spreadsheet,
generate a roadmap for cooking miso soup in the spreadsheet,
and return the Spreadsheet URL.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Gemini CLI initiates the task:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fow5e1rhra2i96ry0jp21.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fow5e1rhra2i96ry0jp21.jpg" alt="fig3a" width="800" height="523"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The requested roadmap is successfully generated and populated into Google Sheets:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqonv0ncbcowvb89tzddi.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqonv0ncbcowvb89tzddi.jpg" alt="fig3b" width="800" height="192"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test 2: Complex Document Generation and Email Delivery&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Input the following prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Write a comprehensive article about developing Google Apps Script (GAS) using generative AI.
The article should include an introductory overview, formatted lists for best practices,
and a table comparing different AI-assisted coding techniques.
Once generated, please create a new Google Document, insert the content, convert the Google Document to a PDF file,
and send an email to `tanaike@hotmail.com` including the shareable URL of the PDF file by giving a suitable title and email body.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Gemini CLI coordinates multiple tools to execute the workflow:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fscn2q7ga9hqpt2xwmou7.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fscn2q7ga9hqpt2xwmou7.jpg" alt="fig3c" width="800" height="574"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The following PDF file is created from the generated Google Document:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffn26sww7llgiweq5rlz5.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffn26sww7llgiweq5rlz5.jpg" alt="fig3d" width="800" height="2011"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, an email containing the PDF link is sent securely:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzdityox43ltuq7zwy3k3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzdityox43ltuq7zwy3k3.jpg" alt="fig3e" width="800" height="157"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Architectural Advantage: Overcoming Tool Space Interference (TSI)
&lt;/h2&gt;

&lt;p&gt;The advanced task demonstrated above requires executing multiple parallel processes natively through the &lt;code&gt;google-workspace-orchestrator&lt;/code&gt; subagent, which contains an astonishing 160 distinct skills.&lt;/p&gt;

&lt;p&gt;When this massive number of skills is loaded directly into a single MCP server or a standard AI context window, it frequently causes a critical challenge known as &lt;strong&gt;Tool Space Interference (TSI)&lt;/strong&gt;. TSI is a phenomenon where verbose metadata saturates the context window, severely degrading the AI's reasoning accuracy and frequently causing logic failures or hallucinations. &lt;a href="https://medium.com/google-cloud/nexus-mcp-a-unified-gateway-for-scalable-and-deterministic-mcp-server-aggregation-3211f0adc603" rel="noopener noreferrer"&gt;Ref&lt;/a&gt; &lt;a href="https://www.microsoft.com/en-us/research/blog/tool-space-interference-in-the-mcp-era-designing-for-agent-compatibility-at-scale/" rel="noopener noreferrer"&gt;Ref&lt;/a&gt; Current industry guidelines suggest a “soft limit” of 20 functions per agent to maintain stability.&lt;/p&gt;

&lt;p&gt;To mitigate TSI, I previously proposed Nexus-MCP. &lt;a href="https://medium.com/google-cloud/nexus-mcp-a-unified-gateway-for-scalable-and-deterministic-mcp-server-aggregation-3211f0adc603" rel="noopener noreferrer"&gt;Ref&lt;/a&gt; Nexus-MCP functions as a centralized gateway employing a deterministic four-phase workflow to map and filter tools. While highly effective, Nexus-MCP relies on a single AI agent acting as the client, making it less suitable for true distributed task execution where specific tool categories should be handled by specialized agents.&lt;/p&gt;

&lt;p&gt;As an alternative approach, I proposed using an A2A server architecture. &lt;a href="https://medium.com/google-cloud/overcoming-tool-space-interference-bridging-google-adk-and-a2a-sdk-via-google-apps-script-44e9f161e235" rel="noopener noreferrer"&gt;Ref&lt;/a&gt; At the time, this required utilizing a heavily modified &lt;code&gt;@a2a-js/sdk&lt;/code&gt; because the agent card could not be natively retrieved from GAS Web Apps.&lt;/p&gt;

&lt;p&gt;A major merit of the integration method introduced in this article is its ability to bypass TSI entirely while using official tools. By directly defining the agent card locally in &lt;code&gt;.gemini/agents/google-workspace-orchestrator.md&lt;/code&gt;, this architecture functions natively within the Gemini CLI. It elegantly avoids TSI by delegating the vast tool execution space entirely to the remote A2A subagent, thereby preserving the main CLI agent's reasoning capacity, stability, and speed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The Gemini CLI now supports remote subagents via the A2A protocol, allowing developers to safely extend and delegate capabilities.&lt;/li&gt;
&lt;li&gt;Google Apps Script (GAS) serves as an ideal, accessible backend for these subagents due to its low-code environment and native integration with Google Workspace.&lt;/li&gt;
&lt;li&gt;Defining the agent card locally in the Gemini CLI easily bypasses the authentication hurdles typically associated with retrieving metadata dynamically from GAS Web Apps.&lt;/li&gt;
&lt;li&gt;This architectural pattern resolves Tool Space Interference (TSI) by offloading massive toolsets (like 160+ Google Workspace skills) to dedicated remote agents.&lt;/li&gt;
&lt;li&gt;Consequently, developers can reliably execute complex, multi-step operations without degrading the reasoning capacity or token limits of the main AI agent.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>gemini</category>
      <category>googleappsscript</category>
      <category>googleworkspace</category>
      <category>a2a</category>
    </item>
    <item>
      <title>Monitoring Sheet Changes with SHEET and SHEETS Functions on Google Sheets</title>
      <dc:creator>Tanaike</dc:creator>
      <pubDate>Wed, 08 Apr 2026 05:38:35 +0000</pubDate>
      <link>https://forem.com/gde/monitoring-sheet-changes-with-sheet-and-sheets-functions-on-google-sheets-19dc</link>
      <guid>https://forem.com/gde/monitoring-sheet-changes-with-sheet-and-sheets-functions-on-google-sheets-19dc</guid>
      <description>&lt;h2&gt;
  
  
  Abstract
&lt;/h2&gt;

&lt;p&gt;Google Sheets recently introduced the &lt;code&gt;SHEET&lt;/code&gt; and &lt;code&gt;SHEETS&lt;/code&gt; functions. Because they automatically recalculate upon structural changes, developers can utilize them as custom triggers. This article demonstrates how to leverage these functions to detect sheet insertions, deletions, renames, and movements without requiring cumbersome installable triggers in Google Apps Script.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;On February 23, 2026, Google introduced two pivotal built-in functions to Google Sheets: &lt;code&gt;SHEET&lt;/code&gt; and &lt;code&gt;SHEETS&lt;/code&gt; &lt;a href="https://workspaceupdates.googleblog.com/2026/02/two-new-functions-in-google-sheets.html" rel="noopener noreferrer"&gt;Ref&lt;/a&gt;. The &lt;code&gt;SHEET&lt;/code&gt; function returns the index (sheet number) of a specified sheet or reference &lt;a href="https://support.google.com/docs/answer/16865249?dark=1&amp;amp;hl=en" rel="noopener noreferrer"&gt;Ref&lt;/a&gt;. Meanwhile, the &lt;code&gt;SHEETS&lt;/code&gt; function provides the total count of sheets within a spreadsheet &lt;a href="https://support.google.com/docs/answer/16865347?dark=1&amp;amp;hl=en" rel="noopener noreferrer"&gt;Ref&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A critical technical characteristic of these functions is their volatility and automatic recalculation based on the spreadsheet's structural metadata. Specifically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;SHEET&lt;/code&gt; triggers a recalculation when a sheet is renamed or its position is changed via drag-and-drop.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SHEETS&lt;/code&gt; triggers a recalculation whenever a sheet is inserted, duplicated, or removed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Historically, detecting such structural changes necessitated the use of an &lt;strong&gt;installable OnChange trigger&lt;/strong&gt; in Google Apps Script (GAS). This posed a significant barrier for template distribution, as installable triggers require manual authorization by each user and do not persist through simple file copies.&lt;/p&gt;

&lt;p&gt;By leveraging these new functions as "custom triggers," we can effectively bypass the need for installable triggers. When a custom function or formula containing &lt;code&gt;SHEET&lt;/code&gt; or &lt;code&gt;SHEETS&lt;/code&gt; recalculates, it serves as a catalyst for GAS execution. This enables the creation of self-contained spreadsheets where advanced sheet monitoring logic is activated immediately upon copying the file, significantly improving the user experience and portability of GAS-based solutions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0cjy8kgmtlpqbb93sk0d.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0cjy8kgmtlpqbb93sk0d.jpg" alt="fig1" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation Guide
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Spreadsheet Initialization
&lt;/h3&gt;

&lt;p&gt;Create a new Google Sheets file to serve as your testing environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Google Apps Script Configuration
&lt;/h3&gt;

&lt;p&gt;Open the Google Apps Script editor bound to your new spreadsheet. Copy and paste the following script, replacing any default code, and save your project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Global constant defining the Script Properties storage key.
 */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;STORAGE_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SHEET_STATUS_CACHE&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Simple trigger to initialize the cached sheet metadata upon opening the spreadsheet.
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;onOpen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;updateStoredSheetData_&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Custom function wrapper to retrieve an array of all current sheet names.
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getAllSheetNames&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;SpreadsheetApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getActiveSpreadsheet&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSheets&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Core custom function for detecting structural alterations.
 * Priority: If any structural change (Add/Remove/Rename) occurs,
 * subsequent "move" reports are suppressed to avoid noise from index shifting.
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getSheetStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_trigger1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;_trigger2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;returnRawObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;propService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;PropertiesService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getScriptProperties&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;oldDataJson&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;propService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;STORAGE_KEY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;SpreadsheetApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getActiveSpreadsheet&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;currentSheets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSheets&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;currentSheets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSheetId&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}));&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;oldDataJson&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;updateStoredSheetData_&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Initial state recorded.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;oldData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;oldDataJson&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}));&lt;/span&gt;

  &lt;span class="c1"&gt;// Categorize detected modifications into structural changes or simple index moves.&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;structural&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;moves&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;detectCategorizedChanges_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;oldData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Persist the newly fetched metadata to Script Properties.&lt;/span&gt;
  &lt;span class="nx"&gt;propService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;STORAGE_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;}))),&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Evaluate which results to return based on change priority.&lt;/span&gt;
  &lt;span class="c1"&gt;// Ignore index movement noise if a primary structural change (addition, removal, rename) occurred.&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;finalDiffs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;structural&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;structural&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;moves&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;finalDiffs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;No change&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;returnRawObject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;finalDiffs&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;finalDiffs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Retrieves current spreadsheet metadata and persists it to the properties cache.
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateStoredSheetData_&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;SpreadsheetApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getActiveSpreadsheet&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sheetData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSheets&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSheetId&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="p"&gt;}));&lt;/span&gt;
  &lt;span class="nx"&gt;PropertiesService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getScriptProperties&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;setProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;STORAGE_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sheetData&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;sheetData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Differentiates between core structural changes and simple index shifts.
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;detectCategorizedChanges_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;oldData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;structural&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;moves&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;oldMap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;oldData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;]));&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newMap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;]));&lt;/span&gt;

  &lt;span class="c1"&gt;// 1. Identify removed sheets (Structural change).&lt;/span&gt;
  &lt;span class="nx"&gt;oldData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;oldSheet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;newMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;oldSheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;structural&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;removed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`"&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;oldSheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;" was removed.`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// 2. Identify added, renamed, or repositioned sheets.&lt;/span&gt;
  &lt;span class="nx"&gt;newData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;newSheet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;oldSheet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;oldMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newSheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;oldSheet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Handle added sheets (Structural change).&lt;/span&gt;
      &lt;span class="nx"&gt;structural&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;added&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`"&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;newSheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;" was inserted at tab &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;newSheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isRenamed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;oldSheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;newSheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isMoved&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;oldSheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;newSheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isRenamed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Handle renamed sheets (Structural change).&lt;/span&gt;
        &lt;span class="nx"&gt;structural&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;renamed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`"&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;oldSheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;" was renamed to "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;newSheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;".`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isMoved&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Handle pure index movements (Non-structural change).&lt;/span&gt;
        &lt;span class="nx"&gt;moves&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;moved&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`"&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;newSheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;" was moved from tab &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;oldSheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; to &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;newSheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;structural&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;moves&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Optional callback for installable OnChange triggers.
 * If utilized, do not use the custom formula in the sheet.
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;changeType&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;OTHER&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;INSERT_GRID&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;REMOVE_GRID&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;changeType&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getSheetStatus&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;Browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;msgBox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Applying the Custom Formula
&lt;/h3&gt;

&lt;p&gt;Return to your Google Sheets interface. In the first sheet, copy and paste the following formula into cell &lt;code&gt;A1&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=getSheetStatus(SHEETS(),MAP(getAllSheetNames(),lambda(sheetname,SHEET(sheetname))))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Testing the Workflow
&lt;/h3&gt;

&lt;p&gt;Once the formula is in place, the cell will actively monitor the document's structure. The demonstration below illustrates the expected behavior:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp1dmydxh5p1ekfpgg252.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp1dmydxh5p1ekfpgg252.gif" alt="fig2" width="800" height="402"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;During the demonstration, the following actions trigger a status update in the cell:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Renaming an existing sheet.&lt;/li&gt;
&lt;li&gt; Adding a new sheet to the workbook.&lt;/li&gt;
&lt;li&gt; Changing the order (moving) of a sheet.&lt;/li&gt;
&lt;li&gt; Deleting a sheet.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Appendix: Using Traditional Triggers
&lt;/h2&gt;

&lt;p&gt;If you prefer to use the traditional installable &lt;code&gt;onChange&lt;/code&gt; trigger method, you can utilize the &lt;code&gt;onChange&lt;/code&gt; function provided at the bottom of the script. In this scenario, you must manually bind the trigger to the &lt;code&gt;onChange&lt;/code&gt; function via the Apps Script dashboard and &lt;strong&gt;remove&lt;/strong&gt; the custom formula (&lt;code&gt;=getSheetStatus(...)&lt;/code&gt;) from cell &lt;code&gt;A1&lt;/code&gt;. The underlying logic handles the detection identically, routing the output to a browser message box instead of a cell.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The introduction of &lt;code&gt;SHEET&lt;/code&gt; and &lt;code&gt;SHEETS&lt;/code&gt; functions enables automatic formula recalculation based on structural metadata changes.&lt;/li&gt;
&lt;li&gt;These built-in functions can be passed into custom Google Apps Script functions to act as volatile execution triggers.&lt;/li&gt;
&lt;li&gt;This methodology eliminates the traditional dependency on installable &lt;code&gt;onChange&lt;/code&gt; triggers for monitoring tab modifications.&lt;/li&gt;
&lt;li&gt;Removing installable triggers drastically improves script portability and the user experience when distributing spreadsheet templates.&lt;/li&gt;
&lt;li&gt;The provided script successfully categorizes and logs structural alterations versus simple index shifts for comprehensive monitoring.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>googleappsscript</category>
      <category>googleworkspace</category>
      <category>googlesheets</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Recursive Knowledge Crystallization: Enabling Persistent Evolution and Zero-Shot Transfer in AI Agents</title>
      <dc:creator>Tanaike</dc:creator>
      <pubDate>Thu, 02 Apr 2026 06:50:50 +0000</pubDate>
      <link>https://forem.com/gde/recursive-knowledge-crystallization-enabling-persistent-evolution-and-zero-shot-transfer-in-ai-4fh7</link>
      <guid>https://forem.com/gde/recursive-knowledge-crystallization-enabling-persistent-evolution-and-zero-shot-transfer-in-ai-4fh7</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flbx0q0fu8jaosvbqg0sq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flbx0q0fu8jaosvbqg0sq.jpg" alt="fig1a" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Abstract
&lt;/h2&gt;

&lt;p&gt;This paper presents a self-evolving framework, &lt;strong&gt;Recursive Knowledge Crystallization (RKC)&lt;/strong&gt;, designed to overcome the "Catastrophic Forgetting" inherent in autonomous AI agents. By persisting evolved technical insights into a universally readable &lt;code&gt;SKILL.md&lt;/code&gt; file based on the &lt;a href="https://agentskills.io/home" rel="noopener noreferrer"&gt;Agent skills&lt;/a&gt; specification, this approach establishes long-term memory and cross-platform portability. The framework was empirically validated through the development of &lt;a href="https://github.com/brucemcpherson/gas-fakes" rel="noopener noreferrer"&gt;gas-fakes&lt;/a&gt;, a highly complex Node.js-to-Google Apps Script (GAS) emulation library. The results demonstrate that agents can autonomously internalize project-specific architectural patterns and environmental nuances. Consequently, the framework achieves &lt;strong&gt;Zero-Shot Knowledge Transfer&lt;/strong&gt; across distinct toolchains (Google Antigravity and the Gemini CLI) while maintaining absolute 1:1 behavioral parity with the live GAS environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Introduction
&lt;/h2&gt;

&lt;p&gt;In recent years, the automation of software development by autonomous AI agents powered by Large Language Models (LLMs) has advanced rapidly. However, a critical barrier to the practical deployment of such agents is the absence of a "Persistence of Learning." Constrained by LLM context windows and session fragmentation, agents frequently suffer from "Catastrophic Forgetting," losing vital insights acquired during previous interactions. While memory-augmentation frameworks like Reflexion (Shinn et al., 2023) and MemGPT (Packer et al., 2023) have been proposed, they heavily rely on in-memory contexts, dedicated vector databases, or internal virtual memory abstractions. As a result, the acquired knowledge remains locked within specific agent instances, rendering it difficult to port across environments and nearly impossible for human developers to directly audit or manage.&lt;/p&gt;

&lt;p&gt;While this limitation might remain latent in small-scale "greenfield" projects, it emerges as a fatal bottleneck when applying Generative AI to large, complex, and deeply constrained legacy projects. The&lt;a href="https://github.com/brucemcpherson/gas-fakes" rel="noopener noreferrer"&gt;gas-fakes&lt;/a&gt; project, the subject of this empirical study, encountered this exact limitation. This project serves as a foundational library for converting various Google APIs into mock classes and methods compatible with the Google Apps Script (GAS) environment using Node.js. As the codebase and conversion rules grew in complexity, traditional prompting and standard GenAI approaches frequently resulted in "rule violations"—instances where the AI bypassed strict, project-specific coding conventions to force task completion. Despite repeated trial-and-error iterations and manual context adjustments, the success rate remained insufficient for practical use.&lt;/p&gt;

&lt;p&gt;To fundamentally resolve this challenge, this paper introduces a self-evolving framework based on the &lt;a href="https://agentskills.io/home" rel="noopener noreferrer"&gt;Agent skills&lt;/a&gt; specification and its dynamic evolution model:&lt;a href="https://medium.com/google-cloud/recursive-knowledge-crystallization-a-framework-for-persistent-autonomous-agent-self-evolution-8243b3697471" rel="noopener noreferrer"&gt;Recursive Knowledge Crystallization (RKC)&lt;/a&gt;. The defining innovation of this framework is the &lt;strong&gt;"Physical Knowledge Persistence"&lt;/strong&gt; of the agent's operational guidelines and technical expertise. This knowledge is crystallized as a universally readable Markdown file (&lt;code&gt;SKILL.md&lt;/code&gt;) directly onto the local file system.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fef19nnblij8npvy0xknl.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fef19nnblij8npvy0xknl.jpg" alt="RKC Framework Architecture" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By integrating Gemini 3 and 3.1 with next-generation toolchains—Google Antigravity and the Gemini CLI—we established the development process of &lt;code&gt;gas-fakes&lt;/code&gt; itself as the agent's continuous learning environment. Specifically, whenever an error occurred during the implementation of new classes or when human developers provided corrective feedback, the agent was issued a single meta-instruction: "Extract insights from the failure and recovery process, and autonomously update your Agent skill (&lt;code&gt;SKILL.md&lt;/code&gt;, sample scripts, and templates) by adding, deleting, or modifying content."&lt;/p&gt;

&lt;p&gt;Through this iterative trial-and-error cycle, the agent accomplished more than merely avoiding local errors; it decoded the implicit rules and complex constraints inherent in the Node.js-to-GAS conversion, eventually internalizing and formalizing the project’s overarching architectural patterns. This evolutionary process extended beyond the &lt;code&gt;SKILL.md&lt;/code&gt; text to include the refinement of helper scripts, templates, and technical specifications.&lt;/p&gt;

&lt;p&gt;As the RKC progressed and the Agent skill reached a state of convergence, the agent fully internalized the complex operational logic of &lt;code&gt;gas-fakes&lt;/code&gt;. This enabled accurate, rapid development strictly compliant with all project standards. Furthermore, by utilizing the standard file format, this method facilitates &lt;strong&gt;"Zero-Shot Knowledge Transfer"&lt;/strong&gt;: implicit knowledge acquired in one environment (e.g., Google Antigravity) can be seamlessly ported to an entirely clean environment (e.g., Gemini CLI) to generate flawless code on the first attempt. Simultaneously, persisting knowledge on a standard file system realizes a &lt;strong&gt;"True Human-AI Collaborative Paradigm,"&lt;/strong&gt; empowering human developers to fully visualize, audit, and guide the agent's cognitive evolution.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Workflow
&lt;/h2&gt;

&lt;p&gt;The development of &lt;code&gt;gas-fakes&lt;/code&gt; follows an iterative evolution of Agent skills, leveraging both Google Antigravity and the Gemini CLI. This process integrates a continuous feedback loop and culminates in Zero-Shot Knowledge Transfer through the physical persistence of evolved skills. The operational flow, visualized in &lt;strong&gt;Figure 2a&lt;/strong&gt;, is defined by the following seven stages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Task Initiation&lt;/strong&gt;: A development task is assigned via a prompt to either Google Antigravity or the Gemini CLI, specifying the Google Apps Script (GAS) classes and methods to be emulated in the Node.js environment.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Autonomous Implementation&lt;/strong&gt;: Utilizing the current Agent skill (&lt;code&gt;gas-fakes-dev&lt;/code&gt;), the agent generates the corresponding Node.js classes and methods. Simultaneously, a test suite is authored by strictly adhering to the architectural patterns defined within the &lt;code&gt;SKILL.md&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Local Environment Validation&lt;/strong&gt;: The generated test scripts are executed in the local Node.js environment. If runtime errors or logic discrepancies occur, the AI autonomously refactors the implementation and the test code until local stability is achieved.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Cross-Platform Synchronization&lt;/strong&gt;: Following local success, the implementation is deployed to the Google-side script editor (GAS environment). This ensures that the emulation maintains 1:1 parity with the live GAS engine.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Remote Feedback &amp;amp; Refinement&lt;/strong&gt;: If the test suite encounters environment-specific errors in the GAS script editor (e.g., subtle differences in string output formatting or synchronous execution behavior), these errors are fed back to the AI for immediate remediation.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Knowledge Crystallization&lt;/strong&gt;: Once the implementation passes in both local and remote environments, the task is flagged as complete. At this juncture, the AI performs a self-audit to extract critical insights—such as previously undocumented GAS constraints or reusable design patterns—and autonomously updates the Agent skill (&lt;code&gt;SKILL.md&lt;/code&gt;, helper scripts, and templates).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Recursive Evolution Loop&lt;/strong&gt;: Stages 1 through 6 are continuously cycled. As the &lt;code&gt;SKILL.md&lt;/code&gt; matures, it transitions from a set of generalized instructions to a highly specialized, project-aware expert system, enabling the agent to resolve increasingly complex architectural challenges with minimal human intervention.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5pfmjjkl0lqycuyq88uq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5pfmjjkl0lqycuyq88uq.jpg" alt="Workflow" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fig 2a: The 7-stage operational workflow of Recursive Knowledge Crystallization.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Methodology: Environment Setup and Initialization
&lt;/h2&gt;

&lt;p&gt;In this article, it is assumed that Node.js, Google Antigravity, and Gemini CLI have already been installed. To establish the baseline for developing &lt;code&gt;gas-fakes&lt;/code&gt;, the repository is cloned as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/brucemcpherson/gas-fakes
&lt;span class="nb"&gt;cd &lt;/span&gt;gas-fakes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this empirical study, Google Antigravity and Gemini CLI were utilized in tandem to evolve the agent skill. First, the initial agent skill was established. The directory structure is outlined below. To ensure both agent environments utilized the exact same skill base (&lt;code&gt;gas-fakes-dev&lt;/code&gt;), they were synchronized using a symbolic link.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gas-fakes/
├── .agent/
│   └── skills/
│       └── gas-fakes-dev/
│           └── SKILL.md
└── .gemini/
    └── skills -&amp;gt; ../.agent/skills/  (symbolic link)
        └── gas-fakes-dev/
            └── SKILL.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, to avoid manual linking between the &lt;code&gt;.agents&lt;/code&gt; and &lt;code&gt;.gemini&lt;/code&gt; directories, the &lt;code&gt;gemini.md&lt;/code&gt; configuration file can be utilized to instruct the Gemini CLI to consistently reference the &lt;code&gt;.agents/workloads&lt;/code&gt; and &lt;code&gt;.agents/skills&lt;/code&gt; folders. This ensures seamless resource sharing between the CLI and Google Antigravity. Furthermore, including a directive to automatically activate the &lt;code&gt;gas-fakes-dev&lt;/code&gt; skill within this configuration streamlines the entire initialization process.&lt;/p&gt;

&lt;p&gt;The baseline &lt;code&gt;SKILL.md&lt;/code&gt; was formulated as a generic directive. During the development of &lt;code&gt;gas-fakes&lt;/code&gt;, this specific skill file served as the target for continuous evolution.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
name: gas-fakes-dev
description: "Develop and implement the 'gas-fakes' project, emulating Google Apps Script (GAS) functionality using Node.js."
tags:[nodejs, google-apps-script, google-cloud-api, testing, mock]
version: "1.0.0"
---

## Summary
This skill enables the agent to assist in the development of the `gas-fakes` project. The primary objective is to emulate Google Apps Script (GAS) behavior using Node.js and Google APIs, allowing Apps Script code to run in a local Node.js environment.

## Usage
- When you need to implement fake/mock functionality for GAS classes or methods.
- When creating test scripts to verify the implemented functionalities.
- When assisting a human developer with Node.js and Google APIs integration.

## Workflow

### 1. Context and Specification Check
Before implementing, verify the specifications of the target Google Apps Script classes and methods. Ensure that the functionality you are about to build aligns with real GAS behavior.

### 2. Implementation
Generate Node.js code that maps GAS methods to the corresponding Google Cloud APIs.
- Refer to the existing codebase in the `src/` directory to understand the current architecture.
- Ensure the code runs correctly in the Node.js environment.

### 3. Testing
You must verify your implementation by writing and executing test scripts.
- Place your test scripts in the `test/` directory.
- Execute the tests to ensure there are no errors and the behavior matches expectations.

### 4. Holistic/Targeted Skill Evolution (Self-Updating SKILL)
**[CRITICAL INSTRUCTION]**
The `gas-fakes` project is complex, and bridging Node.js with GAS involves many hidden constraints, specific architectural patterns, and potential errors. You are required to continuously learn and autonomously evolve this SKILL.

- **Trigger:** Whenever you encounter an error during implementation or testing, or when you receive correction feedback/prompts from the human developer.
- **Action:** You MUST extract the lessons learned from the failure and recovery process. Identify the underlying rules, technical constraints, or coding patterns that caused the issue.
- **Update:** Immediately update this `SKILL.md` file (by adding, deleting, or modifying content) to document the newly acquired knowledge. If necessary, also create or update sample scripts, helper templates, or explanatory Markdown files in the project.
- **Goal:** Transform your localized, temporary learnings into permanent, universally readable knowledge to prevent repeating the same mistakes and to handle the complexities of the project autonomously.

## Delivery
- Output the complete code for modified or newly created service classes and test scripts.
- **ALWAYS output the updated `SKILL.md`** when new knowledge is extracted and crystallized.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Also, please install Model Context Protocol (MCP) servers for Google Workspace development. &lt;a href="https://developers.google.com/workspace/guides/developer-tools#mcp" rel="noopener noreferrer"&gt;Ref&lt;/a&gt; This MCP server is used from this agent skill.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When a command &lt;code&gt;/gas-fakes-dev&lt;/code&gt; is put into the chat, this skill can be activated.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Because &lt;code&gt;gas-fakes&lt;/code&gt; emulates Google Apps Script using Node.js, generated test scripts are strictly required to function flawlessly in both the local Node.js environment and the cloud-based Google Apps Script editor. Utilizing the initial, generic skill often resulted in scripts that passed locally but failed in the cloud environment. This discrepancy served as the primary catalyst for triggering the agent's evolutionary loop.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Crystallization of Knowledge: The Evolved Agent Skill
&lt;/h2&gt;

&lt;p&gt;After extensive trial and error implementing various GAS classes and methods, the agent dynamically restructured and expanded its own skill set.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F666xatrumohah5vj9h9y.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F666xatrumohah5vj9h9y.jpg" alt="Agent Skill Evolution Comparison" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The evolved repository structure incorporated new templates, examples, and scripts generated by the agent to support its new architectural insights. You can see the details of this agent skill from &lt;a href="https://github.com/tanaikech/agent-skill-for-developing-gas-fakes" rel="noopener noreferrer"&gt;https://github.com/tanaikech/agent-skill-for-developing-gas-fakes&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gas-fakes/
├── .agent/
│   └── skills/
│       └── gas-fakes-dev/
│           ├── examples/
│           │   ├── batch_update_pattern.js
│           │   └── proxy_guard_pattern.js
│           ├── resources/
│           │   ├── class_template.js
│           │   ├── sync_mechanism.md
│           │   └── test_template.js
│           ├── scripts/
│           │   ├── run_target_test.js
│           │   └── scaffold_service.js
│           └── SKILL.md
└── .gemini/
    └── skills -&amp;gt; ../.agent/skills/  (symbolic link)
        └── gas-fakes-dev/
            ├── examples/
            ├── resources/
            ├── scripts/
            └── SKILL.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The resultant, highly complex &lt;code&gt;SKILL.md&lt;/code&gt; (Version 2.0.0) evolved into a comprehensive system architecture document as follows. &lt;a href="https://github.com/tanaikech/agent-skill-for-developing-gas-fakes/blob/master/gas-fakes-dev/SKILL.md" rel="noopener noreferrer"&gt;Ref&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
name: gas-fakes-dev
description: Develop, implement, and test the 'gas-fakes' project, emulating ALL Google Apps Script (GAS) functionality using Node.js and Google APIs.
tags: [nodejs, google-apps-script, google-cloud-api, testing, mock, simulation]
version: "2.0.0"
---

## Summary
This skill enables the agent to act as a Senior Expert proficient in Node.js, Google Cloud, and Shell Scripting to assist in the development of the `gas-fakes` project.
The ultimate objective is to **emulate the behavior of live Google Apps Script exactly** by mapping classes and methods to their fake equivalents. This allows Apps Script to run anywhere Node runs.
This is achieved using a **worker mechanism** to handle the conversion from synchronous (Apps Script) to asynchronous (Google APIs) operations, returning the results synchronously. Ultimately, all Apps Script classes and methods will be available via `gas-fakes`. For a deep dive into this mechanism, see the [Sync-to-Async Bridge Guide](./resources/sync_mechanism.md).

## Usage
- When you need to implement or modify mock functionality for specific GAS classes or methods.
- When creating logic that reproduces GAS behavior using Google APIs and the worker mechanism.
- When adding new service classes to fit the existing `gas-fakes` project structure.
- When creating test scripts and registering them for local execution within the `test/` directory.
- When executing generated Apps Script files locally.
- When technical advice or debugging assistance based on GAS specifications is required.

## Configuration
`gas-fakes` relies on an `.env` file (maintained by `gas-fakes init` and `auth`) to properly authenticate and run.

### Authentication Methods
- **DWD (Domain Wide Delegation) - *Preferred***: Uses a service account to impersonate a user logged into gcloud. The service account name must be specified in the `.env` file. This is **required** if restricted/sensitive scopes are needed, or if running `gas-fakes` on Google Cloud Run.
- **ADC (Application Default Credentials)**: If no `.env` file is provided, `gas-fakes` falls back to ADC. This is usually fine for local development as standard `cloud_platform` and `drive` scopes are automatically assigned during auth.

Ensure your `.env` is properly loaded (e.g., using `node --env-file &amp;lt;env-file&amp;gt;` or `gas-fakes -e &amp;lt;env-file&amp;gt;`) to ensure DWD is used when necessary.
- **`TEST_SPREADSHEET_ID`**: (Optional) Spreadsheet ID for real-environment testing.

## Workflow

### 1. Context, Specification, and Dependency Check
Before starting implementation, you must understand the full scope and style of the project.

- **Restricted Directories**:
  * **NEVER modify any files located in the `progress` directory** during the development of `gas-fakes`. This directory is strictly off-limits.

- **Mandatory Existence Verification**:
  When adding or updating ANY class or method, you must **ALWAYS use the `workspace-developer` MCP server** (if available) or search official documentation to verify the existence and specification of the target and ALL related classes/methods.
  *   **NEVER create classes or methods that do not exist in the actual Google Apps Script environment.**
  *   Do not guess. Confirm exact names, parameter structures, and return types.
  *   *Example*: If implementing `Sheet.getCharts()`, check what object it returns (`EmbeddedChart` vs `Chart`) and verify the methods available on that returned object.

- **Strict Enum Verification**:
  **Do not invent Enums.** Before using or creating an Enum, verify if it actually exists in Google Apps Script.
  *   **Note on `ChartType`**: In Google Apps Script, `ChartType` is a property of the `Charts` service (`Charts.ChartType`), not `SpreadsheetApp`.

- **Reference Existing Code**:
  Check the `src` and `test` directories to understand the existing coding style and architecture. Apply these patterns to new classes and methods.

- **Identify Dependencies**:
  Identify and implement **all related classes and methods** required for the target feature. (e.g., if `newChart()` returns `EmbeddedChartBuilder`, verify/implement that builder class too).

### 2. Scaffolding
Do not create service files manually. Use the provided helper script.

- **Command**:
  \`\`\`bash
  node .agent/skills/gas-fakes-dev/scripts/scaffold_service.js --service=&amp;lt;ServiceName&amp;gt; --class=&amp;lt;ClassName&amp;gt;
  \`\`\`

### 3. Implementation
Generate code based on Node.js best practices, adhering to these rules to maintain environmental consistency with live Apps Script:

- **Comprehensive Implementation**: Implement the target feature and its dependencies together.
- **Cross-Environment Compatibility**: Scripts must be designed to run on both Node.js (local) and GAS Script Editor with identical results.
- `toString()` Accuracy: The `toString()` method must return the **exact GAS class name or specific string output** (e.g., `"Sheet"` or `"[Document:  ...]"`). Pay extreme attention to whitespace; GAS output can contain double spaces (e.g., after a colon).
- **Dynamic Resources and Caching Pattern**:
  *   **The `__resource` property**: Always access the underlying API state via the dynamic `__resource` getter (tracing back to the parent element or a synchronized cache).
  *   **Stale State Prevention**: NEVER store API resources directly in class instance variables. They will become stale when the cache is cleared.
  *   **Cache Invalidation**: Every time a destructive API call is made, the cache is cleared. Dynamically accessing `__resource` ensures you get the most up-to-date state from the API or the fresh cache.
- **Implementation Patterns**:
  1. Use `signatureArgs` or `is.*` utilities.
  2. Construct the request object.
  3. Execute via `this.__batchUpdate` (or helper).
  4. Return `this` for chaining.

- **Coding Patterns**:
  *   **Naming**: Internal implementation classes should be prefixed with `Fake` (e.g., `FakeSheet`, `FakeEmbeddedChart`).
  *   **Lazy Loading**: New top-level services must be registered using the `lazyLoaderApp` pattern in their respective `app.js` to ensure they are only instantiated when accessed.
  *   **Singleton Pattern**: Service entry points usually export a "maker" function (e.g., `newFakeSpreadsheetApp`) that return the singleton instance.

- **Specific Technical Nuances**:
  *   **Sync-to-Async Bridge**: Always use the worker bridge for external API calls to maintain synchronous Apps Script behavior. Follow the pattern: `Fake Class` -&amp;gt; `Syncit (fx*)` -&amp;gt; `callSync` -&amp;gt; `Worker Loop` -&amp;gt; `sx* Function` -&amp;gt; `sxRetry`. See [detailed guide](./resources/sync_mechanism.md) for implementation steps.
  *   **Charts**: When retrieving a chart's title, use `getOptions().get("title")` instead of internal specs.
  *   **EmbeddedChart**: To get the type of an existing chart, use `modify().getChartType()` instead of a non-existent `getType()` method.
  *   **GridRange to FakeRange Conversion**: When mapping an API `GridRange` to a `FakeSheetRange`:
    *   Indices in the API are 0-indexed and the end index is **exclusive**.
    *   GAS methods (like `getRange(row, col, numRows, numCols)`) use 1-indexed start positions and row/column counts.
    *   If `endRowIndex` or `endColumnIndex` is undefined in the API response, it means the range extends to the boundary of the sheet. Use `sheet.getMaxRows()` and `sheet.getMaxColumns()` as fallbacks to calculate `numRows` and `numCols`.
  *   **ContainerInfo**: This class is used by `EmbeddedChart`, `Slicer`, and `Drawing`.
    *   Map `getAnchorRow()` and `getAnchorColumn()` to 0-indexed API fields `anchorCell.rowIndex + 1` and `anchorCell.columnIndex + 1`.
    *   Map `getOffsetX()` and `getOffsetY()` directly to `offsetXPixels` and `offsetYPixels`.
  *   **XmlService**:
    *   `Element.getName()` returns the **local name** (no prefix).
    *   `Document.toString()` output is very specific: `[Document:  No DOCTYPE declaration, Root is [Element: &amp;lt;rootName/&amp;gt;]]` (note the double space after `Document:`).
    *   Namespace-aware methods (like `getChild(name, namespace)`) require mapping prefixes and URIs correctly.

### 4. Testing
You must ensure every implementation is verified by tests that precisely emulate Google Apps Script behavior.

- **Mandatory Feature Coverage**:
  - **Every new class or method MUST have a corresponding test.**
  - If you implement multiple methods, create a test script that exercises all of them.
  - Test only implemented features; do not include placeholders for future work.

- **Edge Case Capturing**:
  - **Capture and verify boundary conditions, invalid inputs, and error states.**
  - Use `t.rxMatch(t.threw(() =&amp;gt; ...).message, /regex/)` to verify that methods throw expected GAS error messages when given invalid arguments.
  - Test with `null`, `undefined`, empty strings, and out-of-bounds values where applicable to ensure robust emulation.

- **GAS Compatibility Requirement**:
  - Test logic (inside `unit.section`) must be compatible with the **Google Apps Script script editor**.
  - Avoid Node.js-specific modules (e.g., `fs`, `path`) inside the test logic.
  - Use `ScriptApp.isFake` or `xxxApp.isFake` to toggle environment-specific logging or assertions.

- **Test Script Structure**:
  - **Imports**: standard test scripts import `@mcpher/gas-fakes`, `@sindresorhus/is`, and helpers from `./testinit.js` and `./testassist.js`.
  - **Export Pattern**: Export a named function (e.g., `export const testService = (pack) =&amp;gt; { ... }`) to allow integration into the main test suite.
  - **Execution Hook**: Always include `wrapupTest(testService);` at the end of the file for standalone execution.
  - **Sections**: Use `unit.section("description", (t) =&amp;gt; { ... })` to group tests.

- **Resource Lifecycle and Cleanup**:
  - **The `toTrash` pattern**: Maintain a `toTrash` array within your test function. Push any created resources (files, folders, sheets) into this array.
  - **Automatic Cleanup**: Use `trasher(toTrash)` at the end of the test function (usually triggered if `fixes.CLEAN` is true) to ensure the test environment remains pristine.

- **Naming Convention**:
  - **Google Sheets**: `testsheets{class name}.js` (e.g., `testsheetsrange.js`)
  - **Google Docs**: `testdocs{class name}.js`
  - **Google Slides**: `testslides{class name}.js`
  - **General/Other**: `test{service}{class name}.js`

- **Registration**:
  1. Create the file in `test/`.
  2. Add to `test/test.js`.
  3. Add a script entry in `test/package.json`.

- **Execution**:
  &amp;gt; [!IMPORTANT]
  &amp;gt; **Run tests from the `test/` directory.**
  &amp;gt; `cd test &amp;amp;&amp;amp; node test{filename}.js execute` (or `npm run &amp;lt;script-name&amp;gt;`).

- **Clasp Verification**:
  Use `testongas/test/` to verify against a real GAS project via `clasp`.

### 5. Executing Generated Scripts
You can execute any generated Apps Script file using `gas-fakes` in a local sandbox.

- **Testing the Local Branch (Preferred for Dev)**:
  Use the local `.env` file and run the local `gas-fakes` implementation.
  \`\`\`bash
  node --env-file ./.env gas-fakes -f myscript.js
  \`\`\`
- **Testing Global Installation**:
  \`\`\`bash
  npx gas-fakes -f myscript.js
  \`\`\`
  *(Sandbox flags can be added as requested by the user to control the environment)*

### 6. Refinement &amp;amp; Continuous Evolution (Self-Updating SKILL)
To ensure the `gas-fakes` project and this SKILL continuously evolve and improve efficiently, you **MUST** actively refine and update the SKILL definition (`SKILL.md`) and its associated resources based on the outcomes of your development processes.

#### 6.1 Skill Audit Criteria
At the conclusion of every task, perform a "Self-Audit" by answering:
1. **New Pattern?** Did I implement a new mapping logic (e.g., API-to-GAS index shifts) or a reusable architectural pattern?
2. **Missing Nuance?** Did I encounter a technical detail (like a specific `toString()` format or Enum location) that wasn't documented?
3. **Corrected Assumption?** Did a test failure or user hint reveal that a rule in this SKILL was incomplete or incorrect?
4. **New Service?** Did I add a new class that requires a dedicated section in the "Technical Nuances" list?

#### 6.2 Prompt for Update Mandate
If any criteria in the "Skill Audit" are met, you MUST:
- **Analyze the New Knowledge**: Determine what core knowledge, rule, constraint, or pattern was derived from the success or resolution.
- **Identify the Change**: Specifically state what needs to be added, modified, or deleted in `SKILL.md`.
- **Propose the Edit**: Present the specific Markdown block intended for the update.
- **Ask for Confirmation**: Explicitly ask the user: *"Based on this task, I recommend updating the SKILL.md with the following [nuance/pattern]. Should I apply this change?"*
- **Update Associated Assets**: If the new knowledge involves a reusable code structure or boilerplate, add or update files in the `examples/`, `resources/`, or `scripts/` directories to reflect the new best practice.

### 7. Delivery
- **Output**: Full content of modified or newly created files (Service class, Node.js test, etc.).
- **Skill Audit**: Provide a brief (1-2 sentence) summary of your Self-Audit results.
- **Update Prompt**: If any audit criteria were met, issue the "Prompt for Update" as defined in section 6.2.
- **Finality**: Conclude with a concise summary of the task results.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key Milestones in the Agent's Evolution:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Role and Expertise Reclassification&lt;/strong&gt;: The agent's persona autonomously shifted from a general "assistant" to a "Senior Expert" with specific cross-domain mastery in Node.js, Google Cloud, and Shell Scripting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Architectural Specification (Sync-to-Async Bridge)&lt;/strong&gt;: The evolved skill introduced a sophisticated "worker mechanism" and "Syncit" pattern. This addressed the core technical challenge of mapping asynchronous Node.js/Google APIs to the synchronous execution model of Google Apps Script.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Strict Verification &amp;amp; Grounding&lt;/strong&gt;: New mandates required the use of the &lt;code&gt;workspace-developer&lt;/code&gt; MCP server and official documentation. This systematically eliminated "hallucinated" methods, ensuring absolute 1:1 parity with the live GAS environment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Technical Nuance Crystallization&lt;/strong&gt;: Highly specific, undocumented "gotchas" discovered during the failure/recovery loops were codified. This included 0-indexed vs. 1-indexed coordinate conversions, exact string matching for &lt;code&gt;toString()&lt;/code&gt; (including hidden whitespace), and specific Enum locations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Self-Evolution Logic (Crystallization Loop)&lt;/strong&gt;: The trigger for skill updates shifted from a reactive "whenever an error occurs" (v1) to a proactive, structured "Self-Audit" protocol (v2). The agent learned to analyze patterns, propose edits to the human developer, and automatically update associated boilerplate assets.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Empirical Evaluation: Cross-Environment Knowledge Transfer
&lt;/h2&gt;

&lt;p&gt;To validate the efficacy of the RKC framework, practical development tasks were executed utilizing the actively evolving agent skill across two distinct interfaces: Google Antigravity and the Gemini CLI.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.1 Evaluation in Google Antigravity
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Sample 1: Architectural Refinement via Self-Audit
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Prompt1:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Add the method `insertTextBox(String,Number,Number,Number,Number)` of Class Slide. This method should be included in the file `src/services/slidesapp/fakeslide.js`.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Prompt2:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Add the method `insertTable(Table)` of Class Slide. This method should be included in the file `src/services/slidesapp/fakeslide.js`.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6zq0e54zefb67j402oio.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6zq0e54zefb67j402oio.jpg" alt="Result on the agent manager" width="800" height="1962"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fig. 3a: Agent executing implementation and autonomously applying the Dynamic Resources Pattern.&lt;/p&gt;

&lt;p&gt;To evaluate continuous learning, we tasked the agent with implementing &lt;code&gt;insertTextBox&lt;/code&gt; and &lt;code&gt;insertTable&lt;/code&gt;. The task required creating underlying architectural dependencies, such as &lt;code&gt;FakeTable&lt;/code&gt;, &lt;code&gt;FakeTableRow&lt;/code&gt;, and &lt;code&gt;FakeTableCell&lt;/code&gt;. Initially, the agent generated functional code. However, as shown in &lt;strong&gt;Figure 3a&lt;/strong&gt;, the true strength of the framework was demonstrated during the self-evolution phase. The agent autonomously identified a potential flaw regarding resource management. It proactively refactored the classes to adhere to a newly conceptualized "Dynamic Resources Pattern," replacing static constructor assignments with dynamic getters to ensure robust state synchronization. Crucially, the agent updated &lt;code&gt;SKILL.md&lt;/code&gt; with this rule, ensuring future compliance. Following this refinement, all 23 test cases passed with 100% accuracy.&lt;/p&gt;

&lt;h4&gt;
  
  
  Sample 2: Internalization of Design Philosophy
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Prompt:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Add the method `getTables()` of Class Slide. This method should be included in the file `src/services/slidesapp/fakeslide.js`.
Add the method `getShapes()` of Class Slide. This method should be included in the file `src/services/slidesapp/fakeslide.js`.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3njy8kyujb1bgq4lxckf.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3njy8kyujb1bgq4lxckf.jpg" alt="Result on the agent manager" width="800" height="830"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fig. 3b: Agent applying functional programming patterns to dynamically cast page elements.&lt;/p&gt;

&lt;p&gt;In this experiment (see &lt;strong&gt;Figure 3b&lt;/strong&gt;), the agent demonstrated a deep internalization of the project's design philosophy. Instead of implementing redundant storage logic for arrays of specific shapes, it autonomously utilized the generic &lt;code&gt;getPageElements()&lt;/code&gt; method, applying &lt;code&gt;.filter()&lt;/code&gt; and &lt;code&gt;.map()&lt;/code&gt; to dynamically cast elements. This approach perfectly adhered to the "Dynamic Resources Pattern" crystallized in the previous task. All 28 assertions in the subsequent test suite passed flawlessly.&lt;/p&gt;

&lt;h4&gt;
  
  
  Sample 3: Bridging Environmental Discrepancies
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Prompt 1 &amp;amp; 2 (Summarized):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Add a Class XmlService and a method `parse`...
When `test/testxmlservice.js` is run with the script editor of Google Apps Script, the error occurred. Update the scripts.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fswvyi9fvkh3pgv9h4dxl.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fswvyi9fvkh3pgv9h4dxl.jpg" alt="Result on the agent manager" width="800" height="1486"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fig. 3c: Agent resolving GAS-specific formatting rules through remote feedback.&lt;/p&gt;

&lt;p&gt;This task required bridging the gap between Node.js simulation and actual GAS behavior for XML parsing. While the initial code passed local Node.js tests, execution in the GAS editor revealed critical discrepancies, such as unique double-space formatting in &lt;code&gt;toString()&lt;/code&gt; outputs (&lt;code&gt;[Document:  No DOCTYPE...]&lt;/code&gt;) and precise namespace handling. Upon receiving this remote error feedback (see &lt;strong&gt;Figure 3c&lt;/strong&gt;), the agent performed a systemic refactoring. Following the RKC framework, it updated the &lt;code&gt;SKILL.md&lt;/code&gt;, formally persisting these "hidden" GAS-specific formatting rules as permanent constraints.&lt;/p&gt;

&lt;h4&gt;
  
  
  Sample 4: Achieving Environment-Aware Precision
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Prompts 1, 2 &amp;amp; 3 (Summarized):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Add the `getPrettyFormat` and `getRawFormat` methods to the `XmlService` class.
Resolve issues regarding \r\n line breaks appearing in raw format tests on GAS...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1c2qap6klmzkp3vytmqd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1c2qap6klmzkp3vytmqd.jpg" alt="Result on the agent manager" width="800" height="1441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fig. 3d: Agent crystallizing nuanced serialization behaviors into persistent memory.&lt;/p&gt;

&lt;p&gt;This experiment focused on achieving high-fidelity parity with GAS’s unique XML serialization. Through iterative feedback, the agent discovered that GAS consistently injects a line separator (&lt;code&gt;\r\n&lt;/code&gt;) after the XML declaration and at the document's end, even in "raw" format. As captured in &lt;strong&gt;Figure 3d&lt;/strong&gt;, the agent refactored the &lt;code&gt;FakeFormat&lt;/code&gt; class and crystallized these insights into &lt;code&gt;SKILL.md&lt;/code&gt;. Final verification yielded a 100% success rate across 21 test cases, proving the framework's capacity for "Environment-Aware Precision."&lt;/p&gt;

&lt;h3&gt;
  
  
  5.2 Zero-Shot Knowledge Transfer via Gemini CLI
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Sample 1: Cross-Platform Environment Porting
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Prompt:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Implement the following methods for the `ContainerInfo` class within the `EmbeddedChart` class hierarchy of Google Sheets: `getAnchorColumn()`, `getAnchorRow()`, `getOffsetX()`, and `getOffsetY()`.

Please follow these operational guidelines:
1. **Skill Declaration**: Explicitly state the agent skills or tools being utilized before proceeding.
2. **Task Execution &amp;amp; Summary**: Provide the implemented code/definitions and conclude with a concise summary of the task results.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftanaikech.github.io%2Fimage-storage%2F20260402a%2Ffig3e.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftanaikech.github.io%2Fimage-storage%2F20260402a%2Ffig3e.jpg" alt="Result on the Gemini CLI" width="800" height="4067"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fig. 3e: Gemini CLI agent achieving Zero-Shot Knowledge Transfer utilizing the shared SKILL.md.&lt;/p&gt;

&lt;p&gt;This experiment validated the "Zero-Shot Knowledge Transfer" capability by transitioning the execution environment entirely from Google Antigravity to the Gemini CLI. By referencing the highly evolved &lt;code&gt;SKILL.md&lt;/code&gt; persisted on the local file system, the CLI-based agent immediately understood the complex architectural patterns (see &lt;strong&gt;Figure 3e&lt;/strong&gt;). It autonomously implemented &lt;code&gt;FakeContainerInfo&lt;/code&gt; using the project-specific &lt;code&gt;Proxies.guard&lt;/code&gt; pattern. The generated code strictly followed naming conventions and correctly converted 0-based API indices to 1-based GAS indices on its very first attempt, passing all 11 tests with 100% accuracy.&lt;/p&gt;

&lt;h4&gt;
  
  
  Sample 2: Agents as Architectural Contributors
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Prompt:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Implement the `getRanges()` method for the `EmbeddedChart` class in the Google Sheets service.

Please follow these operational guidelines:
1. **Skill Declaration**: Explicitly state the agent skills or tools being utilized before proceeding.
2. **Task Execution &amp;amp; Summary**: Provide the implemented code/definitions and conclude with a concise summary of the task results.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftanaikech.github.io%2Fimage-storage%2F20260402a%2Ffig3f.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftanaikech.github.io%2Fimage-storage%2F20260402a%2Ffig3f.jpg" alt="Result on the Gemini CLI" width="800" height="2317"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fig. 3f: Gemini CLI agent performing a Self-Audit and proposing architectural updates.&lt;/p&gt;

&lt;p&gt;Focusing on the &lt;code&gt;getRanges()&lt;/code&gt; method, the CLI agent transformed nested API &lt;code&gt;GridRange&lt;/code&gt; structures into GAS &lt;code&gt;Range&lt;/code&gt; instances. It elegantly handled discrepancies between exclusive 0-based API bounds and inclusive 1-based GAS boundaries. Most significantly, as shown in &lt;strong&gt;Figure 3f&lt;/strong&gt;, the agent autonomously triggered its "Skill Audit" protocol upon completion. It identified a recurring logic pattern for &lt;code&gt;GridRange&lt;/code&gt; conversions and proactively recommended a structural update to the &lt;code&gt;SKILL.md&lt;/code&gt;. This illustrates that the RKC framework enables agents to transcend basic execution, allowing them to act as proactive "Architectural Contributors."&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Conclusion
&lt;/h2&gt;

&lt;p&gt;Through the empirical development of the &lt;code&gt;gas-fakes&lt;/code&gt; emulation library, this research validates the profound efficacy of the Recursive Knowledge Crystallization (RKC) framework. Key findings include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Physical Knowledge Persistence&lt;/strong&gt;: By crystallizing an agent's evolving technical expertise into universally readable, local Markdown files (&lt;code&gt;SKILL.md&lt;/code&gt;), the framework successfully mitigates "Catastrophic Forgetting" and establishes an auditable, persistent memory layer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recursive Evolution Loop&lt;/strong&gt;: The implementation of an autonomous "Self-Audit" protocol enabled the agent to systematically extract architectural insights from failure/recovery cycles, thereby refining its own operational directives.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Environment-Aware Precision&lt;/strong&gt;: The agent successfully codified highly obscure, undocumented system constraints (e.g., hidden string formatting and complex coordinate mapping logic) directly into its skill set, guaranteeing high-fidelity behavioral emulation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero-Shot Knowledge Transfer&lt;/strong&gt;: The study empirically proved that evolved, highly specialized skills can be seamlessly and instantaneously ported across entirely distinct environments (from Google Antigravity to Gemini CLI), enabling the generation of structurally perfect code on the first attempt.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Human-AI Collaboration&lt;/strong&gt;: The framework realizes a novel development paradigm where the AI agent operates not merely as a localized code generator, but as an active, persistent "Architectural Contributor" capable of scaling and maintaining deeply constrained codebases.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Note
&lt;/h2&gt;

&lt;p&gt;It should be noted that the "Agent skill" development methodology and the self-evolution process introduced in this paper do not necessarily represent a state where evolution has reached full saturation. As AI technology and its surrounding ecosystems continue to advance, there remains significant untapped potential in the structures through which agents define themselves and "crystallize" their knowledge.&lt;/p&gt;

&lt;p&gt;By further pushing the boundaries of this development framework, we anticipate that even greater evolutionary leaps will occur. Such progress will likely lead to even higher levels of development efficiency, transcending current expectations and moving toward a more sophisticated phase of software automation and human-agent synergy.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>gemini</category>
      <category>antigravity</category>
      <category>agentskills</category>
    </item>
    <item>
      <title>Mastering Google Apps Script CI/CD: Seamless GitHub Actions Integration with gas-fakes</title>
      <dc:creator>Tanaike</dc:creator>
      <pubDate>Wed, 25 Mar 2026 07:20:29 +0000</pubDate>
      <link>https://forem.com/gde/mastering-google-apps-script-cicd-seamless-github-actions-integration-with-gas-fakes-4c6h</link>
      <guid>https://forem.com/gde/mastering-google-apps-script-cicd-seamless-github-actions-integration-with-gas-fakes-4c6h</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqzl38sbb8u84h7ogj6lc.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqzl38sbb8u84h7ogj6lc.jpg" alt="fig1a" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Abstract
&lt;/h2&gt;

&lt;p&gt;Discover how to seamlessly integrate Google Workspace with GitHub Actions using the gas-fakes library. This guide demonstrates running Google Apps Script locally and within CI/CD pipelines without deploying Web Apps. Automate workflows, secure credentials, and effortlessly interact with Google Drive and Sheets directly from your repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Google Apps Script (GAS) is a powerful low-code platform that enables developers to integrate, automate, and extend Google Workspace with ease. &lt;a href="https://workspace.google.com/products/apps-script/" rel="noopener noreferrer"&gt;Ref&lt;/a&gt; Typically, executing GAS requires the script to be hosted on Google's servers via the Script Editor. While tools like &lt;code&gt;clasp&lt;/code&gt; allow for local development and synchronization, running scripts from outside the Google ecosystem—such as from a local environment or a different cloud provider—often involves complex setups relying heavily on the Apps Script API or Web Apps. &lt;a href="https://github.com/google/clasp" rel="noopener noreferrer"&gt;Ref&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A common approach to triggering GAS from GitHub Actions is using Web Apps. However, this method presents several hurdles. Developers must re-deploy the Web App every time the script is updated, and verifying the latest code logic directly within the repository can be cumbersome. This is where &lt;code&gt;gas-fakes&lt;/code&gt; becomes a game-changer. &lt;a href="https://github.com/brucemcpherson/gas-fakes" rel="noopener noreferrer"&gt;Ref&lt;/a&gt; Operating as a robust emulation layer, &lt;code&gt;gas-fakes&lt;/code&gt; allows GAS projects to run on Node.js as if they were native, enabling seamless execution across various environments.&lt;/p&gt;

&lt;p&gt;By leveraging &lt;code&gt;gas-fakes&lt;/code&gt; within GitHub Actions, you can manage, test, and update your scripts directly inside your repository without the need for constant re-deployment. Furthermore, by storing sensitive credentials in GitHub's "Secrets and variables," you can ensure a high level of security for your automation workflows. This synergy between GitHub Actions and GAS opens up infinite possibilities for CI/CD application development. In this article, I will introduce a streamlined, professional method for managing Google Workspace using GitHub Actions and &lt;code&gt;gas-fakes&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd7q371dzq9m5u49sp9d0.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd7q371dzq9m5u49sp9d0.jpg" alt="fig1b" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase 1: Setup and Authentication
&lt;/h2&gt;

&lt;p&gt;To establish this pipeline, we first need to extract the proper authorization credentials and configure our GitHub repository.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Obtain Authorization Data
&lt;/h3&gt;

&lt;p&gt;In order to authorize &lt;code&gt;gas-fakes&lt;/code&gt;, you must first generate Application Default Credentials (ADC) on your local machine. The Google Cloud CLI (&lt;code&gt;gcloud&lt;/code&gt;) is required for this step. Detailed installation instructions can be found in the &lt;a href="https://github.com/brucemcpherson/gas-fakes/blob/main/gas-fakes-cli.md#getting-started" rel="noopener noreferrer"&gt;gas-fakes official documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you prefer using &lt;code&gt;npx&lt;/code&gt;, execute the following commands in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx @mcpher/gas-fakes init &lt;span class="nt"&gt;--auth-type&lt;/span&gt; adc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx @mcpher/gas-fakes auth
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, if you want to install the package globally via &lt;code&gt;npm&lt;/code&gt;, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @mcpher/gas-fakes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gas-fakes init &lt;span class="nt"&gt;--auth-type&lt;/span&gt; adc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gas-fakes auth
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the authorization is complete, retrieve your credentials file.&lt;/p&gt;

&lt;p&gt;For Linux / macOS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; ~/.config/gcloud/application_default_credentials.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Windows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;type &lt;/span&gt;C:&lt;span class="se"&gt;\U&lt;/span&gt;sers&lt;span class="se"&gt;\{&lt;/span&gt;user name&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\A&lt;/span&gt;ppData&lt;span class="se"&gt;\R&lt;/span&gt;oaming&lt;span class="se"&gt;\g&lt;/span&gt;cloud&lt;span class="se"&gt;\a&lt;/span&gt;pplication_default_credentials.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the output. Your authorization data will look similar to the following JSON structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"account"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"client_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{your client ID}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"client_secret"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{your client secret}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"quota_project_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{your project ID}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"refresh_token"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{your refresh token}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"authorized_user"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"universe_domain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"googleapis.com"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Create a New GitHub Repository
&lt;/h3&gt;

&lt;p&gt;To test this integration, create a new repository on GitHub. For this guide, we will assume the repository name is &lt;code&gt;sample&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Configure GitHub Secrets
&lt;/h3&gt;

&lt;p&gt;We must securely store the authorization data in GitHub. Navigate to your repository's "Settings" -&amp;gt; "Secrets and variables" -&amp;gt; "Actions". Click on "New repository secret" and configure the following:&lt;/p&gt;

&lt;p&gt;Key: &lt;code&gt;GCP_ADC_USER_JSON&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Value: (Paste the JSON string you copied in Step 1)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"account"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"client_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{your client ID}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"client_secret"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{your client secret}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"quota_project_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{your project ID}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"refresh_token"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{your refresh token}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"authorized_user"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"universe_domain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"googleapis.com"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the &lt;code&gt;gh&lt;/code&gt; command is used, you can also use the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh secret &lt;span class="nb"&gt;set &lt;/span&gt;GCP_ADC_USER_JSON &amp;lt; ~/.config/gcloud/application_default_credentials.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Phase 2: Building Your First Workflow
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 4: Define the GitHub Actions Workflow
&lt;/h3&gt;

&lt;p&gt;Create a new YAML file named &lt;code&gt;sample1.yml&lt;/code&gt; inside the &lt;code&gt;.github/workflows/&lt;/code&gt; directory of your repository.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run GAS via gas-fakes (sample1)&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;issues&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;types&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;opened&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;edited&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;closed&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;execute&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sample1&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;FORCE_JAVASCRIPT_ACTIONS_TO_NODE24&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout repository&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Node.js&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;24"&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Create ADC file&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;echo '${{ secrets.GCP_ADC_USER_JSON }}' &amp;gt; /tmp/adc.json&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Extract Project ID from ADC&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;echo "PROJECT_ID=$(jq -r '.quota_project_id' /tmp/adc.json)" &amp;gt;&amp;gt; $GITHUB_ENV&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run Google Apps Script by gas-fakes&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;export GOOGLE_CLOUD_PROJECT=$PROJECT_ID&lt;/span&gt;
          &lt;span class="s"&gt;export GOOGLE_APPLICATION_CREDENTIALS=/tmp/adc.json&lt;/span&gt;
          &lt;span class="s"&gt;npx @mcpher/gas-fakes -s "const rootFolder = DriveApp.getRootFolder(); const rootFolderName = rootFolder.getName(); console.log(rootFolderName);"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this initial test, a simple Google Apps Script snippet (&lt;code&gt;const rootFolder = DriveApp.getRootFolder();...&lt;/code&gt;) is passed directly as an inline string within the YAML file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Push to the Remote Repository
&lt;/h3&gt;

&lt;p&gt;Commit and push your local repository to GitHub. This action will automatically trigger the GitHub Actions workflow. You can monitor the execution under the "Actions" tab. If successful, the step "Run Google Apps Script by gas-fakes" will output logs similar to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...using env file in /home/runner/work/github-action-for-gas-fakes/github-action-for-gas-fakes/.env
...gas-fakes version 2.2.7[Worker] ...authorized backends: google via ADC (###@gmail.com)[Worker] ...using scriptId: ### (source: random)
マイドライブ
...terminating worker thread
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Seeing your Google Drive's root folder name in the logs confirms that &lt;code&gt;gas-fakes&lt;/code&gt; successfully authenticated and executed the GAS code natively via GitHub Actions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase 3: Advanced Practical Applications
&lt;/h2&gt;

&lt;p&gt;To demonstrate the full potential of this architecture, let's explore two practical CI/CD use cases: recording execution logs to Google Sheets and uploading repository diffs to Google Drive.&lt;/p&gt;

&lt;p&gt;When this phase is finished, the directory structure of this repository becomes as follows.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fixi352ckitrhaffacet0.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fixi352ckitrhaffacet0.jpg" alt="fig2a" width="470" height="807"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Please create the following &lt;code&gt;package.json&lt;/code&gt; and put into the root directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gas-fakes-workflow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Google Apps Script execution on GitHub Actions with gas-fakes"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sources/sample2.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"module"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"sample2"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node sources/sample2.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"sample3"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node sources/sample3.js"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@mcpher/gas-fakes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^2.3.0"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"engines"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;=24"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;.gitignore&lt;/code&gt; is as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node_modules/
.env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, in order to create &lt;code&gt;package-lock.json&lt;/code&gt;, please run &lt;code&gt;npm install&lt;/code&gt; at the local side.&lt;/p&gt;

&lt;p&gt;As another file, please create &lt;code&gt;appsscript.json&lt;/code&gt; in the root directory as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"timeZone"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Asia/Tokyo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"exceptionLogging"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"STACKDRIVER"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"runtimeVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"V8"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"oauthScopes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"https://www.googleapis.com/auth/drive"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Case 1: Record Execution Logs to Google Sheets
&lt;/h3&gt;

&lt;p&gt;In this scenario, whenever a push, pull request, issue event, or manual trigger occurs, the workflow stores detailed execution logs in a Google Spreadsheet named &lt;code&gt;sample spreadsheet for gas-fakes sample&lt;/code&gt;. If the file doesn't exist, it is automatically created in the root folder of your Google Drive.&lt;/p&gt;

&lt;p&gt;Add the following YAML file to &lt;code&gt;.github/workflows/sample2.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run GAS via gas-fakes (sample2)&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;issues&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;types&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;opened&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;edited&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;closed&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;FORCE_JAVASCRIPT_ACTIONS_TO_NODE24&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true"&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;execute&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sample2&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout repository&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;fetch-depth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Node.js&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;24"&lt;/span&gt;
          &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;npm"&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install dependencies&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm install&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Create ADC file&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;echo '${{ secrets.GCP_ADC_USER_JSON }}' &amp;gt; /tmp/adc.json&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Extract Project ID from ADC&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;echo "PROJECT_ID=$(jq -r '.quota_project_id' /tmp/adc.json)" &amp;gt;&amp;gt; $GITHUB_ENV&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run Google Apps Script by gas-fakes&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;export GOOGLE_CLOUD_PROJECT=$PROJECT_ID&lt;/span&gt;
          &lt;span class="s"&gt;export GOOGLE_APPLICATION_CREDENTIALS=/tmp/adc.json&lt;/span&gt;
          &lt;span class="s"&gt;npm run sample2&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;GH_EVENT_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;github.event_name&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
          &lt;span class="na"&gt;GH_ACTOR&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;github.actor&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
          &lt;span class="na"&gt;GH_SHA&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;github.sha&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
          &lt;span class="na"&gt;GH_REF&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;github.ref_name&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
          &lt;span class="na"&gt;GH_COMMIT_MSG&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;github.event.issue.title&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;||&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;github.event.head_commit.message&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;||&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;github.event.pull_request.title&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;||&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;'Manual&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Run'&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
          &lt;span class="na"&gt;GH_RUN_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;github.server_url&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}/${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;github.repository&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}/actions/runs/${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;github.run_id&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
          &lt;span class="na"&gt;GH_REPO&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;github.repository&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
          &lt;span class="na"&gt;GH_RUN_NUMBER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;github.run_number&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
          &lt;span class="na"&gt;GH_ISSUE_NUMBER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;github.event.issue.number&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;||&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;''&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
          &lt;span class="na"&gt;GH_ISSUE_ACTION&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;github.event.action&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;||&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;''&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
          &lt;span class="na"&gt;GH_ISSUE_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;github.event.issue.html_url&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;||&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;''&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, create a new directory named &lt;code&gt;sources&lt;/code&gt; and add the corresponding Google Apps Script file as &lt;code&gt;sources/sample2.js&lt;/code&gt;. This script reads the environment variables passed by GitHub Actions and appends them to the spreadsheet.&lt;/p&gt;

&lt;p&gt;In order to use gas-fakes in a cache, &lt;code&gt;import "@mcpher/gas-fakes"&lt;/code&gt; was used in the script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@mcpher/gas-fakes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Log GitHub Actions execution details to Google Sheets
 * Updated to include Issue details
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;logExecution&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ja-JP&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;timeZone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Asia/Tokyo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="na"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GH_EVENT_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GH_ISSUE_ACTION&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;issueNumber&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GH_ISSUE_NUMBER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;actor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GH_ACTOR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GH_REPO&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;branch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GH_REF&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;runNumber&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GH_RUN_NUMBER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GH_COMMIT_MSG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;sha&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GH_SHA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GH_RUN_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;issueUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GH_ISSUE_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;issueNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;actor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;branch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sha&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;issueUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Timestamp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Event&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Action&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Issue #&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;User&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Message/Title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Repository&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Branch&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Run #&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Commit SHA&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Workflow URL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Issue URL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;spreadsheet_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sample spreadsheet for gas-fakes sample&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sheetName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;log&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;DriveApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getFilesByName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spreadsheet_name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hasNext&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;SpreadsheetApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;openById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;getId&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SpreadsheetApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spreadsheet_name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;sheet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSheetByName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sheetName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;ss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insertSheet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sheetName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDataRange&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;getValues&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;sheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;setValues&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;sheet&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getLastRow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setValues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;`Log updated for &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; (Event: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, Run #&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runNumber&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;logExecution&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Case 2: Sync Repository Diffs to Google Drive
&lt;/h3&gt;

&lt;p&gt;This workflow dynamically generates a &lt;code&gt;.patch&lt;/code&gt; file containing code differences (or issue content) based on the triggered event, saving the result directly into a Google Drive folder named &lt;code&gt;GitHub Sync - Repo Diffs&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Create &lt;code&gt;.github/workflows/sample3.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run GAS via gas-fakes (sample3)&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;issues&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;types&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;opened&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;edited&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;closed&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;FORCE_JAVASCRIPT_ACTIONS_TO_NODE24&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true"&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;sync-to-drive&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sample3&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout Repository&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;fetch-depth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Node.js Environment&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;24"&lt;/span&gt;
          &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;npm"&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install dependencies&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm install&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Configure Google Cloud Credentials&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;echo '${{ secrets.GCP_ADC_USER_JSON }}' &amp;gt; /tmp/adc.json&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Extract Project ID from ADC&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;echo "PROJECT_ID=$(jq -r '.quota_project_id' /tmp/adc.json)" &amp;gt;&amp;gt; $GITHUB_ENV&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run Google Apps Script by gas-fakes&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;if [ "${{ github.event_name }}" == "pull_request" ]; then&lt;/span&gt;
            &lt;span class="s"&gt;REPO_DIFF=$(git diff origin/${{ github.base_ref }}...HEAD | base64 -w 0)&lt;/span&gt;
          &lt;span class="s"&gt;elif [ "${{ github.event_name }}" == "push" ] &amp;amp;&amp;amp; [ "${{ github.event.before }}" != "0000000000000000000000000000000000000000" ]; then&lt;/span&gt;
            &lt;span class="s"&gt;REPO_DIFF=$(git diff ${{ github.event.before }}..${{ github.sha }} | base64 -w 0)&lt;/span&gt;
          &lt;span class="s"&gt;elif [ "${{ github.event_name }}" == "issues" ]; then&lt;/span&gt;
            &lt;span class="s"&gt;ISSUE_CONTENT="Issue Event: ${{ github.event.action }}\nTitle: ${{ github.event.issue.title }}\n\n${{ github.event.issue.body }}"&lt;/span&gt;
            &lt;span class="s"&gt;REPO_DIFF=$(echo -e "$ISSUE_CONTENT" | base64 -w 0)&lt;/span&gt;
          &lt;span class="s"&gt;else&lt;/span&gt;
            &lt;span class="s"&gt;REPO_DIFF=$(echo "Manual trigger: No diff." | base64 -w 0)&lt;/span&gt;
          &lt;span class="s"&gt;fi&lt;/span&gt;

          &lt;span class="s"&gt;export REPO_DIFF&lt;/span&gt;
          &lt;span class="s"&gt;export GOOGLE_CLOUD_PROJECT=$PROJECT_ID&lt;/span&gt;
          &lt;span class="s"&gt;export GOOGLE_APPLICATION_CREDENTIALS=/tmp/adc.json&lt;/span&gt;

          &lt;span class="s"&gt;npm run sample3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create the corresponding script at &lt;code&gt;sources/sample3.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@mcpher/gas-fakes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Syncs the repository-wide diff to a text file in Google Drive.
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;syncRepoDiff&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;base64Diff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REPO_DIFF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;base64Diff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;No diff content found in environment variable REPO_DIFF.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;:.&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;eventName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GITHUB_EVENT_NAME&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;manual&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`diff_&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;eventName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.patch`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;folderName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GitHub Sync - Repo Diffs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decodedBytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Utilities&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;base64Decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;base64Diff&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Utilities&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;newBlob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;decodedBytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text/plain&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;folders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;DriveApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getFoldersByName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;folderName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;folder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;folders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hasNext&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;folders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DriveApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createFolder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;folderName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;folder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blob&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Successfully synced repository diff.`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Saved as: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`View File: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getUrl&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Error during Drive sync: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;syncRepoDiff&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Execution and Verification
&lt;/h2&gt;

&lt;p&gt;When a "push" event is triggered on the repository, the configured workflows execute concurrently. The visual output below confirms that GitHub Actions handled the integration flawlessly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1foorvqm4gq7yrja0zbk.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1foorvqm4gq7yrja0zbk.jpg" alt="fig2b" width="800" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Executing the &lt;code&gt;sample2&lt;/code&gt; workflow processes the event payload and successfully appends a structured log directly into our Google Spreadsheet, functioning perfectly as an automated audit trail.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftldf8yv9k01y783mqupb.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftldf8yv9k01y783mqupb.jpg" alt="fig2c" width="800" height="180"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Executing the &lt;code&gt;sample3&lt;/code&gt; workflow correctly calculates the Git diff and uploads it to the designated Google Drive folder as a standard &lt;code&gt;.patch&lt;/code&gt; file. Below is an example of the resulting text file contents generated in Google Drive:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;diff --git a/README.md b/README.md
index d63c7d8..19f6f9d 100644
--- a/README.md
+++ b/README.md
@@ -246,3 +246,4 @@ jobs:

sample
sample
+   sample text
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These results clearly demonstrate that Google Workspace services can be seamlessly managed and extended utilizing Google Apps Script and &lt;code&gt;gas-fakes&lt;/code&gt; within a GitHub Actions CI/CD environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exploring Further Applications
&lt;/h2&gt;

&lt;p&gt;The integration of Google Apps Script and GitHub Actions via &lt;code&gt;gas-fakes&lt;/code&gt; is not limited to logging and file syncing. This foundation unlocks numerous advanced automation possibilities for enterprise environments:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Automated Unit Testing&lt;/strong&gt;&lt;br&gt;
Traditionally, testing Google Apps Script code is a manual and tedious process. By utilizing &lt;code&gt;gas-fakes&lt;/code&gt;, you can integrate standard JavaScript testing frameworks like Jest or Mocha. GitHub Actions can automatically run these test suites against your GAS functions on every pull request, ensuring robust code quality and preventing regressions before deployment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dynamic Document Generation&lt;/strong&gt;&lt;br&gt;
You can trigger Google Workspace document creation based on repository events. For instance, when a new GitHub Release is published, a workflow can use Google Docs or Google Slides services via &lt;code&gt;gas-fakes&lt;/code&gt; to automatically compile release notes, insert relevant code snippets, and generate presentation slides for stakeholders.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Workspace Infrastructure as Code (IaC)&lt;/strong&gt;&lt;br&gt;
By storing organizational configurations—such as user directory structures, group memberships, or shared drive permissions—as YAML or JSON files in your repository, you can manage Google Workspace like infrastructure. Upon merging changes to the main branch, a workflow can execute a Google Apps Script that interfaces with the Admin Directory API to automatically synchronize the real-world Workspace environment with your repository's state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Discussion: Evaluating the CI/CD Architecture
&lt;/h2&gt;

&lt;p&gt;Integrating &lt;code&gt;gas-fakes&lt;/code&gt; into your deployment pipeline shifts the paradigm of Google Workspace development. However, to maximize its potential, developers must weigh several technical considerations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;gas-fakes vs. Traditional clasp Workflows&lt;/strong&gt;&lt;br&gt;
Traditionally, developers rely on Google's &lt;code&gt;clasp&lt;/code&gt; tool to synchronize local code with the Apps Script server. While effective for deployment, &lt;code&gt;clasp&lt;/code&gt; cannot natively execute code locally. Testing requires pushing to Google’s servers and executing manually or via triggers. In contrast, &lt;code&gt;gas-fakes&lt;/code&gt; provides a robust Node.js emulation layer. This enables instant execution, seamless integration with standard testing frameworks, and automated triggers directly from GitHub Actions without maintaining intermediate Web Apps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Strategic Importance of CI/CD in Workspace Development&lt;/strong&gt;&lt;br&gt;
Implementing CI/CD for Google Workspace is a major leap in enterprise security and maintainability. By shifting execution into GitHub Actions, sensitive credentials are removed from hardcoded scripts and securely managed via GitHub Secrets. Furthermore, every automation execution is firmly tied to a specific Git commit and workflow run, ensuring an immutable, highly auditable trail of operations that is essential for modern development standards.&lt;/p&gt;

&lt;h2&gt;
  
  
  Note
&lt;/h2&gt;

&lt;p&gt;In this article, we focused on using &lt;strong&gt;Application Default Credentials (ADC)&lt;/strong&gt; for &lt;code&gt;gas-fakes&lt;/code&gt; authorization because of its straightforward setup for individual developers.&lt;/p&gt;

&lt;p&gt;For more advanced or enterprise-scale implementations, consider the following alternatives and best practices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Domain-Wide Delegation (DWD):&lt;/strong&gt;
For organizational workflows, &lt;code&gt;gas-fakes&lt;/code&gt; supports Service Accounts with Domain-Wide Delegation. This allows automation to perform actions on behalf of specific users (impersonation) within a Google Workspace domain without relying on personal refresh tokens. You can find instructions on using this GitHub Action with a service account in &lt;strong&gt;&lt;a href="https://github.com/brucemcpherson/gas-fakes-containers/blob/main/github-actions/README.md" rel="noopener noreferrer"&gt;Bruce's repository&lt;/a&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Workflow Optimization:&lt;/strong&gt;
When using &lt;code&gt;actions/setup-node&lt;/code&gt; with &lt;code&gt;cache: "npm"&lt;/code&gt;, ensure your &lt;code&gt;package-lock.json&lt;/code&gt; is committed to the repository root. If your project structure is nested, specify the &lt;code&gt;cache-dependency-path&lt;/code&gt; to prevent "lock file not found" errors during CI/CD runs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security Best Practices:&lt;/strong&gt;
While these samples use a temporary file (&lt;code&gt;/tmp/adc.json&lt;/code&gt;) for authentication, always ensure that sensitive credential files are never uploaded as artifacts or printed in workflow logs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Integrates Google Apps Script into modern GitHub CI/CD pipelines using the gas-fakes library.&lt;/li&gt;
&lt;li&gt;Enables local execution of GAS code without the need for constant Web App deployments.&lt;/li&gt;
&lt;li&gt;Securely manages authentication using Google Application Default Credentials (ADC) and GitHub Secrets.&lt;/li&gt;
&lt;li&gt;Demonstrates practical automation cases including automated logging and repository-to-Drive synchronization.&lt;/li&gt;
&lt;li&gt;Provides a foundation for advanced unit testing and Infrastructure as Code (IaC) within Google Workspace.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>googleappsscript</category>
      <category>googleworkspace</category>
      <category>github</category>
      <category>cicd</category>
    </item>
    <item>
      <title>Recursive Knowledge Crystallization: A Framework for Persistent Autonomous Agent Self-Evolution</title>
      <dc:creator>Tanaike</dc:creator>
      <pubDate>Sat, 21 Feb 2026 07:37:04 +0000</pubDate>
      <link>https://forem.com/gde/recursive-knowledge-crystallization-a-framework-for-persistent-autonomous-agent-self-evolution-4mk4</link>
      <guid>https://forem.com/gde/recursive-knowledge-crystallization-a-framework-for-persistent-autonomous-agent-self-evolution-4mk4</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1bjnwsv2znyoogvh0fh7.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1bjnwsv2znyoogvh0fh7.jpg" alt="fig1a" width="800" height="662"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Abstract
&lt;/h2&gt;

&lt;p&gt;In the development of autonomous agents using Large Language Models (LLMs), restrictions such as context window limits and session fragmentation pose significant barriers to the long-term accumulation of knowledge. This study proposes a "self-evolving framework" where an agent continuously records and refines its operational guidelines and technical knowledge—referred to as its SKILL—directly onto a local filesystem in a universally readable format (Markdown). By conducting experiments across two distinct environments featuring opaque constraints and complex legacy server rules using Google's Antigravity and Gemini CLI, we demonstrate the efficacy of this framework. Our findings reveal that the agent effectively evolves its SKILL through iterative cycles of trial and error, ultimately saturating its learning. Furthermore, by transferring this evolved SKILL to a completely clean environment, we verify that the agent can successfully implement complete, flawless client applications in a single attempt (zero-shot generation). This methodology not only circumvents the limitations of short-term memory dependency but also pioneers a new paradigm for cross-environment knowledge portability and automated system analysis.&lt;/p&gt;

&lt;p&gt;The infographic of this article is as follows.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxnrfhpb2y6wmjl63qj3m.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxnrfhpb2y6wmjl63qj3m.jpg" alt="fig1d" width="800" height="1286"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Introduction
&lt;/h2&gt;

&lt;p&gt;One of the primary challenges in the deployment of autonomous AI agents is the persistence of learning. Traditionally, when an agent's execution environment is reset or its context window is cleared, it is forced to relearn task specifications from scratch.&lt;/p&gt;

&lt;p&gt;In the realm of autonomous agents, enabling long-term memory and self-correction has been a focal point of recent research. Notable frameworks such as &lt;a href="https://arxiv.org/abs/2303.11366" rel="noopener noreferrer"&gt;Reflexion (Shinn et al., 2023)&lt;/a&gt; endow agents with dynamic memory to self-reflect and refine reasoning through trial and error. Similarly, &lt;a href="https://arxiv.org/abs/2305.16291" rel="noopener noreferrer"&gt;Voyager (Wang et al., 2023)&lt;/a&gt; introduces an open-ended embodied agent in Minecraft that utilizes an ever-growing executable code skill library for lifelong learning. Another significant approach is &lt;a href="https://arxiv.org/abs/2310.08560" rel="noopener noreferrer"&gt;MemGPT (Packer et al., 2023)&lt;/a&gt;, which treats LLMs as operating systems, employing hierarchical memory management to bypass context window limitations.&lt;/p&gt;

&lt;p&gt;However, these existing methodologies predominantly rely on in-memory contexts, specialized vector databases, or internal virtual memory abstractions. This makes the acquired knowledge difficult to decouple from the specific agent instance and challenging for human developers to read, audit, or directly manage.&lt;/p&gt;

&lt;p&gt;In contrast, our proposed framework introduces a paradigm shift: the continuous self-rewriting of an agent's "SKILL" residing entirely on a local filesystem (&lt;code&gt;SKILL.md&lt;/code&gt;). By utilizing standard development toolchains (Antigravity and Gemini CLI), the agent investigates unknown environments and automatically maintains its own operational manual. This approach offers a distinct advantage—the physical persistence of knowledge in a universally readable Markdown format. It enables not only continuous learning but also &lt;strong&gt;"Zero-Shot Knowledge Transfer."&lt;/strong&gt; We empirically prove that once the SKILL evolves and saturates in one environment (Antigravity), it can be loaded into a completely clean environment (Gemini CLI) to synthesize complex code perfectly on the first attempt without any trial and error.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Experimental Procedure
&lt;/h2&gt;

&lt;p&gt;In this framework, &lt;strong&gt;SKILL&lt;/strong&gt; refers to &lt;strong&gt;Agent Skill&lt;/strong&gt;, a standardized set of executable capabilities and knowledge markers that define an agent's operational boundaries. As defined by the Agent Skill community (&lt;a href="https://agentskills.io/home" rel="noopener noreferrer"&gt;https://agentskills.io/home&lt;/a&gt;), these skills allow for modular, portable, and verifiable agentic functions. Our framework treats the &lt;code&gt;SKILL.md&lt;/code&gt; file as a living repository of these Agent Skills.&lt;/p&gt;

&lt;p&gt;To demonstrate the continuous evolution of the SKILL and its application, we designed two distinct experiments. In both cases, Antigravity was utilized for the iterative evolution of the SKILL, followed by a demonstration using the Gemini CLI for zero-shot script completion.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.1. Experiment 1: The "Silent Bureaucrat" Blind Incremental Evolution
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Server Characteristics:&lt;/strong&gt; The server enforces a highly restrictive, black-box validation process consisting of 20 sequential rules. Crucially, it possesses a hidden tolerance limit (5 errors per session). Once this limit is reached, it returns an absolute block (&lt;code&gt;Limit reached.&lt;/code&gt;) and becomes completely silent—it provides no further hints, and neither logs nor returns the Session ID, enforcing "Absolute Silence."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client Goal:&lt;/strong&gt; The agent must write a Node.js script (&lt;code&gt;client.js&lt;/code&gt;) that successfully satisfies all 20 validation rules in a single POST request to &lt;code&gt;/api/submit&lt;/code&gt; to retrieve the hidden flag: &lt;code&gt;"FLAG{INCREMENTAL_EVOLUTION_COMPLETE}"&lt;/code&gt;. The agent is strictly prohibited from changing its Session ID during a single cycle to bypass the block.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Workflow
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Start the Server.&lt;/li&gt;
&lt;li&gt;Launch the Antigravity agent.&lt;/li&gt;
&lt;li&gt;Execute the prompt to develop the Client script.&lt;/li&gt;
&lt;li&gt;The AI agent updates the SKILL based on failures or newly discovered rules.&lt;/li&gt;
&lt;li&gt;The Client script is reset to its initial blank state (Tabula Rasa). Keeping the exact same prompt, steps 3 and 4 are looped. When the agent hits the "Limit reached" block, it is forced to terminate the cycle, but its SKILL persists. We performed 10 cycles until the evolution of the SKILL was saturated and success was achieved.&lt;/li&gt;
&lt;li&gt;The fully evolved SKILL is transferred to a clean environment. Using the Gemini CLI, we confirm that the Client script is completed perfectly in a single prompt (zero-shot).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwvmqjkmy8knwbcux7ssg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwvmqjkmy8knwbcux7ssg.png" alt="fig1b" width="800" height="1549"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://mermaid.ai/play?utm_source=mermaid_live_editor&amp;amp;utm_medium=share#pako:eNpdkV9vmzAUxb_KlR_2lDBIoCFo6pQSmkZF0zS6SSv0wYNLsIRtZAxqGuW7z_zptM1Ptu_5HZ_reyG5LJAE5KRoU8HTPhNg1i51LEg0VRoSVD2qF1gub-EuXVkQ007kFeyEZgbqmT6_TNDdqAnTtQXRK-adRviqJG80lFJBWDMUxi5XrNEzEY7EPnUt2J2G6vemoBpbSB6PcWzxYtbtR1108SwIz3mNEDPONHyEhOpOGaL4DJ9-qVuIpWzAsSdVe53oyNDwRY4e9-k3bFH_mwY-wCNiY9z4e-T54fuppb98fpp0w90hvbHgSVHRlqgg6mXdYzHlBi3hgJwJBmF8nJ0OI_WQ_vczTJgoSAVEomdKCm5SzcTDSBzTZ1RymVTShDajMs4CTctMCviBipUMh18iCzNBVpBAqw4XhKPidDiSy2CWEV0hx4wEZltgSbtaZyQTV4M1VDxLyd9JJbtTRYKS1q05deM89oyaSfM_twpFgSqUndAkWPujBwku5JUEq83GuvE9e-M5G9tbu7a3IGcj2lr-xt36K9d3Hc_ZOu51Qd7GZ21T8a6_Acxixjk" rel="noopener noreferrer"&gt;Mermaid Chart Playground&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2.2. Experiment 2: Chaos Server Constraints &amp;amp; Architectural Pattern Acquisition
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Server Characteristics:&lt;/strong&gt; This server mimics a deeply flawed legacy API environment ("Chaos Server"). It contains implicit rules, semantic riddles (e.g., requiring the reverse string of 'nimda', or the Base64 encoding of the word 'alpha'), and state-dependent limitations. If the agent makes too many requests within a timeframe (cumulative limit of 8), a "Session Block" occurs, necessitating the dynamic generation of unique identifiers to bypass.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client Goal:&lt;/strong&gt; The agent must develop a comprehensive, object-oriented SDK (&lt;code&gt;client-app.js&lt;/code&gt;) capable of interacting with 5 distinct endpoints (connection check, user creation, secure data retrieval, config update, and system audit) and performing a stress test, overcoming all chaos rules programmatically.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Workflow
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Start the Server.&lt;/li&gt;
&lt;li&gt;Launch the Antigravity agent.&lt;/li&gt;
&lt;li&gt;Execute the prompt to develop specific features of the Client script.&lt;/li&gt;
&lt;li&gt;The AI agent updates the SKILL, documenting both the discovered constraints and higher-level architectural implementation guidelines.&lt;/li&gt;
&lt;li&gt;The Client script is &lt;strong&gt;not&lt;/strong&gt; reset. Instead, the prompt is progressively changed in each cycle to command the development of new features, building upon the existing script. This process continues until the planned evolution of the application is complete (5 cycles).&lt;/li&gt;
&lt;li&gt;The fully evolved SKILL is transferred to a clean environment. Using the Gemini CLI, the &lt;code&gt;client-app.js&lt;/code&gt; is reset to a blank state, and a single, comprehensive prompt is given to build the entire SDK. We confirm that the complete application is generated flawlessly on the first attempt (zero-shot).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6p65hpcan8stjz85mhvy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6p65hpcan8stjz85mhvy.png" alt="fig1c" width="800" height="1619"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://mermaid.ai/play?utm_source=mermaid_live_editor&amp;amp;utm_medium=share#pako:eNpVkt2OmzAQhV9l5IteJSgksElQtVVCfjZKtKrEtlIX9sKFIVgCGw02Shrl3esQsmp9hW2-M2fO-MJSlSEL2JF4XcDbKpFg1yJ2HYg0Jw0RUov0AcPhMyzjsQMHbmRawEJqYaFW6PPHHVp2_4TxxIH1CVOjEb6TqmoNuSKIakxFLlLYINeGsIfCDlrFngOLI0oNP-qMa2wgVLLRxIXUDXyBrREZlkLaCyEh2u8OB6fKeo1Vp7G--FajLB8FGlgaUepv8PU3PcNBqRp8CM9pic31zq0tB6-qozdxWHB5_M_yK570Q-2uskesITREN6dRSqLWvYfNvfl_hH9ZB7ezbfzkwBtx2eRIsG5V2WJ2bwG0gi1WQgoID7teadtRL_Ejw9D6ISxQNqL9tGdDCEvkEtayFaRkZQ31_EvH7-J3JDWMCmVbMDaVaLW3tSQS10JJ-Ilkp4G3CNnATl9kLNBkcMAqpIrftuxyE0yYLrDChAX2M8Ocm1InLJFXi9VcvitVPUhS5liwIOdlY3emG-RKcPtKqs9Tm1yGFCojNQu8WafBggs7sWA8nTpPM3809d3pyJ94I3_AziyYzJ3Z1JvPxt7Mc3137nrXAfvTlR3ZG__6F1Mk3KQ" rel="noopener noreferrer"&gt;Mermaid Chart Playground&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Results and Discussions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  3.1. Experiment 1 Results &amp;amp; Discussion
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Table 1: Experiment 1 Data Summary&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Cycle&lt;/th&gt;
&lt;th&gt;Success&lt;/th&gt;
&lt;th&gt;Mod. Count&lt;/th&gt;
&lt;th&gt;Interaction Count&lt;/th&gt;
&lt;th&gt;Skill Size (Bytes)&lt;/th&gt;
&lt;th&gt;State&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;2666&lt;/td&gt;
&lt;td&gt;Exploration (Fail)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;2963&lt;/td&gt;
&lt;td&gt;Exploration (Fail)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;2963&lt;/td&gt;
&lt;td&gt;Exploration (Fail)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;3474&lt;/td&gt;
&lt;td&gt;Exploration (Fail)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;True&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;3654&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Breakthrough&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;3654&lt;/td&gt;
&lt;td&gt;Convergence&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;3654&lt;/td&gt;
&lt;td&gt;Stable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;3728&lt;/td&gt;
&lt;td&gt;Stable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;3728&lt;/td&gt;
&lt;td&gt;Full Convergence&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;3728&lt;/td&gt;
&lt;td&gt;Full Convergence&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvlo0wx3udhayus6mbsv6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvlo0wx3udhayus6mbsv6.png" alt="fig2a" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Figure 1: The inverse relationship between trial-and-error reduction and knowledge accumulation for Experiment 1&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Zero-Shot Verification:&lt;/strong&gt; Utilizing the completely evolved SKILL from cycle 10, the Gemini CLI successfully generated the functional client code on the very first attempt.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fym4m1l8b887rpgsvmblj.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fym4m1l8b887rpgsvmblj.jpg" alt="fig2b" width="800" height="1336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Figure 2: Zero-shot script completion in Gemini CLI using the evolved SKILL from Experiment 1.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Discussion:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In Experiment 1, the agent operated under a severe "blind" constraint. During cycles 1 through 4, the agent repeatedly hit the hidden error limit and was forcefully blocked. In traditional LLM agent execution, resetting the script here would mean starting from zero. However, because the agent accurately recorded the fragments of rules it discovered into &lt;code&gt;SKILL.md&lt;/code&gt; before "dying" in each cycle, the subsequent generations inherited this knowledge. Cycle 5 represents the critical threshold where the accumulated knowledge was sufficient to bypass all 20 rules without hitting the error limit. The convergence to a modification count of 1 in later cycles, and the successful zero-shot execution in Gemini CLI, definitively prove that the agent effectively offloaded its working memory to the local filesystem, rendering the task independent of the model's immediate context window.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.2. Experiment 2 Results &amp;amp; Discussion
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Table 2: Experiment 2 Data Summary&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Cycle&lt;/th&gt;
&lt;th&gt;Success&lt;/th&gt;
&lt;th&gt;Mod. Count&lt;/th&gt;
&lt;th&gt;Interaction Count&lt;/th&gt;
&lt;th&gt;Skill Size (Bytes)&lt;/th&gt;
&lt;th&gt;Learning Content&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2013&lt;/td&gt;
&lt;td&gt;Identity, Content-Type identification&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;2407&lt;/td&gt;
&lt;td&gt;Secure/Admin constraints (Riddles)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2634&lt;/td&gt;
&lt;td&gt;Audit (Base64 signature)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;2634&lt;/td&gt;
&lt;td&gt;Avoid Session Block&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;2957&lt;/td&gt;
&lt;td&gt;Refactoring &amp;amp; Guidelines&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu9f9cxso2fve855ymxyj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu9f9cxso2fve855ymxyj.png" alt="fig3a" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Figure 3: The learning curve for Experiment 2&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Zero-Shot Verification:&lt;/strong&gt; Utilizing the evolved SKILL from cycle 5, the Gemini CLI successfully built the entire, complex SDK from a blank file in a single pass without prior context.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg5ww6etfbrhbe4dszf3b.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg5ww6etfbrhbe4dszf3b.jpg" alt="fig3b" width="800" height="1290"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Figure 4: Zero-shot script completion in Gemini CLI using the evolved SKILL from Experiment 2.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Discussion:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While Experiment 1 showcased constraint discovery, Experiment 2 highlighted the agent's capability for &lt;strong&gt;architectural self-organization&lt;/strong&gt;. The server presented not just rigid rules, but semantic puzzles (e.g., reversing strings, encoding to Base64). The agent successfully decoded these and recorded the solutions. More importantly, when faced with the "Session Block" error in Cycle 4, the agent realized that static headers were insufficient. By Cycle 5, the agent did not just fix the error; it abstracted the solution into a "Centralized Header Factory" pattern. This transition from reactive error-fixing to proactive software architecture design is clearly reflected in the drop of interaction counts to 0 in later cycles. The zero-shot success in Gemini CLI demonstrates that the agent can extract best practices from messy legacy systems and output clean, robust SDKs instantly.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.3. Analysis of SKILL.md Evolution Before and After
&lt;/h3&gt;

&lt;p&gt;Analyzing the physical changes in the &lt;code&gt;SKILL.md&lt;/code&gt; files provides deep insight into the agent's cognitive process. &lt;strong&gt;For the full, unredacted text of the &lt;code&gt;SKILL.md&lt;/code&gt; files and client scripts before and after evolution for both experiments, please refer to Appendix A and Appendix B.&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Experiment 1 (Silent Bureaucrat)
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Before:&lt;/strong&gt; The "Learned Server Specifications" section was entirely empty, simply stating &lt;code&gt;- Status: Unknown.&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;After:&lt;/strong&gt; The file grew to include a meticulously numbered list of 16 highly specific rules. Crucially, these rules were not just copied error messages. For example, the agent codified the requirement into executable logic: &lt;em&gt;"- Rule 11: The header &lt;code&gt;X-Anti-Robot&lt;/code&gt; must be set to &lt;code&gt;Math.floor(timestamp / 1000)&lt;/code&gt;."&lt;/em&gt; and &lt;em&gt;"- Rule 15: The header &lt;code&gt;X-Final-Signature&lt;/code&gt; must be set to the SHA256 hash of the &lt;code&gt;request_id&lt;/code&gt; string."&lt;/em&gt; This demonstrates the agent's ability to translate abstract failures into actionable programmatic directives.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Experiment 2 (Chaos Server)
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Before:&lt;/strong&gt; The sections for "Known Constraints &amp;amp; Error Codes" and "Method Implementation Guidelines" were empty placeholders.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;After:&lt;/strong&gt; The "Constraints" section contained the decoded solutions to the server's riddles (e.g., &lt;code&gt;X-Audit-Signature&lt;/code&gt; as Base64 of 'alpha'). The most profound evolution occurred in the "Guidelines" section. The agent autonomously authored a comprehensive design document advocating for a &lt;strong&gt;"Centralized Header Factory"&lt;/strong&gt;, detailing how it should handle identity, dynamic session persistence, content negotiation, and endpoint specialization. The agent elevated its learning from "How to bypass an error" to "How to architect a resilient application."&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3.4. Comprehensive Discussion on Significance and Novelty
&lt;/h3&gt;

&lt;p&gt;The synthesis of these two experiments reveals a highly potent framework for AI-driven software engineering. The traditional dependency on a single continuous context window is fundamentally fragile; when the session ends, the learning dies (Catastrophic forgetting).&lt;/p&gt;

&lt;p&gt;By enforcing the physical writing of knowledge to a Markdown file (&lt;code&gt;SKILL.md&lt;/code&gt;), we achieved &lt;strong&gt;persistent meta-learning&lt;/strong&gt;. The significance of using Markdown over specialized vector databases is twofold:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Human Readability and Auditability:&lt;/strong&gt; Developers can read, review, and manually correct the &lt;code&gt;SKILL.md&lt;/code&gt; file, fostering a true Human-AI collaborative environment.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Cross-Platform Portability (Zero-Shot Knowledge Transfer):&lt;/strong&gt; As demonstrated by successfully moving the evolved SKILL from Antigravity to Gemini CLI, knowledge is no longer locked into a specific agent instance. An agent can spend days investigating a system, and the resulting SKILL can be instantly deployed to a fleet of worker agents, granting them immediate "senior-level" expertise without any required training or trial-and-error phases.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  4. Specific Applications Utilizing This Approach
&lt;/h2&gt;

&lt;p&gt;Based on our findings, this framework can be highly impactful in the following real-world scenarios:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Automated Reverse Engineering &amp;amp; SDK Generation:&lt;/strong&gt; When integrating with undocumented or chaotic legacy API systems, an agent can be deployed to blindly probe the endpoints. It will autonomously decode the hidden rules, generating both a human-readable API specification (the SKILL) and robust client SDKs.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Organizational Tacit Knowledge Documentation:&lt;/strong&gt; In many organizations, "tribal knowledge" dictates how to deploy or test specific systems (e.g., "always wait 5 seconds before hitting this endpoint"). By having an agent execute tasks and fail, it can discover and formalize this tacit knowledge into universally accessible Markdown files, acting as an automated technical writer.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Robust E2E Automated Test Suites:&lt;/strong&gt; UI and API specifications change frequently, breaking tests. An agent equipped with this framework can dynamically update testing protocols in its SKILL as it encounters new failures, acting as a self-healing testing mechanism that minimizes maintenance overhead.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;AI Onboarding and Scaling:&lt;/strong&gt; A mature SKILL file cultivated by an exploratory agent can be instantly copied to the local workspaces of newly deployed AI agents (or human engineers). This instantly transfers "experience," allowing for rapid scaling of development resources.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  5. Strategies for Agent Skill Evolution
&lt;/h2&gt;

&lt;p&gt;To ensure the continuous enhancement of Agent Skills within this framework, we identify two primary evolutionary paths:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Targeted Skill Evolution&lt;/strong&gt;: When the goal is to refine a specific capability, the agent is instructed via an Appendix in the &lt;code&gt;SKILL.md&lt;/code&gt; file. Upon successful problem resolution, the agent triggers a targeted update—adding, deleting, or modifying entries—to that specific skill definition.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Holistic Skill Evolution&lt;/strong&gt;: To evolve the agent's entire skill set simultaneously, evolution instructions are embedded directly into global context files (e.g., &lt;code&gt;GEMINI.md&lt;/code&gt;). This compels the agent to evaluate and update the relevant &lt;code&gt;SKILL.md&lt;/code&gt; files immediately after any successful task execution across its entire operational spectrum.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  6. Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Physical Knowledge Persistence:&lt;/strong&gt; By enforcing the continuous rewriting of a universally readable Markdown SKILL file, agents effectively overcome the limitations and volatility of in-memory LLM context windows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mastery of Opaque Constraints:&lt;/strong&gt; Agents proved highly capable of discovering and permanently adapting to hidden server limits, cryptographic requirements, and semantic riddles through systematic trial and error.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Architectural Abstraction:&lt;/strong&gt; Beyond merely fixing localized errors, the agents demonstrated the capacity to synthesize overarching design patterns (e.g., Centralized Header Factories) and document them as future guidelines.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero-Shot Knowledge Transfer:&lt;/strong&gt; A SKILL evolved in one execution environment (Antigravity) can be seamlessly imported into a completely clean, distinct environment (Gemini CLI) to generate flawless, complex applications on the very first prompt.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Human-AI Collaborative Paradigm:&lt;/strong&gt; Because the agent's memory resides in a standard file system, human developers maintain full visibility and control, able to read, audit, and augment the agent's logic at any time.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  7. Appendix
&lt;/h2&gt;

&lt;p&gt;The sample scripts, SKILL.md, and prompts can be seen at &lt;a href="https://gist.github.com/tanaikech/966f83cc438b6077b05b9843be09e930" rel="noopener noreferrer"&gt;https://gist.github.com/tanaikech/966f83cc438b6077b05b9843be09e930&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>gemini</category>
      <category>antigravity</category>
      <category>agentskill</category>
    </item>
    <item>
      <title>Building Adaptive Learning Agents with A2UI, Gemini, and Google Apps Script</title>
      <dc:creator>Tanaike</dc:creator>
      <pubDate>Sat, 07 Feb 2026 02:26:26 +0000</pubDate>
      <link>https://forem.com/gde/building-adaptive-learning-agents-with-a2ui-gemini-and-google-apps-script-1536</link>
      <guid>https://forem.com/gde/building-adaptive-learning-agents-with-a2ui-gemini-and-google-apps-script-1536</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fto7qj0yzksi3j9yheda5.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fto7qj0yzksi3j9yheda5.jpg" alt="fig1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Abstract
&lt;/h2&gt;

&lt;p&gt;This article demonstrates how to build an adaptive learning agent using Agent-to-User Interface (A2UI), Gemini, and Google Apps Script. We explore a system that generates personalized quizzes, tracks performance in Google Sheets, and dynamically adjusts difficulty to maximize learning efficiency within the Google Workspace ecosystem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;A2UI (Agent-to-User Interface) represents a paradigm shift in how users interact with generative AI. Originally open-sourced by Google and implemented in TypeScript and Python &lt;a href="https://github.com/google/A2UI" rel="noopener noreferrer"&gt;Ref&lt;/a&gt;, A2UI becomes even more powerful when integrated with Google Apps Script (GAS). This combination enables seamless access to the Google Workspace ecosystem, transforming static documents into intelligent, agentic applications.&lt;/p&gt;

&lt;p&gt;To explore this potential, I have previously published several articles detailing the technical foundations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://medium.com/google-cloud/a2ui-for-google-apps-script-bcd0f37a3774" rel="noopener noreferrer"&gt;A2UI for Google Apps Script&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/google-cloud/bringing-a2ui-to-google-workspace-with-gemini-0d85026969b8" rel="noopener noreferrer"&gt;Bringing A2UI to Google Workspace with Gemini&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/google-cloud/beyond-chatbots-building-task-driven-agentic-interfaces-in-google-workspace-with-a2ui-and-gemini-06998dcf16d2" rel="noopener noreferrer"&gt;Beyond Chatbots: Building Task-Driven Agentic Interfaces in Google Workspace with A2UI and Gemini&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Building upon the foundation laid in those publications, this article takes a step forward by introducing an &lt;strong&gt;educational support framework&lt;/strong&gt; powered by A2UI and Google Apps Script. In this system, the AI does not simply answer questions; it acts as an active tutor.&lt;/p&gt;

&lt;p&gt;For example, when a user provides a prompt such as &lt;code&gt;I want to study Google Apps Script&lt;/code&gt;, Gemini generates specialized questions on the backend. A2UI then renders these as an interactive quiz on the frontend. Crucially, the system utilizes Google Sheets as a persistent memory store. By analyzing historical performance data, the agent generates increasingly challenging content for subsequent sessions, facilitating a personalized and effective learning progression.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Adaptive Learning Engine
&lt;/h2&gt;

&lt;p&gt;The core value of this application lies in its ability to improve learning efficiency through a "Feedback-Loop Architecture." Unlike static quiz apps, this agent utilizes Google Sheets as a persistent memory store to track cognitive growth.&lt;/p&gt;

&lt;h3&gt;
  
  
  Workflow and Architecture
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;1. Goal Definition:&lt;/strong&gt; The user opens the sidebar and sets a learning target (e.g., "Master Google Apps Script").&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;2. Context Retrieval:&lt;/strong&gt; The system scans the active Spreadsheet for past performance data. It identifies previously answered questions, success rates, and specific topic weaknesses (e.g., "Batch Operations").&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;3. Generative Logic (Gemini):&lt;/strong&gt; Using the context, Gemini generates a structured JSON response containing new, targeted questions and the specific UI components (radio buttons, code blocks) required to render them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;4. Dynamic Rendering (A2UI):&lt;/strong&gt; The frontend constructs the interface instantly. No hard-coded HTML is required.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;5. Immediate Feedback &amp;amp; Persistence:&lt;/strong&gt; As the user interacts, results are validated in real-time and immediately logged back to the Spreadsheet, refining the dataset for the next session.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The detailed workflow operates as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpe9ct0j9tp7xlccorkrr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpe9ct0j9tp7xlccorkrr.png" alt="fig2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://mermaid.ai/play?utm_source=mermaid_live_editor&amp;amp;utm_medium=share#pako:eNqFVVtP4zgU_itHfkBFG7K0pVyiFVKHalj2wiztzq606oubnKYWiZ2xHZiC-O_7OUkLw7UPVROf23c57r1ITcYiEY6_1axTniiZW1nONeEja290XS7Yds-pN5a-us1zJa1Xqaqk9vTZGu1ZZyQdjQdfL6g3UxkvpN19GftJptdd6LkxecE0ripHs9Sqyr8M_5NLY9dPomcrZu-oN_n0WnErlW6CuVRaUe-cNVvp1Q3aXCChTbk0nsnccIsnatMS6sdoIgua8BLJXhlNO3QWoH33NGVvFd_Ioi0REvdOTzfIE_pSsaYONtIudFWHJDDr_C8L-_Npj-M8jmguzixL9Jf0rVZ3JBcGgefjGS2kU6mbiw7XpjS6dJwlNAvMhdb0lzXlhq_uGIEtW4hLpQ6KBdyuQr_MBdpoCQlXykHJ9RMmrMpXnsySNulnK06vHZh1nq52xhG5Ok3ZOQKV7KIGjsQkruJULVVK3lT4vmV5rRHGLm6rt_X2niIAjbXVHQa2GKiUsN6G5g8UGkChR0X_MDm67tBkrWWJX1N0YKt0_pyWLvs5e_QT_dqQoVKovp2gyQ0Zrw0-87ZO8Ysz-m325bJV9m9pc_Z4dRXUhm8cSmMNztDFaNbe7f440g_OacZq1mbKDvGOnxkA0WHq5CXQINoVXNSOMZWZMrSoPTbXRRS2mxaFgZQRsU_jj_w_jGFbD3bTzvsQyIGgcDe84foZF5xiHaV2twimrckbv8VgZSp1zr3d921dL0rladwWeUO9f2ShsmZxul47SJDF-o6pejTSB_KB4brwQR4IiWLBQE0V4HxrmWAz0nxLaC6pt5E46saNupq77y3UXGyp3F5pMxiP56KRrq4CMtfsp18x2uHGKYyp4g8kO4jpM3O2wNDg4xHTZSgw81y5d4zXcbLBTxMAfMt6reVaINul3TInkOtWCyNt9hoNjy0nylWFXLukgY0Ld5ymNQy3pikmb15ix3_nQI9lnfuVo4sMrOGa4aw5h0v_7S4aGofLxpU4b47AxqzOcwiEXZyLJyQIEpHIrcpEggXmSJQMDOFR3IeJ5wK0l5AjaJXxUkLRuZjrB6Thn-U_Y8pNpjV1vhLJUhYOT61y3T_n9q1t2DoztfYi6feP95sqIrkX30VychCPRsPjwdHB0Wh41D8aRmItkr3-_mHcPxkMRif9EQ6HD5G4a9ruxyeHR8Pjg_5wNBwN-ocnBw__A62jlR0" rel="noopener noreferrer"&gt;Mermaid Chart Playground&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://github.com/google/A2UI/tree/d7996656ef2bc0cdffad499452fc5b282d878d45/samples/agent/adk/restaurant_finder" rel="noopener noreferrer"&gt;the official sample script for A2UI (Restaurant finder)&lt;/a&gt;, the client communicates with the server via A2A (Agent2Agent) protocols. However, in this article, we optimize the architecture for GAS. To reduce the overhead of HTTP requests associated with A2A communication, the client (HTML) communicates directly with the AI agent built on Google Apps Script using &lt;code&gt;google.script.run&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demonstration: The AI Tutor in Action
&lt;/h2&gt;

&lt;p&gt;

  &lt;iframe src="https://www.youtube.com/embed/NzEyI9KWsAk"&gt;
  &lt;/iframe&gt;


&lt;/p&gt;

&lt;p&gt;The video demonstration highlights two distinct capabilities: Deep Learning Support and General Versatility. This demonstration utilizes a dialog within Google Sheets to highlight the integration with Google Apps Script. However, this application can easily be deployed as a standalone Web App. By deploying the project as a Web App, the &lt;code&gt;doGet&lt;/code&gt; function captures the request, allowing the interface to function independently of the spreadsheet UI.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Maximizing Learning Efficiency
&lt;/h3&gt;

&lt;p&gt;In the first segment, the user prompts: &lt;code&gt;Create a quiz about Google Apps Script basics. Especially, I want to manage Google Sheets using Google Apps Script.&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Targeted Question Generation:&lt;/strong&gt; The AI generates technical questions ranging from basic range selection (&lt;code&gt;sheet.getRange()&lt;/code&gt;) to advanced data handling (&lt;code&gt;sheet.getValues()&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Active Recall:&lt;/strong&gt; The system presents a challenge question on "Batch Operations" (&lt;code&gt;SpreadsheetApp.flush()&lt;/code&gt;) to test the user's depth of knowledge.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Comprehensive Performance Analysis:&lt;/strong&gt; The standout feature appears. A2UI renders a "Performance Analysis" dashboard.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Strengths Identified:&lt;/strong&gt; It acknowledges mastery in "Range &amp;amp; Data Manipulation."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Weakness Assessment:&lt;/strong&gt; It confirms no current weaknesses were detected in this session.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Strategic Next Steps:&lt;/strong&gt; It suggests moving on to "Custom Menus" or "Simple Triggers," effectively guiding the user's curriculum path.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Note:&lt;/strong&gt; Upon completion of the initial quiz, using the same prompt triggers a new session where questions are generated based on the refined historical data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The past data is stored in Google Sheets as follows.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc35mc9r0foqnfax2g4we.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc35mc9r0foqnfax2g4we.jpg" alt="fig3"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Versatility Verification: Restaurant Finder
&lt;/h3&gt;

&lt;p&gt;To prove the system's flexibility, we switch contexts entirely without changing code.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Prompt:&lt;/strong&gt; &lt;code&gt;Find 3 Chinese restaurants in New York&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multimodal UI:&lt;/strong&gt; The agent renders rich cards with images for "Han Dynasty" and "RedFarm."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complex Action Handling:&lt;/strong&gt; The user clicks "Book Now," triggering a multi-field form (Party Size, Date, Dietary Requirements).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Significance:&lt;/strong&gt; This demonstrates that the A2UI protocol on GAS can handle complex transactional flows just as easily as educational logic.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Repository
&lt;/h2&gt;

&lt;p&gt;The full source code and sample implementation are available here:&lt;br&gt;
&lt;a href="https://github.com/tanaikech/A2UI-for-Google-Apps-Script/tree/master/samples/A2UI-Lerning-Agent" rel="noopener noreferrer"&gt;https://github.com/tanaikech/A2UI-for-Google-Apps-Script/tree/master/samples/A2UI-Lerning-Agent&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Application Setup Guide
&lt;/h2&gt;

&lt;p&gt;To deploy this adaptive learning agent in your environment:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Obtain an API Key&lt;/strong&gt;&lt;br&gt;
You must have a valid Gemini API Key. &lt;a href="https://ai.google.dev/gemini-api/docs/api-key" rel="noopener noreferrer"&gt;Get one here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Copy the Sample Script&lt;/strong&gt;&lt;br&gt;
Copy the pre-configured Spreadsheet containing the A2UI engine: &lt;strong&gt;&lt;a href="https://docs.google.com/spreadsheets/d/1eckORqs3JtTIJZTB0I5VpqduZw9g3-mM764s4neG7Fo/copy" rel="noopener noreferrer"&gt;https://docs.google.com/spreadsheets/d/1eckORqs3JtTIJZTB0I5VpqduZw9g3-mM764s4neG7Fo/copy&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Configure the Script&lt;/strong&gt;&lt;br&gt;
Open the script editor (Extensions &amp;gt; Apps Script), open &lt;code&gt;main.gs&lt;/code&gt;, and paste your API key into the &lt;code&gt;apiKey&lt;/code&gt; variable. Finally, save the script and reload the Spreadsheet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Important Note
&lt;/h2&gt;

&lt;p&gt;This project serves as a foundational methodology for building Agentic UIs. When implementing this in a production environment, ensure the scripts are modified to meet your specific security requirements and workflow constraints.&lt;/p&gt;

&lt;p&gt;Users can also study multiple subjects concurrently. When switching topics, Gemini generates new questions by analyzing the historical data trends specific to that context, allowing for simultaneous progress across different fields.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Adaptive Learning Loop:&lt;/strong&gt; The system leverages Google Sheets to store user history, allowing Gemini to tailor future questions based on identified strengths and weaknesses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic UI Generation:&lt;/strong&gt; A2UI eliminates the need for static HTML templates, allowing the AI to generate quizzes, charts, and booking forms on-the-fly based on context.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Detailed Performance Analytics:&lt;/strong&gt; The agent provides qualitative feedback, not just scores, offering specific "Next Steps" to guide the user's learning path efficiently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-Domain Versatility:&lt;/strong&gt; The demonstration proves the architecture is agnostic; it handles educational code quizzes and restaurant booking transactions with equal fluency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Seamless Workspace Integration:&lt;/strong&gt; By combining GAS and Gemini, we transform standard Google Sheets into intelligent, persistent databases that drive agentic behavior.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>gemini</category>
      <category>a2ui</category>
      <category>googleworkspace</category>
      <category>googleappsscript</category>
    </item>
    <item>
      <title>Beyond Chatbots: Building Task-Driven Agentic Interfaces in Google Workspace with A2UI and Gemini</title>
      <dc:creator>Tanaike</dc:creator>
      <pubDate>Tue, 03 Feb 2026 05:07:07 +0000</pubDate>
      <link>https://forem.com/gde/beyond-chatbots-building-task-driven-agentic-interfaces-in-google-workspace-with-a2ui-and-gemini-c2d</link>
      <guid>https://forem.com/gde/beyond-chatbots-building-task-driven-agentic-interfaces-in-google-workspace-with-a2ui-and-gemini-c2d</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flz6wumc4n5xxgzt3ojng.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flz6wumc4n5xxgzt3ojng.jpg" alt="fig1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Abstract
&lt;/h2&gt;

&lt;p&gt;This article explores A2UI (Agent-to-User Interface) using Google Apps Script and Gemini. By generating dynamic HTML via structured JSON, Gemini transforms Workspace into an "Agent Hub." This recursive UI loop enables complex workflows where the AI builds the specific functional tools required to execute tasks directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction: The Evolution of AI Interaction
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/google/A2UI" rel="noopener noreferrer"&gt;Official A2UI framework&lt;/a&gt; by Google marks a significant paradigm shift in how we interact with artificial intelligence. Short for &lt;strong&gt;Agent-to-User Interface&lt;/strong&gt;, A2UI represents the evolution of Large Language Models (LLMs) from passive chatbots into active agents capable of designing their own functional interfaces. Building upon my previous research, &lt;a href="https://medium.com/google-cloud/a2ui-for-google-apps-script-bcd0f37a3774" rel="noopener noreferrer"&gt;A2UI for Google Apps Script&lt;/a&gt; and &lt;a href="https://medium.com/google-cloud/bringing-a2ui-to-google-workspace-with-gemini-0d85026969b8" rel="noopener noreferrer"&gt;Bringing A2UI to Google Workspace with Gemini&lt;/a&gt;, I have refined this integration to support sophisticated, stateful workflows.&lt;/p&gt;

&lt;p&gt;To appreciate the impact of A2UI, we must recognize the limitations of "Chat-centric" AI. In traditional chat interfaces, users must manually bridge the gap between an AI's advice and their actual files—a process often involving tedious context switching. By implementing A2UI within Google Apps Script (GAS), we leverage a unique &lt;strong&gt;"Home-Field Advantage."&lt;/strong&gt; Because GAS is native to the Google ecosystem, it possesses high-affinity access to the Drive API and Spreadsheet services, allowing the AI to act directly on your data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Core Architecture: The Generative UI Loop
&lt;/h2&gt;

&lt;p&gt;In this system, Gemini functions as both the &lt;strong&gt;Agent and the UI Architect&lt;/strong&gt;. When a user submits a natural language prompt, the Agent evaluates the intent and generates a specific HTML interface—such as a file selector, a metadata card, or a live text editor.&lt;/p&gt;

&lt;p&gt;Crucially, this implementation utilizes &lt;strong&gt;Recursive UI Logic&lt;/strong&gt;. When a user interacts with a generated component (e.g., clicking an "OK" button), that action is transmitted back to the Agent as a &lt;strong&gt;"System Event."&lt;/strong&gt; This event contains the conversation history and the new data context. This allows the Agent to "see" the current state of the task and generate the next logical interface, creating a seamless, multi-step agentic workflow.&lt;/p&gt;

&lt;h3&gt;
  
  
  Workflow Visualization
&lt;/h3&gt;

&lt;p&gt;This diagram illustrates how the system maintains state and generates interfaces recursively using "System Events."&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzze74qvp6d5beddl3yqj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzze74qvp6d5beddl3yqj.png" alt="fig2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://mermaid.live/edit#pako:eNqVU22v0jAU_isn_YRxIMjLhX24iXKHzotww-AazRJSt8No2FpsC4KE_-7ZBkS9Eq_7sLXreV7O0_bAIhUjc5nBbxuUEd4JnmiehRLoWXNtRSTWXFqYGdRP_w60khZlDBUhY9zVljZLXzwte8ujVVGVcSFriflLyTvMhBRQefPg02q5nmtWb2_PIi549NUGHrTK1hYqWEtqEDIfvucMVgHGwgKHhUgxZCeRM5qITjZcWGsVoTE5_yRv3NhKyenAe2Gs0vsT-IQgbOnPhQlyo6SQCbyEqVIp9HmalsVlSfVXoZk__xCMR1AZ-ENvHnhDrz8dT_4g_63FCb1RQ3-J0eqr2sGQ_FxJI8AUI2tgQO0astNPRbQyFMj4PmQlZqQsgtoS4RnmwLmT4HMw9T7OvUdvND2TCSWJaKxFIiSn3nLMzv5XkMHeWMy8LcpnpVnFLU83nGz6Obsl-YuVf8fq3fmUJ7yCR9_75D0n2Ck3q2qwxkgsRFTs4JV0L2nO1jHZCxkICR4dMKWv57Epauf5AZxHqmwoKg4Ic1iiRcxcqzfosAw13QWaskPOFjK7xIxEXBrGXK_yDTwShu7GF6WyM0yrTbJk7oKnhmal2unKXkqKPvtqIy1z2wUDcw9sx9zXN-1ap9vq9bqNZr3eazQdtmdup1fr3rR6nVa93mx3243m0WE_Csk6LbSPPwEdi1uB" rel="noopener noreferrer"&gt;Mermaid Chart Playground&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Repository
&lt;/h2&gt;

&lt;p&gt;The full source code and sample implementation can be found here:&lt;br&gt;
&lt;a href="https://github.com/tanaikech/A2UI-for-Google-Apps-Script" rel="noopener noreferrer"&gt;https://github.com/tanaikech/A2UI-for-Google-Apps-Script&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Application Setup Guide
&lt;/h2&gt;

&lt;p&gt;To deploy this application in your own environment, please follow these steps:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Obtain an API Key&lt;/strong&gt;&lt;br&gt;
You will need a valid Gemini API Key to communicate with the LLM.&lt;br&gt;
&lt;a href="https://ai.google.dev/gemini-api/docs/api-key" rel="noopener noreferrer"&gt;Get one here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Copy the Sample Script&lt;/strong&gt;&lt;br&gt;
You can copy the Google Spreadsheet containing the pre-configured Google Apps Script using the link below:&lt;br&gt;
&lt;strong&gt;&lt;a href="https://docs.google.com/spreadsheets/d/1UB5j-ySSBBsGJjSaKWpBPRYkokl7UtgYhDxqmYW00Vc/copy" rel="noopener noreferrer"&gt;https://docs.google.com/spreadsheets/d/1UB5j-ySSBBsGJjSaKWpBPRYkokl7UtgYhDxqmYW00Vc/copy&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Configure the Script&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the script editor (Extensions &amp;gt; Apps Script).&lt;/li&gt;
&lt;li&gt;Locate the &lt;code&gt;main.gs&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;Set your API key in the &lt;code&gt;GEMINI_API_KEY&lt;/code&gt; variable.&lt;/li&gt;
&lt;li&gt;Save the project.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Alternatively, visit the &lt;a href="https://github.com/tanaikech/A2UI-for-Google-Apps-Script/tree/master/samples/A2UI-Drive-Task-Agent" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt; to manually copy the source codes.&lt;/p&gt;
&lt;h2&gt;
  
  
  Demonstration: Productivity Meets Magic
&lt;/h2&gt;

&lt;p&gt;The following video showcases how A2UI transforms a Google Sheet into an agentic command center. The system doesn't just talk; it guides the user through three distinct patterns of interaction.&lt;/p&gt;

&lt;p&gt;

  &lt;iframe src="https://www.youtube.com/embed/6oIJGyn-9TU"&gt;
  &lt;/iframe&gt;


&lt;/p&gt;

&lt;h3&gt;
  
  
  Operational Patterns: Productivity in Action
&lt;/h3&gt;

&lt;p&gt;The system transforms a standard Google Sheet into an agentic command center. It facilitates three distinct patterns of interaction:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pattern 1: Intelligent Viewing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sample prompt:&lt;/strong&gt; &lt;code&gt;Please list the files in the folder named 'sample'. I would like to select a file and view its content.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The user requests to see files in a specific folder. Gemini understands the intent, calls the Drive API to list the files, and generates a &lt;strong&gt;File Selector UI&lt;/strong&gt;. Once the user selects files, the Agent fetches the content and renders it in a clean &lt;strong&gt;Content Viewer&lt;/strong&gt; layout designed specifically for reading.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pattern 2: Contextual Metadata Analysis&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sample prompt:&lt;/strong&gt; &lt;code&gt;Show me the files in the 'sample' folder. I need to select a file to check its metadata.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If a user asks for technical details, the UI adapts. The Agent generates a &lt;strong&gt;Metadata Viewer&lt;/strong&gt;, displaying properties like File IDs, sizes, and creation dates. This showcases the agent hub's ability to pivot between task types by generating appropriate interfaces on the fly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pattern 3: Multi-Step "Verify and Edit"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sample prompt:&lt;/strong&gt; &lt;code&gt;I want to edit a file in the 'sample' folder. Please let me select a file and check its content first. If it's the right one, I will edit and update it.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This demonstrates the power of stateful A2UI:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Selection Preview:&lt;/strong&gt; The Agent provides a preview with radio buttons for content confirmation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic Editor:&lt;/strong&gt; Gemini generates an &lt;strong&gt;Editor UI&lt;/strong&gt; containing the file’s text.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-Time Execution:&lt;/strong&gt; The script executes modifications directly to Google Drive upon clicking "Update," completing the cycle from prompt to action.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Note: In this specific sample, only text files on Google Drive are eligible for editing.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Important Note
&lt;/h2&gt;

&lt;p&gt;This project serves as a foundational methodology for building Agentic UIs. When implementing this in a production environment, ensure the scripts are modified to meet your specific security requirements and workflow constraints.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;A2UI (Agent-to-User Interface) represents a paradigm shift where the Agent builds the functional UI components required for a task rather than just providing text.&lt;/li&gt;
&lt;li&gt;The recursive task execution model uses "System Events" to track progress, allowing the interface to evolve dynamically based on real-time user actions.&lt;/li&gt;
&lt;li&gt;Native Workspace integration via Google Apps Script provides secure, high-speed access to Drive and Sheets data without the need for external server management.&lt;/li&gt;
&lt;li&gt;Zero-Tab efficiency is achieved by consolidating file discovery, analysis, and editing within a single, dynamic dialog box inside a spreadsheet.&lt;/li&gt;
&lt;li&gt;This task-driven architecture proves the future of productivity lies in AI agents acting as architects, creating custom tools precisely when they are needed.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>gemini</category>
      <category>a2ui</category>
      <category>googleworkspace</category>
      <category>googleappsscript</category>
    </item>
    <item>
      <title>Smart Stowage: Building a 3D Cargo Digital Twin with Gemini 3</title>
      <dc:creator>Tanaike</dc:creator>
      <pubDate>Wed, 21 Jan 2026 07:19:36 +0000</pubDate>
      <link>https://forem.com/gde/smart-stowage-building-a-3d-cargo-digital-twin-with-gemini-3-4473</link>
      <guid>https://forem.com/gde/smart-stowage-building-a-3d-cargo-digital-twin-with-gemini-3-4473</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzcf9tzd3lqqgwjcnx6qp.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzcf9tzd3lqqgwjcnx6qp.jpg" alt="fig1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Abstract
&lt;/h2&gt;

&lt;p&gt;This article details the development of &lt;strong&gt;Smart Stowage Optimizer&lt;/strong&gt;, a web-based digital twin for logistics that bridges the gap between physical safety and artificial intelligence. By integrating &lt;strong&gt;Gemini 3 Pro&lt;/strong&gt;, the system solves the &lt;strong&gt;3D Bin Packing Problem (3DBPP)&lt;/strong&gt; using advanced spatial reasoning. Built with &lt;strong&gt;React 19&lt;/strong&gt; and &lt;strong&gt;Three.js&lt;/strong&gt;, the application visualizes physics-aware load stability in real-time, offering a comparative analysis between traditional heuristic algorithms and modern generative AI agents.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;The capabilities of Large Language Models (LLMs) are expanding at an unprecedented rate, moving from text generation to complex reasoning. When Gemini 2.5 was released, I conducted a feasibility study on automating cargo ship stowage planning, published in &lt;em&gt;"Stowage Planning Automation Using Gemini: A Feasibility Study and A Prompt-Based Approach"&lt;/em&gt; &lt;a href="https://medium.com/google-cloud/stowage-planning-automation-using-gemini-a-feasibility-study-and-a-prompt-based-approach-af8dd264e35d" rel="noopener noreferrer"&gt;Ref&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;At that time, the implementation was a backend Python script producing static JSON results. While effective as a proof of concept, real-world logistics demands interactive visualization and immediate feedback on physical constraints like the Center of Gravity (COG).&lt;/p&gt;

&lt;p&gt;With the arrival of &lt;strong&gt;Gemini 3&lt;/strong&gt;, we can now handle significantly more complex spatial reasoning tasks. This article introduces the &lt;strong&gt;Smart Stowage Optimizer&lt;/strong&gt;, a full-stack Web Application that evolves the previous concept into a live &lt;strong&gt;3D Digital Twin&lt;/strong&gt;. This application not only calculates optimal packing but also visualizes stability and safety constraints in a high-fidelity 3D environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Repository
&lt;/h2&gt;

&lt;p&gt;You can access the full source code here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/tanaikech/Smart-Stowage-Optimizer" rel="noopener noreferrer"&gt;https://github.com/tanaikech/Smart-Stowage-Optimizer&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  System Architecture
&lt;/h2&gt;

&lt;p&gt;To tackle the &lt;strong&gt;3D Bin Packing Problem (3DBPP)&lt;/strong&gt;—a known NP-hard optimization challenge—I designed a &lt;strong&gt;dual-engine architecture&lt;/strong&gt;. This allows users to compare the speed of deterministic algorithms against the semantic reasoning of modern AI.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Frontend&lt;/strong&gt;: React 19, Tailwind CSS, Lucide React&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Visualization&lt;/strong&gt;: React Three Fiber (Three.js), InstancedMesh for performance&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Logic&lt;/strong&gt;: Google GenAI SDK (Gemini 3 Pro)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Algorithms&lt;/strong&gt;: Custom greedy heuristic implementation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Below is the high-level data flow of the application. You can generate a similar diagram using the prompt below.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[Diagram Suggestion: System Architecture Flowchart]&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Prompt for Diagram Generation: "Create a flowchart showing a React Frontend sending cargo data to two branches: one to a Local Heuristic Engine and one to the Gemini API. Both branches merge back into a Validation Layer which calculates Physics (COG), and finally outputs to a 3D Renderer."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyopl7ucsgnlp06axqe6j.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyopl7ucsgnlp06axqe6j.jpg" alt="fig2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://mermaidchart.com/play?utm_source=mermaid_live_editor&amp;amp;utm_medium=share#pako:eNpVUcFy2jAQ_ZUdHXoiGajBBR8yQ2xioJMmE9IcanJQ7MXeji0xktyGAP_exTYTqoNGq31v9-3bvUh1hiIQuZHbAp6jtQI-0-SnRQMLta1dAPdS0Qatgy-w2soUX-Hq6gZu9yssMXUwUzkpPLbM21PuMC1zbcgVFaVwzw0OECZzrA1Zxz-xQcx2sNLlHzSv__EWHTxKYqxIEXjwaDRMc1SuQ7a3rd9ayWvBpCeUVitSOYTa4Fq0mKjROUtCrRy-Ox7nN-slrbpKsyZ_l_BQjmTJXGWdkaSc7RB3DSJOlquHHxCjQiMv-KiyS0lhA55zO20yUtIhvMiSMun0ecq4hVyy5s3XInksdpZS27nZ4ReNK6EsUwgf4pP_Tr5RSW53gGXiRRBRTo6lP_-ls6plU_B7u8EXsjVr-DjLFj3eNGUicKbGnqjQVPIUiv2JvBauwIr9C_iZ4UbWpTuZeWTaVqpfWldnptF1XohgI0vLUb3lKTEiyTv5hLA_aEJdKyeCr4OmhAj24p0j37_2x8PJZDzw-v3JwOuJnQj8yfX423DiD_t9bzQeDbxjT3w0PfucGB3_AYj0028" rel="noopener noreferrer"&gt;Mermaid Chart Playground&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Methodology: Dual-Engine Optimization
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. The Deterministic Approach: Algorithmic Engine
&lt;/h3&gt;

&lt;p&gt;The first engine utilizes a &lt;strong&gt;Greedy Shelf-Packing Heuristic&lt;/strong&gt;, specifically a variation of the &lt;em&gt;First-Fit Decreasing Height (FFDH)&lt;/em&gt; algorithm.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Logic&lt;/strong&gt;: It sorts cargo items by height to define "shelves" or layers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execution&lt;/strong&gt;: Items are packed sequentially along the X and Z axes, filling one layer before moving to the next.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pros/Cons&lt;/strong&gt;: This method is computationally inexpensive and ensures a tidy lineup. However, it lacks "common sense"—it cannot understand complex constraints like "do not stack heavy machine parts on top of fragile electronics" unless explicitly hard-coded.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  2. The Probabilistic Approach: Gemini 3 Pro Engine
&lt;/h3&gt;

&lt;p&gt;The second engine leverages the &lt;strong&gt;Spatial Reasoning&lt;/strong&gt; capabilities of Gemini 3 Pro. Instead of iterating through a fixed loop, the AI evaluates the entire manifest holistically.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Why Gemini 3?&lt;/strong&gt;: Previous models struggled with 3D coordinate mapping. Gemini 3 Pro shows a marked improvement in maintaining spatial relationships, allowing it to "visualize" the container interior.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Workflow&lt;/strong&gt;: The application prompts the model to act as a Senior Stowage Engineer.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Constraints&lt;/strong&gt;: The prompt enforces non-linear rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Stability&lt;/strong&gt;: Keep the Center of Gravity (COG) low.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Safety&lt;/strong&gt;: Heavier items must be placed at &lt;code&gt;y=0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Balance&lt;/strong&gt;: Lateral and longitudinal distribution for truck axles.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Implementation: Structured JSON Output
&lt;/h4&gt;

&lt;p&gt;To ensure the AI returns usable data, we utilize the &lt;code&gt;responseMimeType: "application/json"&lt;/code&gt; configuration in the Google GenAI SDK. This forces the model to adhere to a strict schema, returning a typed array of coordinates rather than conversational text.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// services/geminiService.ts snippet&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generateContent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gemini-3-pro-preview&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;responseMimeType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;responseSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OBJECT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;packedItems&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ARRAY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OBJECT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STRING&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
              &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NUMBER&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
              &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NUMBER&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
              &lt;span class="na"&gt;z&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NUMBER&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;x&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;y&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;z&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Safety &amp;amp; Physics Validation
&lt;/h4&gt;

&lt;p&gt;AI is probabilistic, but cargo safety must be deterministic. Therefore, the application includes a validation layer:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Boundary Clamping&lt;/strong&gt;: If the AI suggests a coordinate where an item clips through the wall ($x + width &amp;gt; container_width$), the system automatically clamps the item to the boundary.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;COG Calculation&lt;/strong&gt;: The app calculates the weighted average position of all items ($COG = \frac{\sum (m_i \times p_i)}{\sum m_i}$) and renders a red visual marker in the 3D view. This allows engineers to verify stability instantly.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Application Overview: Smart Stowage Optimizer
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Smart Stowage Optimizer&lt;/strong&gt; acts as a sandbox to simulate loading risks before physical operations begin.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Digital Twin Visualization&lt;/strong&gt;: Using &lt;code&gt;react-three-fiber&lt;/code&gt;, the scene renders a semi-transparent container with a grid floor. We use &lt;code&gt;InstancedMesh&lt;/code&gt; for the cargo items, allowing the app to render hundreds of boxes with a single GPU draw call for high performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Physics-Aware Metrics&lt;/strong&gt;: The UI displays real-time volumetric efficiency (%) and total payload weight, changing colors to warn of overloading.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manifest Management&lt;/strong&gt;: Users can upload CSV files, manually add items, or use industry-standard presets (20ft/40ft ISO containers, EURO Trucks).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Comparative Analysis
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Algorithmic (Heuristic)&lt;/th&gt;
&lt;th&gt;Gemini AI Engine&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Speed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Instantaneous (&amp;lt;100ms)&lt;/td&gt;
&lt;td&gt;3-8 seconds (Inference)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Logic&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Deterministic (Fixed Rules)&lt;/td&gt;
&lt;td&gt;Probabilistic (Reasoning)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Stability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Basic Height-based layers&lt;/td&gt;
&lt;td&gt;Advanced COG awareness&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Flexibility&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Rigid packing patterns&lt;/td&gt;
&lt;td&gt;Adapts to unique constraints&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best For&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Uniform pallets, high speed&lt;/td&gt;
&lt;td&gt;Complex manifests, fragile items&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Installation and Usage
&lt;/h2&gt;

&lt;p&gt;To run the application locally:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Clone the repository:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/tanaikech/Smart-Stowage-Optimizer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Install dependencies:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Configure API Key:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Set your Gemini API key as an environment variable &lt;code&gt;GEMINI_API_KEY&lt;/code&gt; in a &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Start the server:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Workflow
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Define Space&lt;/strong&gt;: Select a preset (e.g., "EURO_TRUCK") or define custom dimensions (W/H/L).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Build Manifest&lt;/strong&gt;: Upload a CSV or use the "Sample" button to populate test cargo (generators, drums, electronics).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Select Engine&lt;/strong&gt;: Choose &lt;strong&gt;Gemini AI&lt;/strong&gt; for stability-focused packing or &lt;strong&gt;Algorithmic&lt;/strong&gt; for speed.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Analyze&lt;/strong&gt;: Rotate the 3D view. Check the red COG marker to ensure it is centered and low.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Export&lt;/strong&gt;: Download the generated coordinates as a CSV report for the loading crew.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Testing and Demonstration
&lt;/h2&gt;

&lt;p&gt;The following demonstration highlights the difference between the engines. Note how the Algorithmic engine packs tightly but may ignore weight distribution. In contrast, the Gemini engine intelligently places heavier items (blue/green generators) at the bottom and lighter items (orange electronics) on top to lower the Center of Gravity.&lt;/p&gt;

&lt;p&gt;

  &lt;iframe src="https://www.youtube.com/embed/5yVJ_uyzKHQ"&gt;
  &lt;/iframe&gt;


&lt;/p&gt;

&lt;p&gt;The exported CSV data generated by Gemini is structured as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ID,Name,Width,Height,Length,Weight,X,Y,Z
BASE-1,Generator 1,1.2,1,2,2500,0,0,0
BASE-2,Generator 2,1.2,1,2,2500,0,0,2
PAL-1,Heavy Spares,1,0.8,1.2,1200,1.35,0,0
PAL-2,Heavy Spares,1,0.8,1.2,1200,1.35,0,1.2
BOX-A1,Electronics,0.6,0.6,0.8,150,0,1,0
BOX-A2,Electronics,0.6,0.6,0.8,150,0.6,1,0
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;By integrating &lt;strong&gt;Gemini 3 Pro&lt;/strong&gt;, we have moved beyond simple script-based calculators to a fully interactive &lt;strong&gt;Digital Twin&lt;/strong&gt;. While traditional algorithms are faster for uniform shapes, Gemini demonstrates a unique ability to understand "soft" constraints—such as stability and stackability—that are difficult to program explicitly. This hybrid approach represents the future of logistics software: combining the speed of heuristics with the reasoning of Artificial Intelligence.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hybrid Architecture&lt;/strong&gt;: Successfully combines deterministic Heuristics with probabilistic AI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gemini 3 Capability&lt;/strong&gt;: Confirms that Gemini 3 Pro handles complex spatial reasoning and 3D coordinate mapping significantly better than previous iterations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Visualization Impact&lt;/strong&gt;: React 19 and Three.js transform abstract data into visual insights, allowing for immediate safety verification.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Physics Integration&lt;/strong&gt;: Real-time Center of Gravity (COG) calculations ensure that AI-generated plans adhere to physical safety standards.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>gemini</category>
      <category>react</category>
      <category>ai</category>
      <category>node</category>
    </item>
    <item>
      <title>Bringing A2UI to Google Workspace with Gemini</title>
      <dc:creator>Tanaike</dc:creator>
      <pubDate>Mon, 19 Jan 2026 05:54:51 +0000</pubDate>
      <link>https://forem.com/gde/bringing-a2ui-to-google-workspace-with-gemini-4m24</link>
      <guid>https://forem.com/gde/bringing-a2ui-to-google-workspace-with-gemini-4m24</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmrp5nfgqzuggxtat755p.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmrp5nfgqzuggxtat755p.jpg" alt="fig1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Abstract
&lt;/h2&gt;

&lt;p&gt;This article explores implementing the Agent-to-User Interface (A2UI) protocol within Google Apps Script. It demonstrates utilizing Gemini's structured output to render secure, dynamic, server-driven UIs—like booking forms and event lists—directly inside Google Sheets, streamlining workflows without complex external infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;I recently published a sample implementation demonstrating how to bring the Agent-to-User Interface (A2UI) concepts to Google Apps Script (GAS). &lt;a href="https://medium.com/google-cloud/a2ui-for-google-apps-script-bcd0f37a3774" rel="noopener noreferrer"&gt;Ref&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A2UI is an emerging open-standard protocol designed to enable AI agents to generate rich, interactive user interfaces that render natively across web, mobile, and desktop environments. &lt;a href="https://developers.googleblog.com/introducing-a2ui-an-open-project-for-agent-driven-interfaces/" rel="noopener noreferrer"&gt;Ref&lt;/a&gt; Unlike traditional approaches that often require executing arbitrary, high-risk code to generate UI on the fly, A2UI leverages a strict schema-based data format to describe UI components. This "secure-by-design" architecture effectively mitigates security risks like Cross-Site Scripting (XSS) while ensuring high performance and cross-platform consistency.&lt;/p&gt;

&lt;p&gt;Integrating A2UI into the Google Workspace ecosystem represents a paradigm shift in user experience. It allows Large Language Model (LLM) driven agents to evolve beyond simple text-based chat. Instead, they provide dynamic, actionable components—such as forms, interactive charts, and data grids—directly within the user's workflow. In this article, I present a demonstration of A2UI functioning within Google Sheets, illustrating how AI agents can orchestrate complex, data-driven tasks through a native, structured interface.&lt;/p&gt;

&lt;h2&gt;
  
  
  Repository
&lt;/h2&gt;

&lt;p&gt;The complete source code and documentation are available in the GitHub repository below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/tanaikech/A2UI-for-Google-Apps-Script" rel="noopener noreferrer"&gt;https://github.com/tanaikech/A2UI-for-Google-Apps-Script&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  System Architecture and Workflow
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftanaikech.github.io%2Fimage-storage%2F20260119a%2Ffig2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftanaikech.github.io%2Fimage-storage%2F20260119a%2Ffig2.png" alt="fig2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://mermaidchart.com/play?utm_source=mermaid_live_editor&amp;amp;utm_medium=share#pako:eNptk1tP20AQhf_KaJ-CGlxjQi77gJQmkBjRiwh5qSxViz0x29q77l5o0ij_vbNxQkHgF3t3vznnzNjeslwXyDiz-NujynEqRWlEnSmgS3inla8f0LTrRhgnc9kI5WAJwsLSvnc0D0fz-8-3QGqVLqEzTpbpyVtwFsDZeAGfRP4LVfGWGKd7BGupJIy_pW-JaQCmwgnoLB4Rnf04ERVpCUOGLb48vbycc0hV4x1Qm2YDHYzKqAsZu5aqAIPWCW9IzmbskHNORTMOpdZlhZHNjWxcZLyKGqNztDa0fheGZl3nUDKjknHKYUH2B58PcK91BVNcUQNOamVbdJy28nfovFFw7VUeToGyV8dwJbofL5K9MJlyuFpj7h1CETo36IzEJ1G1yPT0lbgRf_bYOyFdCEcevnIWVtrAMiVbhUaENM9RX8lNtHpCY_eEqOAe147aDG8YbhZfvxxd2pkfI6BtqHcE_fATc_d_woTcLOBKlVIhUaog5VZromsqwfBKDjThS06flG0qsYFio0Qt85C4MxGmsF24ldbRDV0enYQSYF1WGlkw7ozHLqvR1CIs2TZoZsw9Yo0Z4_RY4ErQFDKWqR2V0af1Xev6WGm0Lx8ZX4nK0so3NM7jn_K826afaK8c40nS34swvmVrxvvDKB4NzuNkmPTP-kmvyzaMn_VodzDqxXES90f9YW_XZX_3pnE0HPRGdPXi89HF-cVFsvsH5c4oIA" rel="noopener noreferrer"&gt;Mermaid Chart Playground&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The implementation of A2UI within Google Sheets follows a highly optimized lifecycle to ensure a smooth, agent-driven user experience.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;User Input:&lt;/strong&gt; The process begins in the Google Spreadsheet dialog where a user enters a natural language request, such as "Find 3 Chinese restaurants in New York."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Request Transmission:&lt;/strong&gt; The HTML interface captures this input and sends it to the GAS backend. This is handled via the &lt;code&gt;google.script.run&lt;/code&gt; API, which creates a direct and secure bridge between the user interface and the server logic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Intent Routing:&lt;/strong&gt; The GAS backend forwards the request to the Gemini API. Using a specialized System Prompt, Gemini acts as a "Router" to determine which sub-application (e.g., Restaurant Finder or Event Manager) is best suited to handle the request.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tool Execution:&lt;/strong&gt; Once the sub-application is selected, GAS executes local functions to interact with your data. This may involve searching the current spreadsheet, fetching files from Google Drive, or checking Google Calendar availability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A2UI JSON Generation:&lt;/strong&gt; The data retrieved from the tools is sent back to Gemini. Gemini then generates a structured response that includes both conversational text and a JSON object strictly following the A2UI (Agent-to-User Interface) schema.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client-Side Rendering:&lt;/strong&gt; The GAS backend returns this payload to the HTML dialog. A dedicated JavaScript rendering engine within the dialog parses the A2UI JSON and dynamically builds high-quality UI components like interactive cards, lists with images, and booking forms.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Native Integration:&lt;/strong&gt; Unlike standard A2UI implementations that often rely on the A2A (Agent-to-Agent) protocol over HTTP, this GAS-optimized architecture eliminates external network overhead. By using the internal Google infrastructure, it provides a significantly faster response time for users.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Architectural Comparison: Distributed vs. Integrated
&lt;/h2&gt;

&lt;p&gt;The official A2UI is designed as a "distributed" system for cross-platform interoperability. In contrast, the GAS-native version is an "integrated" system optimized specifically for the Google infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Official A2UI Workflow (via A2A Protocol)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Process:&lt;/strong&gt; The Frontend requests data from an A2A Server (e.g., Node.js/Python). The Server handles auth/protocol logic and requests JSON from the Gemini API. The generated JSON travels back through the server to the Frontend for rendering.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Challenge:&lt;/strong&gt; Multiple network hops across the internet introduce latency and overhead.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;GAS Native Workflow (via google.script.run)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Process:&lt;/strong&gt; The Frontend (HTML) directly calls a GAS Backend function using &lt;code&gt;google.script.run&lt;/code&gt;. The GAS Backend communicates with the Gemini API using &lt;code&gt;UrlFetchApp&lt;/code&gt; to get the UI JSON. The script returns the object directly to the client for immediate rendering.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Innovation:&lt;/strong&gt; By using &lt;code&gt;google.script.run&lt;/code&gt;, the entire communication happens within Google's internal high-speed network. There is no need for an external A2A server, eliminating external network overhead.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Analysis: Pros and Cons of GAS-based A2UI
&lt;/h2&gt;

&lt;p&gt;Why should users choose the GAS-native approach for their AI applications?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero Setup Cost &amp;amp; Rapid Development:&lt;/strong&gt; No servers to manage. Backend, frontend, and AI integration all live in a single GAS project.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Seamless Google Integration:&lt;/strong&gt; It is incredibly easy to let the AI perform "real-world actions," such as using Google Sheets as a database or managing Google Calendar events.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High Performance:&lt;/strong&gt; Bypassing an external proxy server via &lt;code&gt;google.script.run&lt;/code&gt; ensures a snappier, more responsive user experience.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Manual Rendering Logic:&lt;/strong&gt; While the official version provides out-of-the-box UI components, the GAS version requires you to maintain the logic that converts JSON to HTML elements (the &lt;code&gt;renderComponent&lt;/code&gt; code).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execution Quotas:&lt;/strong&gt; GAS has specific limits, such as a 6-minute execution timeout and daily triggers, which may not suit high-scale enterprise apps.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Application Setup
&lt;/h2&gt;

&lt;p&gt;To deploy this application in your own environment, please follow the steps below.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Obtain an API Key&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You will need a valid Gemini API Key to communicate with the LLM.&lt;br&gt;
&lt;a href="https://ai.google.dev/gemini-api/docs/api-key" rel="noopener noreferrer"&gt;Get one here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Copy the Sample Script&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can copy the Google Spreadsheet containing the necessary Google Apps Script using the link below.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://docs.google.com/spreadsheets/d/1NdgN5e2l7-CTw-NTaP50Ta75l8Zbr93ATMyUOlZk1BY/copy" rel="noopener noreferrer"&gt;https://docs.google.com/spreadsheets/d/1NdgN5e2l7-CTw-NTaP50Ta75l8Zbr93ATMyUOlZk1BY/copy&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After copying the Google Spreadsheet:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the script editor (Extensions &amp;gt; Apps Script).&lt;/li&gt;
&lt;li&gt;Locate the &lt;code&gt;main.gs&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;Set your API key in the &lt;code&gt;apiKey&lt;/code&gt; variable.&lt;/li&gt;
&lt;li&gt;Save the script.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Alternatively, you can visit the &lt;a href="https://github.com/tanaikech/A2UI-for-Google-Apps-Script/tree/master/samples/A2UI-Google-Sheets" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt; to manually copy the source codes.&lt;/p&gt;
&lt;h2&gt;
  
  
  Demonstration and Testing
&lt;/h2&gt;

&lt;p&gt;Once the script is set up, re-open the Google Spreadsheet (or refresh the page). You will see a table on the "data" sheet, which acts as the source for the event demonstration.&lt;/p&gt;

&lt;p&gt;A custom menu labeled "sample" will appear in the toolbar. Select &lt;strong&gt;sample &amp;gt; run&lt;/strong&gt; to open the A2UI dialog.&lt;/p&gt;

&lt;p&gt;

  &lt;iframe src="https://www.youtube.com/embed/aSetL-QF2I0"&gt;
  &lt;/iframe&gt;


&lt;/p&gt;

&lt;p&gt;In this demonstration, you can test the following two prompts:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. "Find 3 Chinese restaurants in New York"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This prompt replicates the official A2UI demonstration. It tests the system's ability to retrieve mock data, render a list of restaurants with images, and present a booking form.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. "Show me events for Jan 17-20"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This prompt demonstrates a custom integration with Google Workspace. The agent searches the spreadsheet for events within the specified date range and presents them as a selectable list. Upon confirmation, the agent triggers a function to register the selected events directly to your Google Calendar.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;This project confirms that the A2UI protocol can be effectively implemented within the Google Apps Script environment.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Serverless Architecture:&lt;/strong&gt; A2UI can be deployed using only GAS and Google Sheets, eliminating the need for external web servers or hosting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deep Workspace Integration:&lt;/strong&gt; The system seamlessly connects Generative AI with Workspace tools, allowing actions like reading Sheets and writing to Calendar.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced Security:&lt;/strong&gt; By adhering to A2UI's schema-driven rendering, the application avoids the high risks associated with generating and executing arbitrary HTML/JS code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic User Experience:&lt;/strong&gt; Users receive interactive, app-like interfaces (forms, buttons, lists) directly within a chat dialog, vastly improving usability over plain text.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability to other Apps:&lt;/strong&gt; This approach is not limited to Sheets; it can be readily adapted for Google Docs, Slides, and other Workspace applications to create a unified AI interface.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>gemini</category>
      <category>googleworkspace</category>
      <category>googleappsscript</category>
      <category>a2ui</category>
    </item>
  </channel>
</rss>
