<?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: Google Developer Experts</title>
    <description>The latest articles on Forem by Google Developer Experts (@gde).</description>
    <link>https://forem.com/gde</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%2Forganization%2Fprofile_image%2F11939%2Fe3080d5b-ecde-42a8-b089-bafecc31fa97.png</url>
      <title>Forem: Google Developer Experts</title>
      <link>https://forem.com/gde</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/gde"/>
    <language>en</language>
    <item>
      <title>Agent Development Kit for Google Apps Script</title>
      <dc:creator>Tanaike</dc:creator>
      <pubDate>Mon, 18 May 2026 08:50:37 +0000</pubDate>
      <link>https://forem.com/gde/agent-development-kit-for-google-apps-script-38ho</link>
      <guid>https://forem.com/gde/agent-development-kit-for-google-apps-script-38ho</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%2Fntqmqtqeyu44k43v504o.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%2Fntqmqtqeyu44k43v504o.jpg" alt="Infographics" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Google's Agent Development Kit (ADK) revolutionizes autonomous AI agents, yet its standard Node.js-based asynchronous ReAct architecture is fundamentally incompatible with the restrictive, synchronous, and time-bound execution environment of Google Apps Script (GAS). To unlock enterprise-grade AI natively within Google Workspace, this paper introduces GASADK. By abandoning the cyclical ReAct loop in favor of a deterministic Planner-Executor-Synthesizer (PES) architecture, GASADK proactively manages execution constraints, synchronous network blocking, and payload limits. This framework successfully implements multi-agent orchestration, the Model Context Protocol (MCP), and Agent-to-Agent (A2A) communication directly within GAS, empowering developers to build highly resilient, serverless AI workflows that seamlessly manipulate Workspace applications.&lt;/p&gt;

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

&lt;p&gt;Google's released Agent Development Kit (ADK) fundamentally transforms how developers architect and deploy robust, autonomous AI agents. &lt;a href="https://docs.cloud.google.com/gemini-enterprise-agent-platform/build/ad?utm_campaign=deveco_gdemembers&amp;amp;utm_source=deveco" rel="noopener noreferrer"&gt;Ref&lt;/a&gt; At its current stage, the official ADK ecosystem supports primary backend languages such as Python, TypeScript, Go, and Java. Among these, the &lt;a href="https://github.com/google/adk-js" rel="noopener noreferrer"&gt;Agent Development Kit (ADK) for TypeScript (adk-js)&lt;/a&gt; stands out for its elegant, modular approach to managing Generative AI interactions, autonomous agent routing, Agent Skills, and Function Calling. However, there remains a significant frontier for enterprise productivity: Google Apps Script (GAS). Because GAS acts as the native connective tissue of Google Workspace—seamlessly orchestrating Gmail, Sheets, Docs, and Drive—bringing the paradigm of the TypeScript ADK directly into the GAS ecosystem unlocks unprecedented potential. It allows us to evolve traditional, static automation scripts into dynamic, context-aware Workspace agents.&lt;/p&gt;

&lt;p&gt;Yet, attempting to port the TypeScript ADK's architecture directly to Google Apps Script is an exercise in futility. The Node.js environment assumes asynchronous I/O (&lt;code&gt;Promise.all&lt;/code&gt;), unbounded execution times, persistent memory, and standardized WebSocket/stdio channels for external communication. GAS, conversely, is a highly restrictive, ephemeral execution environment. It enforces a strict, unyielding 6-minute maximum execution time limit. Its networking via &lt;code&gt;UrlFetchApp&lt;/code&gt; is purely synchronous and thread-blocking. Standard input/output streams are nonexistent, and the internal specifications of GAS Web Apps function as opaque black boxes. In this hostile environment, the TypeScript ADK’s reliance on continuous, unbounded ReAct (Reason + Act) loops and asynchronous tool discovery will inevitably trigger catastrophic API quota exhaustion, context window payload bloat, and system timeout kills.&lt;/p&gt;

&lt;p&gt;To engineer a true enterprise-grade agent framework for GAS, a fundamental architectural shift was required—one that discards the optimistic assumptions of standard Node.js environments. While the &lt;code&gt;@google/adk&lt;/code&gt; LlmAgent utilizes a recursive, step-by-step execution model where tool discovery, LLM interaction, and execution happen in a continuous feedback loop, the GAS environment demands a "survival architecture." I deliberately adapted the declarative agent structures of &lt;code&gt;adk-js&lt;/code&gt; but replaced its execution engine with a deterministic, phase-separated orchestration model: the Planner-Executor-Synthesizer (PES). Instead of deciding actions on the fly, the GASADK LLM Planner evaluates capabilities and generates a complete Directed Acyclic Graph (DAG) of required tasks upfront. It enforces a "One-Pass Fast-Track" to bypass redundant executions entirely, injects explicit temporal context anchoring to cure LLM time-blindness, and executes tasks sequentially to respect synchronous blocking. Furthermore, it implements pessimistic payload bulletproofing and dynamic Re-Planning to mathematically prevent the dreaded &lt;code&gt;400 Payload Too Large&lt;/code&gt; errors and 6-minute timeout deaths.&lt;/p&gt;

&lt;p&gt;Fortunately, the essential building blocks for this specialized workflow were already in place. Over the course of exploring advanced Generative AI capabilities, standardizing tool-use via the Model Context Protocol (MCP), facilitating distributed problem-solving through A2A networking, and designing sophisticated Agent Skills specifically for the GAS runtime, I previously developed and published the following foundational libraries and guides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/tanaikech/GeminiWithFiles" rel="noopener noreferrer"&gt;GitHub: GeminiWithFiles&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/tanaikech/MCPApp" rel="noopener noreferrer"&gt;GitHub: MCPApp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/tanaikech/MCPA2Aserver-GAS-Library" rel="noopener noreferrer"&gt;GitHub: MCPA2Aserver-GAS-Library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/tanaikech/A2AApp" rel="noopener noreferrer"&gt;GitHub: A2AApp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/tanaikech/FileSearchApp" rel="noopener noreferrer"&gt;GitHub: FileSearchApp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/google-cloud/a-developers-guide-to-understanding-agent-skills-7cb8d3d2ce91" rel="noopener noreferrer"&gt;Medium: A Developer’s Guide to Understanding Agent Skills&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By synthesizing these discrete resources—combining the advanced multi-modal handling of GeminiWithFiles, the standardized external tool integration of MCPApp, and the collaborative multi-agent routing of A2AApp—we construct a highly capable, unified Agent Development Kit natively tailored for Google Apps Script. This unified framework mirrors the best practices of the &lt;a href="https://github.com/google/adk-js" rel="noopener noreferrer"&gt;TypeScript ADK&lt;/a&gt;, fundamentally translating its robust orchestration of generative models, function calling, and MCP-based data retrieval into a native GAS experience capable of surviving its harsh execution limits. In this article, I will introduce this newly forged "ADK for GAS" (GASADK). I will walk you through its architectural divergence from the standard ADK, provide detailed configuration and usage guides, and showcase its capabilities through hands-on Quick Starts and advanced Practical Multi-Agent Applications directly within your Google Workspace environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Repository
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/tanaikech/adk-gas" rel="noopener noreferrer"&gt;https://github.com/tanaikech/adk-gas&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Significance &amp;amp; Future of GASADK in Google Workspace
&lt;/h2&gt;

&lt;p&gt;To appreciate the paradigm shift GASADK brings to Google Workspace, one must first examine the deep architectural chasm between standard Node.js agent frameworks and the hostile execution environment of Google Apps Script.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The TypeScript ADK Workflow: Optimistic Cyclical ReAct
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;@google/adk&lt;/code&gt; &lt;code&gt;LlmAgent&lt;/code&gt; operates on an idealized, cyclical ReAct (Reason + Act) loop, fundamentally relying on the luxuries of the Node.js V8 runtime—specifically, asynchronous event loops (&lt;code&gt;Promise.all&lt;/code&gt;), persistent memory, and essentially unbounded execution timeouts.&lt;/p&gt;

&lt;p&gt;Its workflow is highly recursive:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic Pre-processing &amp;amp; Tool Discovery:&lt;/strong&gt; Upon receiving a prompt, the agent processes history, identity, and context. It dynamically scans for registered tools—fetching MCP server definitions via standard input/output (stdio) or HTTP, and resolving Agent-to-Agent (A2A) interfaces.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LLM Interaction (The Loop):&lt;/strong&gt; The agent passes the context and tools to the LLM.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execution &amp;amp; Interruption:&lt;/strong&gt; If the LLM requests a tool execution, the agent fires it asynchronously. In this phase, it can handle Human-in-the-Loop (HITL) events, pausing for authentication or confirmation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recursive Feedback:&lt;/strong&gt; The tool's output is appended to the session history, and the entire payload is fed &lt;em&gt;back&lt;/em&gt; into the LLM. The agent repeats this loop indefinitely until the LLM decides no further tools are needed and formulates a final text response.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;The Flaw in GAS:&lt;/strong&gt; This optimistic architecture is fatal in Google Apps Script. GAS enforces a hard, unyielding 6-minute kill switch. Its &lt;code&gt;UrlFetchApp&lt;/code&gt; networking is strictly synchronous and thread-blocking. A continuous ReAct loop that blindly iterates and accumulates massive context history will inevitably trigger either API rate limits, a &lt;code&gt;400 Payload Too Large&lt;/code&gt; error, or a violent system timeout, leaving the user with a dead script and zero output.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The GASADK Workflow: Deterministic Planner-Executor-Synthesizer (PES)
&lt;/h3&gt;

&lt;p&gt;GASADK abandons the optimistic ReAct loop in favor of a pessimistic, phase-separated survival architecture. It assumes failure is imminent and aggressively manages state, time, and payload size.&lt;/p&gt;

&lt;p&gt;Its workflow is deterministic and linear:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pre-fetch &amp;amp; Temporal Anchoring:&lt;/strong&gt; GASADK executes a synchronous, one-time fetch of all MCP schemas, A2A Agent Cards, and Drive-based Agent Skills. Crucially, it injects an absolute system time anchor (&lt;code&gt;new Date()&lt;/code&gt;) directly into the global instruction. This instantly cures the LLM of "temporal blindness," eliminating the need for the agent to waste execution cycles trying to calculate what "tomorrow" means.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Planner Phase (DAG Generation):&lt;/strong&gt; Instead of deciding step-by-step, the LLM is forced via JSON Schema to architect an entire execution strategy upfront. It outputs a Directed Acyclic Graph (DAG) of required tasks, complete with defined dependencies (&lt;code&gt;depends_on&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One-Pass Fast-Track &amp;amp; Interception:&lt;/strong&gt; If the Planner determines no external tools are required, GASADK intercepts the routing. It bypasses execution entirely and delivers the answer directly, slashing latency by 80%. If a strict &lt;code&gt;outputSchema&lt;/code&gt; is demanded by the developer, GASADK overrides the bypass, forcing the raw data through the Synthesizer to mathematically guarantee JSON compliance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adaptive Execution &amp;amp; Payload Bulletproofing:&lt;/strong&gt; The DAG is executed strictly sequentially, respecting GAS's synchronous networking constraints to prevent quota burnout. When an external server returns a massive JSON or HTML dump, GASADK's &lt;em&gt;Payload Bulletproofing&lt;/em&gt; violently truncates the string at &lt;code&gt;maxResultLength&lt;/code&gt; (default 20,000 characters). It sacrifices trailing data to guarantee the agent survives the next LLM call without triggering a 400 error.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic Re-planning &amp;amp; Safe Abort:&lt;/strong&gt; If a DAG node fails, GASADK does not infinite-loop. It scraps the remaining queue and executes a highly targeted Re-Plan to bypass the error. Simultaneously, a built-in chronometer monitors execution time. If the script approaches 280 seconds (&lt;code&gt;timeoutMs&lt;/code&gt;), it triggers a Safe Abort, abandons the queue, and forces the gathered data into the Synthesis phase before the 6-minute GAS guillotine drops.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Final Synthesis:&lt;/strong&gt; A final LLM call analyzes the aggregated, bulletproofed data and synthesizes a comprehensive response for the user.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  3. Comparative Evaluation: Engineering for Hostility
&lt;/h3&gt;

&lt;p&gt;When evaluated side-by-side, the TypeScript ADK is a framework built for exploration, whereas GASADK is an engine built for extraction under extreme duress.&lt;/p&gt;

&lt;p&gt;The cyclical ReAct model of the TS ADK is theoretically superior for highly ambiguous, open-ended research tasks where the agent must "think out loud" over many minutes. However, in an enterprise Workspace environment, speed, reliability, and deterministic output are paramount. By compartmentalizing the cognitive load into a Planner (architect), an Executor (worker), and a Synthesizer (reporter), GASADK drastically reduces token consumption, network latency, and the probability of context collapse.&lt;/p&gt;

&lt;p&gt;GASADK proves that you do not need an asynchronous backend to run elite-level autonomous agents; you simply need an architecture that respects and manipulates the physical physics of the runtime environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Redefining Enterprise Automation
&lt;/h3&gt;

&lt;p&gt;Google Workspace provides an incredible suite of productivity tools, but internal automations have traditionally relied on rigid, rule-based scripting. If a cell value changes, send an email. If a form is submitted, generate a document. While undeniably useful, these traditional macros lack the cognitive flexibility to handle ambiguity, context-shifting, or complex decision-making.&lt;/p&gt;

&lt;p&gt;GASADK bridges this crucial gap by injecting true agentic workflows directly into the Workspace ecosystem, leveraging the architectural triumphs of its DAG-based execution model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Native Context &amp;amp; Zero-Server Deployment&lt;/strong&gt;: Agents built with GASADK natively understand and interact with the Google environment. They can read emails, query spreadsheets, and modify Drive files without requiring complex OAuth flows, external hosting, or dedicated backend servers. The infrastructure overhead is zero.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Standardized Extensibility via MCP&lt;/strong&gt;: Through the robust integration of the Model Context Protocol, GAS agents are no longer confined to Google services. The Planner can seamlessly route requests to external enterprise databases, internal APIs, or SaaS platforms using a standardized protocol, effectively bridging the walled garden of Google Workspace with the broader enterprise stack.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability via Multi-Agent Swarms&lt;/strong&gt;: With Sub-Agents and A2A communication, developers can build a hierarchical swarm of specialized AI agents. A "Manager Agent" can evaluate a user request, generate a DAG, delegate data-gathering to a remote "Sheets A2A Server," and utilize a local Sub-Agent to synthesize the response. This distributed cognition handles complex workflows without bloating a single agent's context window.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Future-Proofing Enterprise Automation&lt;/strong&gt;: As enterprise workflows become increasingly multifaceted, the shift from deterministic "macros" to probabilistic, "autonomous agents" is inevitable. GASADK positions Google Apps Script developers at the absolute forefront of this transition. By porting world-class design patterns derived from Google's official ADK and retrofitting them to survive the GAS runtime, GASADK enables developers to build resilient, intelligent systems that dramatically reduce human toil and operational bottlenecks.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ⚙️ GASADK Workflow Architecture
&lt;/h2&gt;

&lt;p&gt;The execution lifecycle of &lt;code&gt;LlmAgent&lt;/code&gt; is rigorously compartmentalized. The diagram below details the exact chronological flow from the moment &lt;code&gt;agent.run()&lt;/code&gt; is invoked to the final synthesized response.&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%2Ftanaikech.github.io%2Fimage-storage%2F20260518a%2Ffig1b.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%2F20260518a%2Ffig1b.png" alt="GASADK Workflow Architecture" width="800" height="1184"&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:eNqdV21v2zYQ_iuEiq4JQKdO3Gax2mZw7STo0GSZ7X3Y6iGgpbPNRRZVkkrjBvnvO75IolxnwOIPBl_ujse7554TH6JEpBDF0VKyYkWmo1lO8PfyJZnoTcbzJRnBgudcc5Ert5dkTClcJaUCOYavZMGzLH6x6C-o0lLcQvyi1-v5cecbT_UqPiruaSIyIeMX3W733ZahREjwVubzZ1vJsnXlynz-XCNwr0HmLKvcWTzbUgoJVxi1yqdF_7mWFFvAsmQyrUwdH_8PU3VCrzDRPoUTzaTe-zKL_sAUxoQtIdcHssz3CinWhd6fRX_vO8lPmPohKxTKmiFnGf8OBFfYnGc4B_V-Lk_3pkJkipLL4TUlg6MBJZNbdFUZQ5WdfyDRU74Ga8lMyBTWhZAY66HINQbeWJpslIY1MYJkkCcrIWsT1xnLc5Co__nzZVxNyfWKKTCqF4BTpoGMBhfkJ_Lr5LcrMklWsGbWhDNyzpSeSpbcjiB5mEUSvpZcgroxBpKtW334QBYsU_DLLHr0cbPmnKoodVFqt2KkU1MnkDbCY9ClzEdoPrGxdnOS2oUblqtvII3i2T0kpakv8nFTYMohdeH3txbFlKlb1McRMUOywCSRAq__ewkl1PEZriC5NYFD584yzBmkLo6n5hSNI3T50uXr6KSr9htXp25zMBdS40lTyZdLDO0EgUfsok2NRgeaI8O8-gQ2qX2VQgF5qm5E_sroegGiBbm2EKu9Nrcf49kg0e0aVxujNN0UPvaNKCIMT8F_MgF5hz4OM47gbZlDAKIM_v-HjMWnkTLQd2glCCtEdpa1BK-Y5ncGtG5Azss8sckyksiPQSxsAs6kuUidU5tgKYUMgo2FliBOTUrZJhMsrZa8_ClZs_sxqDLTnyFf6lXt0ITdgdtAZTMxAdWICbeofnAGI71Bd2qwWHfMYuOOFRyDEbEFYQZDUWJU3htp64pZU43KSIrCmkMvRlwlhprGWAbYJ0zDGFzUDjvVoGpHm5yteYIbHV_A5pDBneAp1ibPELOXoFciDa4y2eR6Zcu8snLODUXbdVDcQnqAKxukpguGaxLNjJhmTSbzNChBpz6wFRjWGkLmZgxLjoS6-bLnIDQoilm0780g7m4cppTZb2CoGpmLkTSAwe0LIZYZ0pGZu_2ai8_SZYuLSadzWnNtm3lJ54DMonPQyYo4tA4x3nggOUCd0OVdetoQ8-sM9zHkX0tQ2isGV9mlNwaE5cE69UTuldzdmtqvNKzzFcHbqU9ui7ntRkjAu0gZhfD4P0GRPbPcsevYR6xyzb9bdOyUrgTZG7NvxDEzMXRcKYZcvFPXHvgJSUomYBugO69G3tOumlPDfkh8T0krI57BtwjdbtWUvcXgzrJnZaShBCA1bcEqhWT9I30_4feWacPs3lyLwXeQuhVqWDokY7fiLDa14O16tt4t3ZBzII2LT0g3JB2Iu_lOBcfVrz-WPNMdngdKbmerozS5QKpu9ZEndly_2L3n-0R7s90gfA7KJAGlqqz6ruDyV_P8Nu8Hdg2Nb3N9Bclt6O2SQsg_CfO2p46YvXDQL35oIEEtDXHmFqs6qLuGr8gipIh6-oTfoX1TcZfs3uuouliDoG03Dpf_PA0oeKAUX2IbN1_ZED5tHCPTkDIoqlbPnfDrvKZA2tAf9c7TVhXRBho0yKZ5-bQMeqqkNcpoHRkaXAffOi01D2TqYUvDtkADqqeOwetnTstIyG205kdaUwdtyoxWAKENqmiYqOr10zog5ClaAZ42uKgfOu8iig9SnkaxliXQaA0Svy5wGj0Ye9jW0DkksBiHKZO3s2iWP6JOwfK_hFhXalKUy1UU2494GpVFiseNOMOnbiOCX6kg7fdOFB_1rYkofojuo7h3dHhwfPKm3z857HW7_cMejTZRfNw_OPn5Tf_4Tbfbe3vy9rD3SKPv9swubrx9_BfcRwV6" rel="noopener noreferrer"&gt;Mermaid Chart Playground&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation &amp;amp; Usage
&lt;/h2&gt;

&lt;p&gt;GASADK relies on a complex interplay of internal dependencies (&lt;code&gt;GeminiWithFiles&lt;/code&gt;, &lt;code&gt;A2AApp&lt;/code&gt;, &lt;code&gt;MCPApp&lt;/code&gt;, etc.). You can integrate it into your Google Apps Script project using one of two methods: binding it as a GAS Library (the strictly recommended path for version control) or injecting the consolidated source directly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 1: Use as a GAS Library (Recommended)
&lt;/h3&gt;

&lt;p&gt;This is the only maintainable approach for enterprise deployments, ensuring your orchestration architecture receives upstream patches without manual intervention.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open your Google Apps Script project editor.&lt;/li&gt;
&lt;li&gt;On the left panel, click the &lt;strong&gt;"+"&lt;/strong&gt; icon next to &lt;strong&gt;Libraries&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;In the "Script ID" field, enter the official Project Key: &lt;code&gt;1w2mwhWQd4_6rom-UBRPD8gayBoqGH_87awSBVqGI8DdaQI_pOeSuGYDu&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Look up&lt;/strong&gt;. Select the latest version from the dropdown, and ensure the identifier is strictly set to &lt;code&gt;GASADK&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Add&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After GASADK was installed, you can use it as follows.&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;const&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;MCPA2Aserver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FileSearch&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;GASADK&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;All objects are the class objects.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can also directly use &lt;code&gt;GeminiWithFiles&lt;/code&gt;, &lt;code&gt;A2AApp&lt;/code&gt;, and &lt;code&gt;MCPApp&lt;/code&gt; like &lt;code&gt;const { LlmAgent, GeminiWithFiles, MCPA2Aserver, FileSearch, GeminiWithFiles, A2AApp, MCPApp } = GASADK&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 2: Direct Source Injection
&lt;/h3&gt;

&lt;p&gt;If organizational security policies block external GAS libraries, do not attempt to copy the framework file by file. Use the compiled distribution script.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to the compiled release file in the repository: &lt;a href="https://github.com/tanaikech/adk-gas/blob/master/dist/GASADK.js" rel="noopener noreferrer"&gt;dist/GASADK.js&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Copy the entire contents.&lt;/li&gt;
&lt;li&gt;Create a new script file in your GAS project (e.g., &lt;code&gt;GASADK.gs&lt;/code&gt;) and paste the code. This single file contains all required dependencies and classes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In this case, you can directly use the class objects. So, you are not required to set &lt;code&gt;const { LlmAgent, GeminiWithFiles, MCPA2Aserver, FileSearch, GeminiWithFiles, A2AApp, MCPApp } = GASADK&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Minimal Quickstart
&lt;/h2&gt;

&lt;p&gt;The following script demonstrates the absolute minimum boilerplate required to safely initialize and execute the orchestrator. &lt;strong&gt;Note:&lt;/strong&gt; You must define your Gemini API key in the Script Properties (&lt;code&gt;File &amp;gt; Project Properties &amp;gt; Script Properties&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="c1"&gt;// Omit this destructuring line ONLY if you injected the dist/GASADK.js file directly.&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;LlmAgent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;GASADK&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;test_quickstart&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;properties&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;API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;properties&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GEMINI_API_KEY&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;API_KEY&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GEMINI_API_KEY is missing in Script Properties.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// 1. Initialize the Orchestrator&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;agent&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;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;API_KEY&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;HelperAgent&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;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="c1"&gt;// Core routing model&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 highly efficient, deterministic AI assistant.&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;// 2. Bind Mandatory Services (CRITICAL)&lt;/span&gt;
  &lt;span class="c1"&gt;// Without LockService, the agent will refuse to run to prevent state corruption.&lt;/span&gt;
  &lt;span class="nx"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setServices&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LockService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getScriptLock&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="nx"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// 3. Execute with Telemetry&lt;/span&gt;
  &lt;span class="c1"&gt;// The Fast-Track bypass will route this directly, skipping unnecessary execution loops.&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="nx"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello, who are you and what is your core directive?&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;logEntry&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="nx"&gt;logEntry&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;] &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;logEntry&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="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;Final Synthesized Response:&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;response&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;In the following script, the second argument receives the detailed real-time log as a callback function.&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;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello, who are you and what is your core directive?&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;logEntry&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="nx"&gt;logEntry&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;] &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;logEntry&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  LlmAgent Configuration (config)
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;new LlmAgent(config)&lt;/code&gt; constructor dictates the cognitive boundaries and physical survival parameters of the agent. The configuration object must be aggressively tuned to your specific deployment environment.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Required&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;apiKey&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Your Gemini API Key. The agent will fatal-crash upon instantiation without this.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;The internal system designation of the agent. Defaults to &lt;code&gt;"Agent"&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;description&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Defines the agent's capability profile. Essential for A2A and Sub-Agent routing so parent orchestrators know &lt;em&gt;when&lt;/em&gt; to delegate to this instance.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;model&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;The specific Gemini LLM endpoint. Defaults to &lt;code&gt;"models/gemini-3-flash-preview"&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;instruction&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;String/Object&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Global system instruction. Supports dynamic string interpolation (e.g., &lt;code&gt;{userName}&lt;/code&gt;).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;state&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Object&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Key-value mapping for dynamic state variables. Replaces the &lt;code&gt;{var_name}&lt;/code&gt; placeholders within the &lt;code&gt;instruction&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tools&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Array&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Array of native GAS functions mapped as callable AI tools via Function Calling schemas.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mcpServers&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Array&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Array of external MCP Server URLs. The agent will autonomously fetch &lt;code&gt;tools/list&lt;/code&gt; on initialization.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;a2aServerAgentCardURLs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Array&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Array of remote Agent Card URLs. Converts other autonomous agents on the network into local tools.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;subAgents&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Array&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Array of child &lt;code&gt;LlmAgent&lt;/code&gt; instances for local, hierarchical task delegation.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;skillFolderId&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Google Drive Folder ID containing &lt;code&gt;.md&lt;/code&gt; files that act as distributed, RAG-like Agent Skills.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;codeExecutor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Object&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Enables the model's Built-in Python execution engine for deterministic math and logic operations.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;googleSearch&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Object&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Configuration object to enable the Built-in Google Search grounding capability.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;generateContentConfig&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Object&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Gemini SDK parameters for the final synthesis (e.g., &lt;code&gt;temperature&lt;/code&gt;, &lt;code&gt;topK&lt;/code&gt;, &lt;code&gt;topP&lt;/code&gt;).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputSchema&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Object&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Strict JSON Schema declaration. Forces the Synthesizer to format the output as JSON, overriding Fast-Track bypasses.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxReplans&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Safeguard:&lt;/strong&gt; Maximum dynamic Re-Plan attempts on DAG execution failure. Defaults to &lt;code&gt;2&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;timeoutMs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Safeguard:&lt;/strong&gt; Milliseconds before triggering a forced queue abort to evade the GAS 6-minute kill switch. Defaults to &lt;code&gt;280000&lt;/code&gt; (280 seconds).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxResultLength&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Safeguard:&lt;/strong&gt; Truncation threshold for raw tool output. Prevents catastrophic &lt;code&gt;400 Payload Too Large&lt;/code&gt; crashes. Defaults to &lt;code&gt;20000&lt;/code&gt; characters.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Practical Applications
&lt;/h2&gt;

&lt;p&gt;Once the basics are mastered, GASADK truly shines in multi-agent configurations and complex data manipulation. Here are three developer-focused practical examples.&lt;/p&gt;

&lt;h3&gt;
  
  
  Practical 1: Multi-Agent Customer Support Orchestrator
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Aim:&lt;/strong&gt; To construct a hierarchical Multi-Agent system where a main "SupportOrchestrator" delegates distinct sub-tasks to specialized Sub-Agents ("TranslatorAgent" and "SentimentAgent") and aggregates their findings into a structured JSON payload.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Execution Details:&lt;/strong&gt; A French customer inquiry is created as a text file. The Main Agent identifies the need to translate the text and assess the sentiment. It autonomously triggers the Sub-Agents, receives their outputs, determines a management action plan, and returns a fully compiled JSON object.&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;/**
 * Practical 1: Multi-Agent Customer Support Orchestrator
 *
 * Demonstrates SubAgents, static Agent Skills, and strict JSON output routing.
 * Requires GEMINI_API_KEY in Script Properties.
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;practical_CustomerSupportOrchestrator&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;LlmAgent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;GASADK&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;properties&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;API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;properties&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GEMINI_API_KEY&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;API_KEY&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GEMINI_API_KEY is missing in Script Properties.&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;tempFolder&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;createFolder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Temp_Skills_&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&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;policyFolder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tempFolder&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;support_policy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;policyFolder&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SKILL.md&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;---&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;name: support_policy&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;description: Corporate policy for customer support actions.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;---&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;Rule: If sentiment is NEGATIVE, the manager_action_plan MUST be 'ESCALATE_TO_HUMAN'. Otherwise, it is 'AUTO_REPLY'.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;MimeType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PLAIN_TEXT&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;translatorAgent&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;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;API_KEY&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;TranslatorAgent&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;Translates foreign text into English.&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;models/gemini-3.1-flash-lite&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;Return ONLY the exact English translation of the provided text.&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;setServices&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LockService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getScriptLock&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="nx"&gt;properties&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;sentimentAgent&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;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;API_KEY&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;SentimentAgent&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;Analyzes sentiment of 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;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.1-flash-lite&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;Return ONLY one word: POSITIVE, NEUTRAL, or NEGATIVE.&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;setServices&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LockService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getScriptLock&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="nx"&gt;properties&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;mainAgent&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;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;API_KEY&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;SupportOrchestrator&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;models/gemini-3.1-flash-lite&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;Process the customer inquiry. Use TranslatorAgent to translate it, SentimentAgent to analyze it, and the support_policy skill to determine the action plan. Output strictly as 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;skillFolderId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tempFolder&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="na"&gt;subAgents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;translatorAgent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sentimentAgent&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;outputSchema&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;original_text&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;english_translation&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;sentiment&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;manager_action_plan&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="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;original_text&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;english_translation&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;sentiment&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;manager_action_plan&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="nf"&gt;setServices&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LockService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getScriptLock&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="nx"&gt;properties&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;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Inquiry: Bonjour, mon application plante à chaque fois que j'essaie de me connecter. C'est très frustrant ! Aidez-moi vite.&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Executing Orchestrator DAG...&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mainAgent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&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="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;log&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="nx"&gt;log&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;] &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;log&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="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;Final Compiled Report:&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;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;response&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="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;tempFolder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setTrashed&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Execution log:&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;2:18:54 PM    Notice  Execution started
2:18:58 PM    Info    Executing Orchestrator DAG...
2:18:58 PM    Info    [2026-05-18T05:18:58.597Z] Agent run sequence initiated
2:18:58 PM    Info    [2026-05-18T05:18:58.598Z] Planning phase initiated.
2:19:00 PM    Info    [2026-05-18T05:19:00.500Z] Execution Plan Generated:
Task [1]: 'subagent_TranslatorAgent'
Task [2]: 'subagent_SentimentAgent'
Task [3]: 'skill_support_policy'
2:19:00 PM    Info    [2026-05-18T05:19:00.501Z] Executing Task [1] via [subagent_TranslatorAgent]
2:19:01 PM    Info    [2026-05-18T05:19:01.478Z] Task [1] completed successfully in 975ms.
2:19:01 PM    Info    [2026-05-18T05:19:01.479Z] Executing Task [2] via [subagent_SentimentAgent]
2:19:02 PM    Info    [2026-05-18T05:19:02.611Z] Task [2] completed successfully in 1131ms.
2:19:02 PM    Info    [2026-05-18T05:19:02.612Z] Executing Task [3] via [skill_support_policy]
2:19:03 PM    Info    [2026-05-18T05:19:03.866Z] Task [3] completed successfully in 1253ms.
2:19:03 PM    Info    [2026-05-18T05:19:03.867Z] Execution phase complete. Initiating final synthesis.
2:19:05 PM    Info    [2026-05-18T05:19:05.601Z] Final synthesis complete.
2:19:05 PM    Info    Final Compiled Report:
 {
  "original_text": "Bonjour, mon application plante à chaque fois que j'essaie de me connecter. C'est très frustrant ! Aidez-moi vite.",
  "english_translation": "Hello, my application crashes every time I try to log in. It's very frustrating! Please help me quickly.",
  "sentiment": "NEGATIVE",
  "manager_action_plan": "A member of our human support team has been notified of your application crash and will reach out to you shortly to assist with the necessary troubleshooting steps and a resolution. Thank you for your patience."
}
2:19:06 PM    Notice  Execution completed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Architectural Analysis &amp;amp; Key Takeaways:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Heterogeneous DAG Construction:&lt;/strong&gt; The execution log proves that the Planner successfully generated a seamless execution queue crossing entirely different capability domains: invoking two distinct &lt;code&gt;LlmAgent&lt;/code&gt; instances (Tasks 1 &amp;amp; 2) and subsequently retrieving an RAG-style Markdown policy from Google Drive (Task 3).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context Isolation:&lt;/strong&gt; By delegating translation and sentiment analysis to Sub-Agents, the &lt;code&gt;SupportOrchestrator&lt;/code&gt; avoids polluting its own context window with intermediate reasoning, preventing LLM confusion.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Strict Schema Adherence:&lt;/strong&gt; The &lt;code&gt;outputSchema&lt;/code&gt; mathematically forces the final Synthesizer phase to output a parsable JSON string. Even though the &lt;code&gt;support_policy&lt;/code&gt; Skill dictated an action of &lt;code&gt;"ESCALATE_TO_HUMAN"&lt;/code&gt;, the LLM synthesized this directive into a polished, customer-facing &lt;code&gt;"manager_action_plan"&lt;/code&gt;, fulfilling both the policy constraint and the JSON structure.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Practical 2: Financial Data Analyzer with Code Execution
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Aim:&lt;/strong&gt; To show how an agent can pull data from a Google Spreadsheet using a Native GAS Tool and then utilize Gemini's internal Code Execution (Python) to perform precise mathematical calculations, avoiding LLM math hallucinations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Execution Details:&lt;/strong&gt; A temporary Spreadsheet is created with mock revenue data. The agent uses &lt;code&gt;getSpreadsheetData&lt;/code&gt; to retrieve it, writes an internal Python script to calculate the average growth rate mathematically, and outputs the forecast.&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;/**
 * Practical 2: Financial Data Analyzer with Code Execution
 * Requires GEMINI_API_KEY in Script Properties.
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;practical_FinancialForecaster&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;LlmAgent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;GASADK&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;properties&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;API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;properties&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GEMINI_API_KEY&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;API_KEY&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GEMINI_API_KEY is missing in Script Properties.&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;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;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Temp_Financial_Data_&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&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;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;getActiveSheet&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="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Month&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;Revenue&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&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="mi"&gt;11500&lt;/span&gt;&lt;span class="p"&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="mi"&gt;12000&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;13500&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;14000&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15500&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="nx"&gt;data&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="mi"&gt;2&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;data&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;ssId&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;getId&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;agent&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;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;API_KEY&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;FinancialAnalyst&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;models/gemini-3.1-flash-lite&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;Use getSpreadsheetData to retrieve revenue data. Then, use your code executor to mathematically calculate the average monthly growth rate and predict Month 7 revenue.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;codeExecutor&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="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;getSpreadsheetData&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;Fetches the raw financial revenue data.&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="p"&gt;},&lt;/span&gt;
          &lt;span class="na"&gt;function&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="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;ssId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
              &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getActiveSheet&lt;/span&gt;&lt;span class="p"&gt;()&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="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="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;outputSchema&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;average_growth_rate_percentage&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;month_7_prediction&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;analysis_summary&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="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;average_growth_rate_percentage&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;month_7_prediction&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;analysis_summary&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="nf"&gt;setServices&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LockService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getScriptLock&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="nx"&gt;properties&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Execute the financial analysis.&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;log&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="nx"&gt;log&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;] &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;log&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="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;Analysis Result:&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;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;response&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="k"&gt;finally&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;getFileById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ssId&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;setTrashed&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Execution log:&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;2:20:55 PM    Notice  Execution started
2:20:56 PM    Info    [2026-05-18T05:20:56.981Z] Agent run sequence initiated
2:20:56 PM    Info    [2026-05-18T05:20:56.985Z] Planning phase initiated.
2:20:58 PM    Info    [2026-05-18T05:20:58.314Z] Execution Plan Generated:
Task [1]: 'tool_getSpreadsheetData'
Task [2]: 'builtin_codeExecutor'
2:20:58 PM    Info    [2026-05-18T05:20:58.316Z] Executing Task [1] via [tool_getSpreadsheetData]
2:21:00 PM    Info    [2026-05-18T05:21:00.632Z] Task [1] completed successfully in 2315ms.
2:21:00 PM    Info    [2026-05-18T05:21:00.634Z] Executing Task [2] via [builtin_codeExecutor]
2:21:04 PM    Info    [2026-05-18T05:21:04.380Z] Task [2] completed successfully in 3745ms.
2:21:04 PM    Info    [2026-05-18T05:21:04.382Z] Execution phase complete. Initiating final synthesis.
2:21:05 PM    Info    [2026-05-18T05:21:05.619Z] Final synthesis complete.
2:21:05 PM    Info    Analysis Result:
 {
  "average_growth_rate_percentage": 9.25,
  "month_7_prediction": 16934.24,
  "analysis_summary": "Based on the provided revenue data from Month 1 to Month 6, the company demonstrated a fluctuating growth pattern with an average monthly growth rate of approximately 9.25%. By applying this average rate to the most recent revenue figure of 15,500, the projected revenue for Month 7 is 16,934.24."
}
2:21:06 PM    Notice  Execution completed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Architectural Analysis &amp;amp; Key Takeaways:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Bridging Environments:&lt;/strong&gt; This execution is a masterclass in hybrid computational routing. The agent uses &lt;code&gt;Task [1]&lt;/code&gt; (a Native GAS Tool) to read local Google Workspace infrastructure data. Then, it uses &lt;code&gt;Task [2]&lt;/code&gt; to inject that payload securely into the Gemini backend's Python sandbox.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Eradicating LLM Hallucination:&lt;/strong&gt; LLMs are inherently probabilistic and terrible at raw arithmetic. By forcing the agent to use &lt;code&gt;builtin_codeExecutor&lt;/code&gt; for the calculation, GASADK ensures the 9.25% growth rate and the Month 7 projection are the result of deterministic Python execution, not a text-prediction hallucination.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execution Speed:&lt;/strong&gt; Executing the entire pipeline—planning, fetching spreadsheet data, writing Python code, executing it remotely, and synthesizing a JSON output—in roughly 10 seconds proves the extreme efficiency of the DAG-based PES architecture compared to looping ReAct models.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Practical 3: Custom Function for Multiple Cells using SubAgent
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Aim:&lt;/strong&gt; To seamlessly embed a Multi-Agent architecture directly into a Google Sheets Custom Function. This demonstrates handling bulk data efficiently without hitting execution timeouts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Execution Details:&lt;/strong&gt; Instead of pinging the API for each row, multiple cells are merged and sent to the Main Agent. The Main Agent sends the entire block to a "Categorizer" Sub-Agent, which classifies the reviews based on strict guidelines, returning a perfectly formatted summary to a single cell.&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;/**
 * Practical 3: Custom Function for Multiple Cells using SubAgent
 * Run setup_Practical3_Environment() first, then use =BULK_FEEDBACK_ANALYZER(A2:A4) in B2.
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setup_Practical3_Environment&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;sheet&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="nf"&gt;getActiveSheet&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="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Customer Reviews&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The UI is great, but the app crashes when I try to upload a picture.&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;I absolutely love the new dark mode feature!&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Customer service took 3 days to reply. Very disappointed.&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;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="nx"&gt;data&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="mi"&gt;1&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;data&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;B1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Agent Analysis Output&lt;/span&gt;&lt;span class="dl"&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;setColumnWidth&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;400&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;setColumnWidth&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="mi"&gt;400&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 that processes bulk feedback using an orchestrated SubAgent.
 * @param {Array&amp;lt;Array&amp;lt;string&amp;gt;&amp;gt;} dataRange The range of cells containing the feedback.
 * @return {string} The categorized analysis.
 * @customfunction
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;BULK_FEEDBACK_ANALYZER&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dataRange&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;LlmAgent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;GASADK&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;dataRange&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;Error: Provide a valid range.&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;properties&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;API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;properties&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GEMINI_API_KEY&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;API_KEY&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;Error: GEMINI_API_KEY missing.&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;mergedData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dataRange&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flat&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;item&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="s2"&gt;`Review &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="s2"&gt;: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;item&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;categorizerAgent&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;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;API_KEY&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;CategorizerAgent&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;Categorizes customer reviews based on internal guidelines.&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;models/gemini-3.1-flash-lite&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;`GUIDELINE: Classify strictly as "BUG" (crash/glitch), "PRAISE" (positive sentiment), or "COMPLAINT" (unhappy with service). Provide Category and short summary.`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;setServices&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LockService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getScriptLock&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="nx"&gt;properties&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;mainAgent&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;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;API_KEY&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;ReviewOrchestrator&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;models/gemini-3.1-flash-lite&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;Send ALL reviews together to CategorizerAgent. Format the final output as clean, unstyled plain 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;subAgents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;categorizerAgent&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;setServices&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LockService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getScriptLock&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="nx"&gt;properties&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;mainAgent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Analyze the following reviews:&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;mergedData&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="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&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="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;Result:&lt;/strong&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%2Fqmk9q9zdel055262ekub.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%2Fqmk9q9zdel055262ekub.jpg" alt="Result for Practical 3" width="800" height="349"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Architectural Analysis &amp;amp; Key Takeaways:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Evading GAS Custom Function Limits:&lt;/strong&gt; Google Sheets imposes a strict 30-second timeout on all Custom Functions (&lt;code&gt;=FUNCTION_NAME&lt;/code&gt;). A traditional looping ReAct agent evaluating cells row-by-row would instantly trigger this timeout limit. GASADK circumvents this infrastructure constraint by flattening the payload, executing a single batch request, and completing the orchestrated Multi-Agent run well within the safe margin (sub-1200ms per the Execution Summary).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cognitive Offloading:&lt;/strong&gt; The &lt;code&gt;ReviewOrchestrator&lt;/code&gt; agent refuses to evaluate the data itself. Its only job is UI formatting. It offloads the cognitive burden of classification to the &lt;code&gt;CategorizerAgent&lt;/code&gt;. This structural separation enforces guideline adherence (BUG/PRAISE/COMPLAINT) while maintaining a clean, unstyled string output required for a Spreadsheet cell.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execution Transparency:&lt;/strong&gt; Notice the automatically appended &lt;code&gt;Execution Summary&lt;/code&gt; in the cell output. Because no JSON &lt;code&gt;outputSchema&lt;/code&gt; was enforced, the Synthesizer honors the system mandate to append its telemetry, proving exactly which SubAgent was utilized, the duration, and the localized prompt used.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Practical 4: Enterprise Intelligence Orchestrator
&lt;/h3&gt;

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

&lt;p&gt;The objective is to architect and demonstrate a highly sophisticated, autonomous enterprise intelligence pipeline utilizing multi-agent orchestration, Agent-to-Agent (A2A) protocols, dynamic context injection (Retrieval-Augmented Generation via Skills), deterministic function calling for side effects, and strict structured outputs. By synthesizing unstructured telemetry from a remote node with real-time web grounding, the system automatically generates, stores, and logs comprehensive corporate intelligence reports within Google Workspace.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Execution Details:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The system operates in two distinct, programmatic phases: state initialization and autonomous pipeline execution.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Environment Initialization (&lt;code&gt;setup_IntelligenceEnvironment&lt;/code&gt;):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dynamically provisions a dedicated Google Drive workspace and persists the folder ID to script properties.&lt;/li&gt;
&lt;li&gt;Generates a structural markdown directive (&lt;code&gt;Corporate_Reporting_Guidelines&lt;/code&gt;) and injects it as an agent skill file. This enforces output formatting constraints via retrieval-augmented generation (RAG) without polluting the core operational prompt.&lt;/li&gt;
&lt;li&gt;Initializes a Google Spreadsheet functioning as a tracking database and state machine (queue) with target entities: "CyberDyne Systems" and "Massive Dynamic."&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Multi-Agent Orchestration &amp;amp; A2A Integration (&lt;code&gt;execute_IntelligencePipeline&lt;/code&gt;):&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SentimentAnalyzer (Sub-Agent):&lt;/strong&gt; Instantiates a specialized agent utilizing the &lt;code&gt;gemini-3.1-flash-lite&lt;/code&gt; model, strictly prompted to evaluate news text and output a deterministic prefix (&lt;code&gt;[BULLISH]&lt;/code&gt;, &lt;code&gt;[BEARISH]&lt;/code&gt;, or &lt;code&gt;[NEUTRAL]&lt;/code&gt;) followed by a one-sentence justification.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ApexOrchestrator (Main Agent):&lt;/strong&gt; The central controller that integrates the following capabilities:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;skillFolderId&lt;/code&gt;: Ingests the 4-section markdown reporting guidelines.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;subAgents&lt;/code&gt;: Delegates sentiment evaluation tasks to the &lt;code&gt;SentimentAnalyzer&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;a2aServerAgentCardURLs&lt;/code&gt;: Connects to a remote Node Web App via the A2A protocol to invoke the &lt;code&gt;get_financial_telemetry&lt;/code&gt; tool.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;googleSearch&lt;/code&gt;: Executes real-time web searches to ground the intelligence report with current events.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tools&lt;/code&gt;: Utilizes a native function (&lt;code&gt;generate_google_doc_report&lt;/code&gt;) to physically convert the markdown string into a persistent Google Document and move it to the workspace folder.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Structured Output:&lt;/strong&gt; Forces the final output into a predefined JSON schema (&lt;code&gt;doc_url&lt;/code&gt;, &lt;code&gt;brief_summary&lt;/code&gt;), allowing the script to parse the result and programmatically update the spreadsheet status (&lt;code&gt;PENDING&lt;/code&gt; -&amp;gt; &lt;code&gt;PROCESSING&lt;/code&gt; -&amp;gt; &lt;code&gt;COMPLETED&lt;/code&gt;/&lt;code&gt;FAILED&lt;/code&gt;).&lt;/li&gt;

&lt;/ul&gt;

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

&lt;p&gt;Execute the following deployment sequence with absolute strictness. Failure to adhere to the exact order of operations regarding deployment IDs and versioning will result in fatal routing errors and A2A handshake failures.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 1: Environment Provisioning&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Isolate Workspaces:&lt;/strong&gt; Create two entirely separate Google Apps Script projects. Designate one as the "Server" (Financial Data Node) and the other as the "Client" (Intelligence Orchestrator).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inject Dependencies:&lt;/strong&gt; Install the &lt;code&gt;GASADK&lt;/code&gt; library into &lt;em&gt;both&lt;/em&gt; projects via the GAS Library manager.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configure Credentials:&lt;/strong&gt; In both projects, navigate to &lt;strong&gt;Project Settings &amp;gt; Script Properties&lt;/strong&gt;. Manually define a property strictly named &lt;code&gt;GEMINI_API_KEY&lt;/code&gt; and assign your active Gemini API key.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Phase 2: Server Node Deployment (Strict Order Required)&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Initial Code Commit:&lt;/strong&gt; Copy and paste the Server script into the Server project.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Initial Deployment:&lt;/strong&gt; Deploy the script as a Web App (&lt;strong&gt;Deploy &amp;gt; New deployment&lt;/strong&gt;). You must configure "Execute as" to &lt;strong&gt;Me&lt;/strong&gt; and "Who has access" to &lt;strong&gt;Anyone&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Capture the Endpoint:&lt;/strong&gt; Copy the generated Web App URL. It will follow the structure &lt;code&gt;https://script.google.com/macros/s/{deploymentId}/exec&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resolve Self-Reference:&lt;/strong&gt; Inject this exact URL into the &lt;code&gt;WEB_APPS_URL&lt;/code&gt; constant within your Server script.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Force State Update (Critical):&lt;/strong&gt; You must redeploy the Web App immediately to bake the updated constant into the active runtime. Go to &lt;strong&gt;Manage deployments &amp;gt; Edit (pencil icon) &amp;gt; Version: New &amp;gt; Deploy&lt;/strong&gt;. Do not create a completely new deployment; version up the existing one.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Phase 3: Client Orchestrator Configuration&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Client Code Commit:&lt;/strong&gt; Copy and paste the Client script into the Client project.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Establish A2A Routing:&lt;/strong&gt; Define the &lt;code&gt;A2A_SERVER_URL&lt;/code&gt; constant. This is &lt;em&gt;not&lt;/em&gt; just the base Server URL. You must append the protocol discovery path to it. It must look exactly like this: &lt;code&gt;https://script.google.com/macros/s/{deploymentId}/exec/.well-known/agent-card.json&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Phase 4: Execution &amp;amp; Verification&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Bootstrap the Architecture:&lt;/strong&gt; In the Client project, manually execute the &lt;code&gt;setup_IntelligenceEnvironment&lt;/code&gt; function. You will be prompted to authorize high-privilege OAuth scopes (Drive, Spreadsheets, Documents). Grant them. This function dynamically builds your state machine (Spreadsheet) and injects the RAG logic (Skill file) into a new Drive directory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitor the State Machine:&lt;/strong&gt; Retrieve the URL of the generated "Target_Corporations_Tracker" spreadsheet from the GAS execution log. Open it in a separate tab to monitor asynchronous state mutations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ignite the Pipeline:&lt;/strong&gt; Execute the &lt;code&gt;execute_IntelligencePipeline&lt;/code&gt; function in the Client project. The orchestrator will autonomously navigate the spreadsheet queue, negotiate the A2A handshake with the Server, spawn the sentiment sub-agent, and generate the final intelligence reports.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Server
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Practical 4 Server: A2A Financial Telemetry Node
 * Deploy as a Web App in a separate GAS project with GASADK installed.
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;doGet&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="k"&gt;return&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;function&lt;/span&gt; &lt;span class="nf"&gt;doPost&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="k"&gt;return&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;WEB_APPS_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://script.google.com/macros/s/{deploymentId}/exec&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Please set your Web Apps URL.&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MCPA2Aserver&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;GASADK&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;lock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;LockService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getScriptLock&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;API_KEY&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="nf"&gt;getProperty&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_API_KEY&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;API_KEY&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GEMINI_API_KEY is missing.&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;m&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;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="nf"&gt;setServices&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;lock&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;API_KEY&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="c1"&gt;// Explicitly enable A2A protocol&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="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="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_financial_telemetry&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;Fetches critical financial data for a specified corporation.&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;company_name&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="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;company_name&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="na"&gt;get_financial_telemetry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&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;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;company_name&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;marketCap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;18.5&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toFixed&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="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;B USD&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;stockPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;14.3&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toFixed&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="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="k"&gt;return&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="s2"&gt;`Telemetry for &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;company_name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; | Market Cap: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;marketCap&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; | Stock Price: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;stockPrice&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="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="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;FinancialDataNode&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;Provides encrypted financial telemetry for global corporations.&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="nx"&gt;WEB_APPS_URL&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_financial_telemetry&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;Fetch Financial Telemetry&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="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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Client
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Practical 4 Client: Enterprise Intelligence Orchestrator
 * Requires GEMINI_API_KEY. Run setup_IntelligenceEnvironment() once.
 * Set A2A_SERVER_URL to the deployed Node Web App URL before executing the pipeline.
 * URL will be https://script.google.com/macros/s/{deploymentId}/exec/.well-known/agent-card.json`
 */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;A2A_SERVER_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://script.google.com/macros/s/{deploymentId}/exec/.well-known/agent-card.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setup_IntelligenceEnvironment&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;folder&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;createFolder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Intelligence_Workspace_&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&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;folderId&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;getId&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;WORKSPACE_FOLDER_ID&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;folderId&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;skillFolder&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;createFolder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Corporate_Reporting_Guidelines&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;guidelineText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`---\nname: Corporate_Reporting_Guidelines\ndescription: Structural guidelines for intelligence reports.\n---\nCORPORATE REPORTING GUIDELINES\nReports MUST follow this structure:\n# 1. EXECUTIVE SUMMARY\n# 2. FINANCIAL TELEMETRY\n# 3. MARKET SENTIMENT\n# 4. STRATEGIC OUTLOOK`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;skillFolder&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SKILL.md&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;guidelineText&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MimeType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PLAIN_TEXT&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;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Target_Corporations_Tracker_&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&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;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;getActiveSheet&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;appendRow&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Target Company&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;Status&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;Report Document 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;Brief Summary&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;targets&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CyberDyne Systems&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;PENDING&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="p"&gt;,&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Massive Dynamic&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;PENDING&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="p"&gt;,&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;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;2&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;targets&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="mi"&gt;4&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;targets&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;TRACKING_SHEET_ID&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&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;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;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;`Setup Complete. Tracking Sheet URL: &lt;/span&gt;&lt;span class="p"&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;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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;execute_IntelligencePipeline&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;A2A_SERVER_URL&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;YOUR_NODE&lt;/span&gt;&lt;span class="dl"&gt;"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;A2A_SERVER_URL not configured.&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="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="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;GASADK&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;props&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;API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GEMINI_API_KEY&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;folderId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;WORKSPACE_FOLDER_ID&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;sheetId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;TRACKING_SHEET_ID&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;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;openById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sheetId&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;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;getActiveSheet&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="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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sentimentAgent&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;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;API_KEY&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;SentimentAnalyzer&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;Evaluates raw news text for market sentiment.&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;models/gemini-3.1-flash-lite&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;Output EXACTLY one prefix: [BULLISH], [BEARISH], or [NEUTRAL], followed by a single sentence justification.&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;setServices&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LockService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getScriptLock&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="nx"&gt;props&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;orchestrator&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;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;API_KEY&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;ApexOrchestrator&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;models/gemini-3.1-flash-lite&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;skillFolderId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;folderId&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;sentimentAgent&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;a2aServerAgentCardURLs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;A2A_SERVER_URL&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;googleSearch&lt;/span&gt;&lt;span class="p"&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;`Construct an intelligence report. Extract telemetry from the A2A node, search Google for recent news, and use SentimentAnalyzer. Synthesize the data adhering strictly to the Corporate_Reporting_Guidelines skill. Save via generate_google_doc_report.`&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="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;generate_google_doc_report&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;Creates a persistent Google Document with the compiled markdown report.&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;title&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;markdown_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;string&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;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;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;markdown_content&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;function&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&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;doc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;DocumentApp&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;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBody&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;setText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;markdown_content&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;getFileById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;doc&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="nf"&gt;moveTo&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;getFolderById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;folderId&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;docUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;doc&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="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="na"&gt;outputSchema&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;doc_url&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;brief_summary&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="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;doc_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;brief_summary&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="nf"&gt;setServices&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LockService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getScriptLock&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="nx"&gt;props&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;for &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;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="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&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;length&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="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;data&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="mi"&gt;1&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;PENDING&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;continue&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;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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PROCESSING&lt;/span&gt;&lt;span class="dl"&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;flush&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="nx"&gt;orchestrator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s2"&gt;`Gather intelligence 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;i&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="s2"&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;log&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="nx"&gt;log&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;] &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;log&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="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;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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;COMPLETED&lt;/span&gt;&lt;span class="dl"&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="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="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;setValue&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;doc_url&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;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="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;setValue&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;brief_summary&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;err&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="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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;FAILED&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;SpreadsheetApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flush&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;&lt;strong&gt;Result:&lt;/strong&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%2Fgvaxf9dbhp1d0lxiyg03.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%2Fgvaxf9dbhp1d0lxiyg03.jpg" alt="Result1 for Practical 4: Created Google Spreadsheet" width="800" height="271"&gt;&lt;/a&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%2F41ilhpio8tc5pbi4t0xk.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%2F41ilhpio8tc5pbi4t0xk.jpg" alt="Result2 for Practical 4: Created Google Document of cell C2" width="800" height="629"&gt;&lt;/a&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%2Fsv602isnkosgvpmhiynx.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%2Fsv602isnkosgvpmhiynx.jpg" alt="Result3 for Practical 4: Created Google Document of cell C3" width="800" height="629"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Deep Analysis of Script Architecture and Execution Results
&lt;/h3&gt;

&lt;p&gt;A rigorous examination of the code structure against the produced execution artifacts reveals the orchestration capabilities, systemic robustness, and inherent inferential logic executed by the multi-agent framework.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Advanced Contextual Reasoning &amp;amp; Contradiction Resolution
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Confidence Level: High (98%)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The most critical takeaway from the execution results is the LLM's capacity for complex critical thinking—specifically, its ability to mediate conflicting data sources without failing or producing hallucinatory contradictions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CyberDyne Systems:&lt;/strong&gt; The orchestrator successfully blended factual Google Search data (referencing CYBERDYNE Inc., a real Japanese medical robotics company, its profitability, and cash-heavy status) with the dummy, astronomically inflated A2A financial data. It logically synthesized a coherent &lt;code&gt;[BULLISH]&lt;/code&gt; narrative.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Massive Dynamic:&lt;/strong&gt; The true test of the system. The A2A node explicitly returned hard numerical data: "Market Cap: $27,176.50 Billion USD." A rudimentary automation pipeline would have ingested this blindly. However, the &lt;code&gt;ApexOrchestrator&lt;/code&gt; utilized Google Search, identified the corporation as a fictional entity from the TV series &lt;em&gt;Fringe&lt;/em&gt;, and independently concluded that the A2A telemetry was invalid. It semantically overrode the input, classifying it as "digital noise" and "speculative," and correctly forced the &lt;code&gt;SentimentAnalyzer&lt;/code&gt; to yield a &lt;code&gt;[NEUTRAL]&lt;/code&gt; verdict. This proves the orchestrator acts as an intelligent semantic filter, aggressively rejecting hallucinatory or mocked inputs when grounded against reality.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  2. Architectural Integrity &amp;amp; Pipeline Validity
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Confidence Level: High (95%)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The scripts validate three advanced agentic paradigms in a single cohesive flow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Skill Injection (RAG):&lt;/strong&gt; The dynamically created markdown file (&lt;code&gt;Corporate_Reporting_Guidelines&lt;/code&gt;) is strictly adhered to. Both generated Google Docs identically feature the four mandated headings (Executive Summary, Financial Telemetry, Market Sentiment, Strategic Outlook).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-Agent Delegation:&lt;/strong&gt; The task separation is absolute. The &lt;code&gt;SentimentAnalyzer&lt;/code&gt; performs exclusively as instructed, outputting the exact prefixes &lt;code&gt;[BULLISH]&lt;/code&gt; and &lt;code&gt;[NEUTRAL]&lt;/code&gt; into the Market Sentiment section of the final reports.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deterministic State Mutations:&lt;/strong&gt; The &lt;code&gt;generate_google_doc_report&lt;/code&gt; tool accurately executes side effects (Document creation) and returns the state (URL). The orchestrator adheres to the &lt;code&gt;outputSchema&lt;/code&gt; constraint, extracting the &lt;code&gt;doc_url&lt;/code&gt; and &lt;code&gt;brief_summary&lt;/code&gt; to update the native GAS Spreadsheet, fully automating the tracking pipeline.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  3. Irrefutable Mathematical Discrepancy in Provided Code
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Confidence Level: Absolute (100%)&lt;/strong&gt;&lt;br&gt;
A forensic analysis of the &lt;code&gt;Server&lt;/code&gt; script versus the logged execution artifacts uncovers a definitive mathematical impossibility. The execution logs are authentic, but the provided &lt;code&gt;Server&lt;/code&gt; script is a simplified or outdated variant that did not generate those specific results.&lt;/p&gt;

&lt;p&gt;Look at the hashing logic in the provided code:&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;const&lt;/span&gt; &lt;span class="nx"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;company_name&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;marketCap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;18.5&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toFixed&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="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;B USD&lt;/span&gt;&lt;span class="dl"&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 we calculate this for &lt;code&gt;company_name = "CyberDyne Systems"&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Length: 17 characters.&lt;/li&gt;
&lt;li&gt;Market Cap Calculation: &lt;code&gt;17 * 18.5 = 314.5&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Expected Output: &lt;strong&gt;$314.50B USD&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, the execution result in the Google Doc explicitly states:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Market Capitalization: $31,320.50 Billion USD&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If we reverse-engineer the math: &lt;code&gt;31320.50 / 18.5 = 1693&lt;/code&gt;.&lt;br&gt;
The number &lt;strong&gt;1693&lt;/strong&gt; is the exact sum of the ASCII decimal values for the string "CyberDyne Systems" (&lt;code&gt;C:67 + y:121 + b:98 + e:101 + r:114 + D:68 + y:121 + n:110 + e:101 + [space]:32 + S:83 + y:121 + s:115 + t:116 + e:101 + m:109 + s:115 = 1693&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Conclusion:&lt;/em&gt; The server code actually executing during the pipeline run utilized an ASCII reduction algorithm:&lt;br&gt;
&lt;code&gt;const hash = args.company_name.split('').reduce((acc, char) =&amp;gt; acc + char.charCodeAt(0), 0);&lt;/code&gt;&lt;br&gt;
The provided code utilized &lt;code&gt;.length&lt;/code&gt; instead. While this does not invalidate the success of the A2A protocol or the orchestrator's logic, it is a glaring deterministic gap in the provided documentation. I have identified it immediately. The system design remains technically exceptional despite this code-to-log discrepancy.&lt;/p&gt;
&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;The objective of this manuscript is to bridge the architectural gap between advanced Generative AI agent frameworks and the Google Workspace ecosystem. The primary goal was to engineer a survival-oriented Agent Development Kit natively tailored for Google Apps Script (GASADK). By achieving robust multi-agent orchestration, MCP integration, and A2A networking without requiring external server infrastructure, this framework profoundly impacts enterprise automation. It transitions static, rule-based macros into dynamic, context-aware AI systems capable of complex reasoning, contradiction resolution, and deterministic structured outputs under extreme execution constraints.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Takeaways:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Architectural Paradigm Shift:&lt;/strong&gt; Replaces the traditional, optimistic ReAct loop with a Planner-Executor-Synthesizer (PES) model that maps a Directed Acyclic Graph (DAG) upfront, effectively circumventing the strict 6-minute GAS timeout and synchronous I/O bottlenecks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Payload and Execution Bulletproofing:&lt;/strong&gt; Implements aggressive data truncation, temporal context anchoring, and dynamic Re-Planning to systematically prevent &lt;code&gt;400 Payload Too Large&lt;/code&gt; crashes and infinite-loop execution deaths, ensuring enterprise-grade reliability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Seamless Serverless Integration:&lt;/strong&gt; Leverages native GAS infrastructure to execute tasks across Google Drive, Sheets, and Docs using Function Calling, built-in code execution (Python), and dynamic Skill injection (RAG) with zero external hosting overhead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Advanced Multi-Agent &amp;amp; A2A Orchestration:&lt;/strong&gt; Enables hierarchical distributed cognition by allowing a master orchestrator to seamlessly delegate specialized tasks (e.g., sentiment analysis, translation) to local Sub-Agents and remote endpoints via standardized Agent Cards.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Critical Inferential Validation:&lt;/strong&gt; Demonstrates the system's advanced capacity to resolve conflicting data sources (e.g., rejecting mocked A2A financial telemetry by cross-referencing real-time Google Search data), while transparently identifying and documenting a forensic code-to-log algorithmic discrepancy (ASCII sum vs. string length) in the presented practical examples.&lt;/li&gt;
&lt;/ul&gt;

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

</description>
      <category>ai</category>
      <category>gemini</category>
      <category>googleappsscript</category>
      <category>adk</category>
    </item>
    <item>
      <title>Deploying a Rust A2A Agent to Google Cloud Run</title>
      <dc:creator>xbill</dc:creator>
      <pubDate>Mon, 18 May 2026 03:02:39 +0000</pubDate>
      <link>https://forem.com/gde/deploying-a-rust-a2a-agent-to-google-cloud-run-30jd</link>
      <guid>https://forem.com/gde/deploying-a-rust-a2a-agent-to-google-cloud-run-30jd</guid>
      <description>&lt;p&gt;Leveraging the Gemini CLI and the underlying Gemini LLM to build A2A Agent Applications with the Rust programming language. The A2A Rust Agent application was debugged and validated locally. Then- the entire solution is deployed to Google Cloud Run.&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%2Faid4vmrhln1r1nrus7ph.jpeg" 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%2Faid4vmrhln1r1nrus7ph.jpeg" width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Rust A2A? Isn’t that a Python Thing?
&lt;/h4&gt;

&lt;p&gt;The bulk of A2A Agents are in Python. The A2A protocol is language independent.&lt;/p&gt;

&lt;p&gt;Python has traditionally been the main coding language for ML and AI tools. The goal of this article is to provide a test bed for building, debugging, and deploying cross language applications.&lt;/p&gt;

&lt;h4&gt;
  
  
  So is this the Real Deal(TM)?
&lt;/h4&gt;

&lt;p&gt;So what is different about this lab compared to all the others out there?&lt;/p&gt;

&lt;p&gt;This is one of the first deep dives into a Rust A2A agent leveraging the standard Rust crates.&lt;/p&gt;

&lt;h4&gt;
  
  
  What is Rust?
&lt;/h4&gt;

&lt;p&gt;Rust is a high performance, memory safe, compiled language:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.rust-lang.org/" rel="noopener noreferrer"&gt;Rust&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Rust provides memory safe operations beyond C/C++ and also can provide exceptional performance gains as it is compiled directly to native binaries.&lt;/p&gt;

&lt;h4&gt;
  
  
  Rust Setup
&lt;/h4&gt;

&lt;p&gt;Instructions to install Rust are available here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.rust-lang.org/learn/get-started" rel="noopener noreferrer"&gt;Getting started&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For a Linux like environment the command looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl — proto ‘&lt;span class="o"&gt;=&lt;/span&gt;https’ — tlsv1.2 &lt;span class="nt"&gt;-sSf&lt;/span&gt; https://sh.rustup.rs | sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rust also depends on a working C compiler and OpenSSL setup. For a Debian 12 system — install the basic tools for development:&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;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;build-essential
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;libssl-dev
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;pkg-config
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;libudev-dev
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;make
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Gemini CLI
&lt;/h4&gt;

&lt;p&gt;If not pre-installed you can download the Gemini CLI to interact with the source files and provide real-time assistance:&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/gemini-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Testing the Gemini CLI Environment
&lt;/h4&gt;

&lt;p&gt;Once you have all the tools and the correct Node.js version in place- you can test the startup of Gemini CLI. You will need to authenticate with a Key or your Google Account:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;▝▜▄ Gemini CLI v0.33.1
    ▝▜▄
   ▗▟▀ Logged in with Google /auth
  ▝▀ Gemini Code Assist Standard /upgrade no sandbox (see /docs) /model Auto (Gemini 3) | 239.8 MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Where do I start?
&lt;/h4&gt;

&lt;p&gt;The strategy for starting Rust A2A development is a incremental step by step approach.&lt;/p&gt;

&lt;p&gt;First, the basic development environment is setup with the required system variables, and a working Gemini CLI configuration.&lt;/p&gt;

&lt;p&gt;Then, a Rust A2A agent is built, debugged, and tested locally.&lt;/p&gt;

&lt;h4&gt;
  
  
  Setup the Basic Environment
&lt;/h4&gt;

&lt;p&gt;At this point you should have a working Python environment and a working Gemini CLI installation. All of the relevant code examples and documentation is available in GitHub.&lt;/p&gt;

&lt;p&gt;The next step is to clone the GitHub repository to your local environment:&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;cd&lt;/span&gt; ~
git clone https://github.com/xbill9/a2a-hello-world
&lt;span class="nb"&gt;cd &lt;/span&gt;a2a-hello-world
&lt;span class="nb"&gt;cd &lt;/span&gt;poly-rust
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run &lt;strong&gt;init.sh&lt;/strong&gt; from the cloned directory.&lt;/p&gt;

&lt;p&gt;The script will attempt to determine your shell environment and set the correct variables:&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;source &lt;/span&gt;init.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your session times out or you need to re-authenticate- you can run the &lt;strong&gt;set_env.sh&lt;/strong&gt; script to reset your environment variables:&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;source &lt;/span&gt;set_env.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Variables like PROJECT_ID need to be setup for use in the various build scripts- so the &lt;strong&gt;set_env&lt;/strong&gt; script can be used to reset the environment if you time-out.&lt;/p&gt;

&lt;h4&gt;
  
  
  Rust A2A Libraries
&lt;/h4&gt;

&lt;p&gt;There are several crates that provide A2A support. This project uses the a2a-rs crate:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://crates.io/crates/a2a-rs" rel="noopener noreferrer"&gt;crates.io: Rust Package Registry&lt;/a&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%2F81eznifwit6ot5ni1kef.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%2F81eznifwit6ot5ni1kef.png" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is a sample Cargo.TOML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[dependencies]&lt;/span&gt;
&lt;span class="py"&gt;tokio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"^1.37.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;features&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"full"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="py"&gt;anyhow&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1.0.86"&lt;/span&gt;
&lt;span class="py"&gt;a2a-rs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.1.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;features&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"full"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="py"&gt;futures&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.3"&lt;/span&gt;
&lt;span class="py"&gt;async-trait&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.1.80"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Minimal System Information Tool Build
&lt;/h4&gt;

&lt;p&gt;The first step is to build the basic tool directly with Rust. This allows the tool to be debugged and tested locally before adding the MCP layer.&lt;/p&gt;

&lt;p&gt;First build the tool locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;xbill@penguin&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;~/a2a-hello-world/poly-rust$ make&lt;/span&gt;
&lt;span class="err"&gt;Building&lt;/span&gt; &lt;span class="err"&gt;the&lt;/span&gt; &lt;span class="err"&gt;Rust&lt;/span&gt; &lt;span class="err"&gt;project...&lt;/span&gt;
    &lt;span class="err"&gt;Finished&lt;/span&gt; &lt;span class="err"&gt;`dev`&lt;/span&gt; &lt;span class="err"&gt;profile&lt;/span&gt; &lt;span class="err"&gt;[unoptimized&lt;/span&gt; &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="err"&gt;debuginfo]&lt;/span&gt; &lt;span class="err"&gt;target(s)&lt;/span&gt; &lt;span class="err"&gt;in&lt;/span&gt; &lt;span class="err"&gt;0.28s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then lint check the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;xbill@penguin&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;~/a2a-hello-world/poly-rust$ make lint&lt;/span&gt;
&lt;span class="err"&gt;Linting&lt;/span&gt; &lt;span class="err"&gt;code...&lt;/span&gt;
    &lt;span class="err"&gt;Finished&lt;/span&gt; &lt;span class="err"&gt;`dev`&lt;/span&gt; &lt;span class="err"&gt;profile&lt;/span&gt; &lt;span class="err"&gt;[unoptimized&lt;/span&gt; &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="err"&gt;debuginfo]&lt;/span&gt; &lt;span class="err"&gt;target(s)&lt;/span&gt; &lt;span class="err"&gt;in&lt;/span&gt; &lt;span class="err"&gt;0.29s&lt;/span&gt;
&lt;span class="err"&gt;Checking&lt;/span&gt; &lt;span class="err"&gt;formatting...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and run local tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="err"&gt;1&lt;/span&gt; &lt;span class="err"&gt;make&lt;/span&gt; &lt;span class="err"&gt;test&lt;/span&gt;

  &lt;span class="nl"&gt;The output confirms that the tests are being picked up and passing&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;

   &lt;span class="err"&gt;1&lt;/span&gt; &lt;span class="err"&gt;running&lt;/span&gt; &lt;span class="err"&gt;2&lt;/span&gt; &lt;span class="err"&gt;tests&lt;/span&gt;
   &lt;span class="nl"&gt;2 test tests&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;test_simple_agent_handler_creation ... ok&lt;/span&gt;
   &lt;span class="nl"&gt;3 test tests&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;test_task_creation ... ok&lt;/span&gt;
   &lt;span class="err"&gt;4&lt;/span&gt;
   &lt;span class="nl"&gt;5 test result&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in&lt;/span&gt;
     0.00s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last step is to build the production version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;xbill@penguin&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;~/a2a-hello-world/poly-rust$ make release&lt;/span&gt;
&lt;span class="err"&gt;Building&lt;/span&gt; &lt;span class="err"&gt;Release...&lt;/span&gt;
    &lt;span class="err"&gt;Finished&lt;/span&gt; &lt;span class="err"&gt;`release`&lt;/span&gt; &lt;span class="err"&gt;profile&lt;/span&gt; &lt;span class="err"&gt;[optimized]&lt;/span&gt; &lt;span class="err"&gt;target(s)&lt;/span&gt; &lt;span class="err"&gt;in&lt;/span&gt; &lt;span class="err"&gt;0.21s&lt;/span&gt;
&lt;span class="nl"&gt;xbill@penguin&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;~/a2a-hello-world/poly-rust$&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The A2A server can be started locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;xbill@penguin&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;~/a2a-hello-world/poly-rust$ make start&lt;/span&gt;
&lt;span class="err"&gt;Starting&lt;/span&gt; &lt;span class="err"&gt;the&lt;/span&gt; &lt;span class="err"&gt;A2A&lt;/span&gt; &lt;span class="err"&gt;Rust&lt;/span&gt; &lt;span class="err"&gt;server&lt;/span&gt; &lt;span class="err"&gt;on&lt;/span&gt; &lt;span class="err"&gt;port&lt;/span&gt; &lt;span class="err"&gt;8080...&lt;/span&gt;
   &lt;span class="err"&gt;Compiling&lt;/span&gt; &lt;span class="err"&gt;a2a-server-rust&lt;/span&gt; &lt;span class="err"&gt;v0.2.0&lt;/span&gt; &lt;span class="err"&gt;(/home/xbill/a2a-hello-world/poly-rust)&lt;/span&gt;
    &lt;span class="err"&gt;Finished&lt;/span&gt; &lt;span class="err"&gt;`dev`&lt;/span&gt; &lt;span class="err"&gt;profile&lt;/span&gt; &lt;span class="err"&gt;[unoptimized&lt;/span&gt; &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="err"&gt;debuginfo]&lt;/span&gt; &lt;span class="err"&gt;target(s)&lt;/span&gt; &lt;span class="err"&gt;in&lt;/span&gt; &lt;span class="err"&gt;0.93s&lt;/span&gt;
     &lt;span class="err"&gt;Running&lt;/span&gt; &lt;span class="err"&gt;`target/debug/a2a-server-rust`&lt;/span&gt;
&lt;span class="err"&gt;🚀&lt;/span&gt; &lt;span class="err"&gt;Starting&lt;/span&gt; &lt;span class="err"&gt;A2A&lt;/span&gt; &lt;span class="err"&gt;Rust&lt;/span&gt; &lt;span class="err"&gt;Server&lt;/span&gt;
&lt;span class="err"&gt;==============================&lt;/span&gt;
&lt;span class="nl"&gt;🌐 Starting HTTP server on 0.0.0.0&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;8080...&lt;/span&gt;
&lt;span class="nl"&gt;🔗 HTTP server listening on http&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;//0.0.0.0:8080&lt;/span&gt;
&lt;span class="nl"&gt;2026-05-17T20&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;45:52.176751Z INFO main ThreadId(01) start{server.address=0.0.0.0:8080 server.has_auth=false}: a2a_rs::adapter::transport::http::server: Starting HTTP server&lt;/span&gt;
&lt;span class="nl"&gt;2026-05-17T20&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;45:52.176972Z INFO main ThreadId(01) start{server.address=0.0.0.0:8080 server.has_auth=false}: a2a_rs::adapter::transport::http::server: HTTP server listening on 0.0.0.0:8080&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Check The Local Agent Status
&lt;/h4&gt;

&lt;p&gt;The project has a target to verify that the A2A server started:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;xbill@penguin&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;~/a2a-hello-world/poly-rust$ make status&lt;/span&gt;
&lt;span class="err"&gt;---&lt;/span&gt; &lt;span class="err"&gt;Project&lt;/span&gt; &lt;span class="err"&gt;Configuration&lt;/span&gt; &lt;span class="err"&gt;---&lt;/span&gt;
&lt;span class="nl"&gt;Project ID&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;comglitn&lt;/span&gt;
&lt;span class="nl"&gt;Service&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;a2a-server-rust&lt;/span&gt;
&lt;span class="nl"&gt;Region&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;us-central1&lt;/span&gt;

&lt;span class="err"&gt;---&lt;/span&gt; &lt;span class="err"&gt;Service&lt;/span&gt; &lt;span class="err"&gt;Status&lt;/span&gt; &lt;span class="err"&gt;---&lt;/span&gt;
&lt;span class="nl"&gt;Local (8080)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;ONLINE (A2A Rust Agent)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  A2A Inspector
&lt;/h4&gt;

&lt;p&gt;The A2A Inspector provides a tool to verify A2A operations.&lt;/p&gt;

&lt;p&gt;Background information is here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://discuss.google.dev/t/announcing-the-a2a-inspector-a-ui-tool-for-a2a-protocol-development/242240" rel="noopener noreferrer"&gt;Announcing the A2A Inspector: A UI tool for A2A protocol development&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GitHub Repo is here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/a2aproject/a2a-inspector" rel="noopener noreferrer"&gt;GitHub - a2aproject/a2a-inspector: Validation Tools for A2A Agents&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Verify The Local A2A Installation
&lt;/h4&gt;

&lt;p&gt;Start the A2A Inspector and use localhost:8080:&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%2Fjlnxmsrefvqf8uacemi1.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%2Fjlnxmsrefvqf8uacemi1.png" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should see the details of the Agent Card:&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;"capabilities"&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;"pushNotifications"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"stateTransitionHistory"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"streaming"&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="nl"&gt;"defaultInputModes"&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;"text"&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;"defaultOutputModes"&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;"text"&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;"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;"An A2A agent using the a2a-rs crate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"documentationUrl"&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://example.org/docs"&lt;/span&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;"A2A Rust Agent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"preferredTransport"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"JSONRPC"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"protocolVersion"&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.3.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;"provider"&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;"organization"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Example Organization"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"url"&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://example.org"&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;"skills"&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;"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;"Echoes back the user's message"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"examples"&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;"Echo: Hello World"&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;"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;"echo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"inputModes"&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;"text"&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;"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;"Echo Skill"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"outputModes"&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;"text"&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;"tags"&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;"echo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"respond"&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;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://0.0.0.0:8080"&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="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;h4&gt;
  
  
  Test the Local A2A Connection Locally
&lt;/h4&gt;

&lt;p&gt;This step tests the A2A agent interactions with a test script:&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="err"&gt;xbill@penguin:~/a&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="err"&gt;a-hello-world/poly-rust$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;make&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;card&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;Fetching&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;local&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;agent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;card...&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;"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;"A2A Rust Agent"&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;"An A2A agent using the a2a-rs crate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://0.0.0.0:8080"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"provider"&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;"organization"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Example Organization"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"url"&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://example.org"&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;"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;"protocolVersion"&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.3.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;"preferredTransport"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"JSONRPC"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"documentationUrl"&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://example.org/docs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"capabilities"&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;"streaming"&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="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"pushNotifications"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"stateTransitionHistory"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&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;"defaultInputModes"&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;"text"&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;"defaultOutputModes"&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;"text"&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;"skills"&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;"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;"echo"&lt;/span&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;"Echo Skill"&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;"Echoes back the user's message"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"tags"&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;"echo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"respond"&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;"examples"&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;"Echo: Hello World"&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;"inputModes"&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;"text"&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;"outputModes"&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;"text"&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="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;xbill@penguin:~/a&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="err"&gt;a-hello-world/poly-rust$&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  So What Just Happened?
&lt;/h4&gt;

&lt;p&gt;The &lt;strong&gt;Rust A2A&lt;/strong&gt; agent was started locally. This agent provided a standard A2A agent card. Then, test scripts performed a A2A skills call against the locally running Rust A2A server. Because the A2A server in Rust provides standard tools- the A2A inspector could connect. The actual implementation language of the A2A code does not matter — as long as standard services are exposed.&lt;/p&gt;

&lt;h4&gt;
  
  
  Deploy to Google Cloud Run
&lt;/h4&gt;

&lt;p&gt;Once the Agent has been validated and tested locally- the solution can be deployed to Google Cloud Run. Run the deploy target in the Makefile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;xbill@penguin&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;~/a2a-hello-world/poly-rust$ make deploy&lt;/span&gt;
&lt;span class="err"&gt;Submitting&lt;/span&gt; &lt;span class="err"&gt;build&lt;/span&gt; &lt;span class="err"&gt;to&lt;/span&gt; &lt;span class="err"&gt;Google&lt;/span&gt; &lt;span class="err"&gt;Cloud&lt;/span&gt; &lt;span class="err"&gt;Build...&lt;/span&gt;
&lt;span class="err"&gt;Creating&lt;/span&gt; &lt;span class="err"&gt;temporary&lt;/span&gt; &lt;span class="err"&gt;archive&lt;/span&gt; &lt;span class="err"&gt;of&lt;/span&gt; &lt;span class="err"&gt;2877&lt;/span&gt; &lt;span class="err"&gt;file(s)&lt;/span&gt; &lt;span class="err"&gt;totalling&lt;/span&gt; &lt;span class="err"&gt;1.6&lt;/span&gt; &lt;span class="err"&gt;GiB&lt;/span&gt; &lt;span class="err"&gt;before&lt;/span&gt; &lt;span class="err"&gt;compression.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the Cloud build finishs- you can check the status of the build:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Step #1: Already have image (with digest): gcr.io/cloud-builders/gcloud
Step #1: Deploying container to Cloud Run service [a2a-server-rust] in project [comglitn] region [us-central1]
Step #1: Deploying...
Step #1: Setting IAM Policy.............done
Step #1: Creating Revision....................................................done
Step #1: Routing traffic.....done
Step #1: Done.
Step #1: Service [a2a-server-rust] revision [a2a-server-rust-00003-8vv] has been deployed and is serving 100 percent of traffic.
Step #1: Service URL: https://a2a-server-rust-1056842563084.us-central1.run.app
Finished Step #1
PUSH
DONE
--------------------------------------------------------------------------------------------------------------------
ID CREATE_TIME DURATION SOURCE IMAGES STATUS
97f585da-538b-44cb-ac66-dc6ec59b6729 2026-05-18T02:44:23+00:00 9M38S gs://comglitn_cloudbuild/source/1779072007.831696-05e1368e282b4d199a1f4f7b25492a98.tgz - SUCCESS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the build is done — you can check the status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;xbill@penguin&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;~/a2a-hello-world/poly-rust$ make status&lt;/span&gt;
&lt;span class="err"&gt;---&lt;/span&gt; &lt;span class="err"&gt;Project&lt;/span&gt; &lt;span class="err"&gt;Configuration&lt;/span&gt; &lt;span class="err"&gt;---&lt;/span&gt;
&lt;span class="nl"&gt;Project ID&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;comglitn&lt;/span&gt;
&lt;span class="nl"&gt;Service&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;a2a-server-rust&lt;/span&gt;
&lt;span class="nl"&gt;Region&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;us-central1&lt;/span&gt;

&lt;span class="err"&gt;---&lt;/span&gt; &lt;span class="err"&gt;Service&lt;/span&gt; &lt;span class="err"&gt;Status&lt;/span&gt; &lt;span class="err"&gt;---&lt;/span&gt;
&lt;span class="nl"&gt;Local (8080)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;ONLINE (A2A Rust Agent)&lt;/span&gt;
&lt;span class="nl"&gt;Remote (Cloud)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;ONLINE (A2A Rust Agent) - https://a2a-server-rust-fgasxpwzoq-uc.a.run.app&lt;/span&gt;
&lt;span class="nl"&gt;xbill@penguin&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;~/a2a-hello-world/poly-rust$ &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and get the endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;xbill@penguin&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;~/a2a-hello-world/poly-rust$ make endpoint&lt;/span&gt;
&lt;span class="nl"&gt;https&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;//a2a-server-rust-fgasxpwzoq-uc.a.run.app&lt;/span&gt;
&lt;span class="nl"&gt;xbill@penguin&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;~/a2a-hello-world/poly-rust$ &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Verify the Cloud Run Service
&lt;/h4&gt;

&lt;p&gt;The Rust A2A service will be visible from the Cloud Run setup in Google Cloud:&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%2F2gz864ehf537ueo73x03.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%2F2gz864ehf537ueo73x03.png" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Testing Cloud Run Deployment
&lt;/h4&gt;

&lt;p&gt;The Makefile has several tools for validating the remote A2A server.&lt;/p&gt;

&lt;p&gt;First — you can get the remote Agent card:&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="err"&gt;xbill@penguin:~/a&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="err"&gt;a-hello-world/poly-rust$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;make&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;card-remote&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;Fetching&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;remote&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;agent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;card...&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;"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;"A2A Rust Agent"&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;"An A2A agent using the a2a-rs crate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://0.0.0.0:8080"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"provider"&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;"organization"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Example Organization"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"url"&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://example.org"&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;"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;"protocolVersion"&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.3.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;"preferredTransport"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"JSONRPC"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"documentationUrl"&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://example.org/docs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"capabilities"&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;"streaming"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"pushNotifications"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"stateTransitionHistory"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&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;"defaultInputModes"&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;"text"&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;"defaultOutputModes"&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;"text"&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;"skills"&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;"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;"echo"&lt;/span&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;"Echo Skill"&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;"Echoes back the user's message"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"tags"&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;"echo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"respond"&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;"examples"&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;"Echo: Hello World"&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;"inputModes"&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;"text"&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;"outputModes"&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;"text"&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="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;and run a basic test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;xbill@penguin&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;~/a2a-hello-world/poly-rust$ make a2a-remote&lt;/span&gt;
&lt;span class="err"&gt;Running&lt;/span&gt; &lt;span class="err"&gt;remote&lt;/span&gt; &lt;span class="err"&gt;A2A&lt;/span&gt; &lt;span class="err"&gt;echo&lt;/span&gt; &lt;span class="err"&gt;test...&lt;/span&gt;
&lt;span class="nl"&gt;🚀 Testing A2A Echo Skill at https&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;//a2a-server-rust-fgasxpwzoq-uc.a.run.app&lt;/span&gt;
&lt;span class="nl"&gt;💬 Sending message&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;'Hello from the test program!'&lt;/span&gt;
&lt;span class="nl"&gt;✅ Received echo&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;'Echo: Hello from the test program!'&lt;/span&gt;
&lt;span class="err"&gt;🌟&lt;/span&gt; &lt;span class="err"&gt;Success!&lt;/span&gt; &lt;span class="err"&gt;The&lt;/span&gt; &lt;span class="err"&gt;echo&lt;/span&gt; &lt;span class="err"&gt;skill&lt;/span&gt; &lt;span class="err"&gt;is&lt;/span&gt; &lt;span class="err"&gt;working&lt;/span&gt; &lt;span class="err"&gt;correctly.&lt;/span&gt;
&lt;span class="nl"&gt;xbill@penguin&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;~/a2a-hello-world/poly-rust$ &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Crates.io
&lt;/h4&gt;

&lt;p&gt;The full package is available on GitHub and crates.io:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://crates.io/crates/a2a-server-rust" rel="noopener noreferrer"&gt;crates.io: Rust Package Registry&lt;/a&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%2Fysun5vlm83ssip01xnyp.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%2Fysun5vlm83ssip01xnyp.png" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Summary
&lt;/h4&gt;

&lt;p&gt;A complete A2A server was built using Rust. Basic validation was done with the A2A inspector. Next, test scripts was built that directly called the Rust A2A server. Finally, the complete solution was deployed to Google Cloud Run.&lt;/p&gt;




</description>
      <category>rust</category>
      <category>gemini</category>
      <category>googlecloudrun</category>
      <category>a2aprotocol</category>
    </item>
    <item>
      <title>Build a Socratic Study Buddy with Gemma 4: A Beginner’s Guide to Running AI Locally</title>
      <dc:creator>leslysandra</dc:creator>
      <pubDate>Mon, 18 May 2026 01:21:13 +0000</pubDate>
      <link>https://forem.com/gde/build-a-socratic-study-buddy-with-gemma-4-a-beginners-guide-to-running-ai-locally-505a</link>
      <guid>https://forem.com/gde/build-a-socratic-study-buddy-with-gemma-4-a-beginners-guide-to-running-ai-locally-505a</guid>
      <description>&lt;p&gt;The landscape of AI has shifted from "bigger is better" to "smarter is better." We are entering the era of &lt;strong&gt;intelligence-per-parameter&lt;/strong&gt;—a metric of how much reasoning power is packed into a compact model. Gemma 4, built on the latest research from Google DeepMind, brings high-level, multi-step reasoning directly to your own hardware.&lt;/p&gt;

&lt;p&gt;This guide will show you how to build a Socratic Study Buddy—a tutor that doesn't just give you answers but helps you think through problems—while keeping your data 100% private using a custom local web interface.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;I built a local &lt;strong&gt;Socratic Study Buddy&lt;/strong&gt; application. It pairs the localized inference engine of LM Studio with a custom-built &lt;strong&gt;Streamlit Web UI&lt;/strong&gt; frontend. Instead of acting as a lazy "answer engine" that does a student's homework for them, this tool forces the underlying Gemma 4 model to plan pedagogical strategies and use structured dialogue to guide critical thinking.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Gemma 4 Matters for Learning
&lt;/h2&gt;

&lt;p&gt;Gemma 4 is a "Thinking Model." Older AI models functioned like advanced autocomplete, predicting the next word based on patterns. Gemma 4 has the capacity for a native &lt;strong&gt;Chain-of-Reasoning&lt;/strong&gt; process.&lt;/p&gt;

&lt;p&gt;Instead of jumping straight to an answer, Gemma 4 works through logical steps internally before it speaks. This makes it a perfect mentor. While other models might just do your homework, Gemma 4 is trained to identify where you are stuck and nudge you toward the solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing Your Brain: The Official Model Sizes
&lt;/h2&gt;

&lt;p&gt;To run this locally, you need to pick the right "size" for your computer. Gemma 4 comes in four official variants:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Effective 2B (E2B)&lt;/strong&gt;: Tiny and lightning-fast. Optimized for high-end phones or older laptops with 4GB–8GB of RAM.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Effective 4B (E4B)&lt;/strong&gt;: The "Sweet Spot" for most modern laptops with 8GB–12GB of RAM. This is the entry point for high-quality image and audio understanding.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;26B A4B (Mixture-of-Experts)&lt;/strong&gt;: The speed demon. It has 26 billion parameters but only uses 4 billion at a time to answer. You get high-quality reasoning with fast speeds. Requires 16GB–24GB of RAM.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;31B Dense&lt;/strong&gt;: The flagship. This is the smartest model in the family, providing maximum reasoning quality for complex math. Use this if you have a powerful workstation with 32GB+ of RAM.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setup: Bringing the Brain to Your Frontend
&lt;/h2&gt;

&lt;p&gt;Instead of staying restricted to standard desktop setups, we bridge the model into a lightweight web dashboard.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1. Weight Retrieval &amp;amp; Backend Hosting
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Search for Gemma 4&lt;/strong&gt;: Open &lt;a href="https://lmstudio.ai/" rel="noopener noreferrer"&gt;LM Studio&lt;/a&gt; and click the Magnifying Glass. Type &lt;code&gt;"Gemma 4"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Select a GGUF&lt;/strong&gt;: Look for files labeled &lt;strong&gt;GGUF&lt;/strong&gt; (a compressed file format that lets heavy models run on consumer hardware).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Choose Your Quantization&lt;/strong&gt;: Look for &lt;strong&gt;Q4_K_M&lt;/strong&gt; (a version that balances intelligence with low memory usage).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Start the Local Server:&lt;/strong&gt;: Head to the Local Server tab in LM Studio, load your downloaded model, ensure your &lt;code&gt;system prompts&lt;/code&gt; are injected, and start the service on port &lt;code&gt;1234&lt;/code&gt;. Turn &lt;strong&gt;GPU Offload&lt;/strong&gt; to "Max" to leverage your graphics card.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2. Running the Custom Web UI
&lt;/h3&gt;

&lt;p&gt;To spin up the clean web chat interface shown below, clone the repository, install the dependencies, and launch the frontend file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;streamlit openai
streamlit run app.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Here is how the complete architecture interacts within the custom Python frontend workspace:&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%2Fc50llw3ri2957mm8c3zt.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%2Fc50llw3ri2957mm8c3zt.png" alt=" " width="800" height="664"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The UI Environment Overview
&lt;/h3&gt;

&lt;p&gt;The implementation splits backend configuration details directly away from the active learning space, allowing seamless swaps between running models:&lt;/p&gt;

&lt;h4&gt;
  
  
  The Project: The Socratic Study Buddy Prompt
&lt;/h4&gt;

&lt;p&gt;In your local configuration workspace or the core application prompt files, we pass this instruction using the official &lt;code&gt;&amp;lt;|think|&amp;gt;&lt;/code&gt; control token sequence to isolate the reasoning channel:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;|think|&amp;gt;
You are an expert academic tutor. You are forbidden from giving the final answer. Instead, use your internal reasoning to identify the core concept the student is struggling with and ask guiding questions.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  The "Thinking" Advantage in Action
&lt;/h4&gt;

&lt;p&gt;When you ask the web component: &lt;em&gt;"I don't understand how recursion works in coding."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Gemma 4 enters its &lt;strong&gt;Internal Thought Channel&lt;/strong&gt;. Within your local terminal execution or dashboard view, you will see it process its strategy before printing its output:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Gemma 4 (Internal Reasoning)&lt;/strong&gt;: The user wants to know recursion. Giving code directly violates the Socratic constraint. I will use a structural stack analogy, like a line of people or nesting boxes, to force them to identify the concept of a terminating condition.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Tutor Output Response:
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;"To understand recursion, we first need to understand a 'base case.' If you were standing in a line of people, how would you know your position without counting everyone yourself?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Beyond Chat: Real-World Visuals
&lt;/h3&gt;

&lt;p&gt;One of the best ways to study is to visualize logic. You can ask your Study Buddy to &lt;code&gt;"Draw the logic of this concept."&lt;/code&gt; It will generate clean &lt;strong&gt;Mermaid.js&lt;/strong&gt; code directly in the conversation panel:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;User:&lt;/strong&gt; "Show me the logic of the Socratic method we just used."&lt;br&gt;
&lt;strong&gt;Gemma 4:&lt;/strong&gt; "Here is the flowchart of our session:"&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;graph TD
    A[Student Asks Question] --&amp;gt; B{Model Thinks}
    B --&amp;gt; C[Identify Missing Concept]
    C --&amp;gt; D[Ask Guiding Question]
    D --&amp;gt; E[Student Responds]
    E --&amp;gt;|Correct| F[Nudge to Next Step]
    E --&amp;gt;|Incorrect| G[Simplify Analogy]
&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%2Fjvxfuah6ufdmll4vbkxk.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%2Fjvxfuah6ufdmll4vbkxk.png" alt=" " width="800" height="755"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;The entire layout—including the Python automation scripts, system prompt templates, configurations, and the Streamlit frontend architecture—is completely open-source:&lt;br&gt;
👉 Check out the GitHub Repository &lt;a href="https://github.com/leslysandra/socratic-study-buddy-gemma4" rel="noopener noreferrer"&gt;Here&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Digital Sovereignty &amp;amp; Ethical AI Safety
&lt;/h2&gt;

&lt;p&gt;Building with open-source models like Gemma 4 is a foundational ethical choice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Privacy (Digital Sovereignty)&lt;/strong&gt;: Every question you ask stays on your machine. Your learning struggles aren't being used to train a corporate model.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Trade-off&lt;/strong&gt;: Unlike cloud models, a local model is your responsibility. You must verify its facts, as it doesn't have an external "safety filter" monitoring the conversation.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Advantages:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Transparency: You can inspect the weights and the "thinking" process, which is impossible with closed-source models.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Privacy: Since it runs locally in LM Studio or on your private GKE cluster, your data never leaves your environment.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Disadvantages:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Resource Intensity: High-reasoning models still require significant compute power compared to lightweight "dumb" bots.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Guardrail Responsibility: Unlike a managed API that filters every word, an open-source model places the "Safety Filter" responsibility on you. You must implement your own output classifiers to ensure the model stays within educational boundaries.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;You’ve gone from raw local model files to running a custom, world-class educational reasoning platform directly on your laptop. You’ve built an app that doesn't just echo stored training text—it actively fosters critical thinking.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your Challenge:&lt;/strong&gt; Use your newly built Web UI Study Buddy to tackle a topic you’ve always found intimidating—maybe organic chemistry or financial engineering. How does having an interface powered by a "Thinking Model" change the way you interact with complex documentation?&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Next Steps:&lt;/strong&gt; Ready to scale from a chat interface to fully autonomous pipelines? Check out the &lt;a href="https://patloeber.com/gemma-4-pi-agent/" rel="noopener noreferrer"&gt;Pi Coding Agent by Patrick Loeber&lt;/a&gt;—a minimal terminal client that bridges local Gemma 4 instances straight to your terminal environment so it can write, debug, and run code directly for you!&lt;/p&gt;

</description>
      <category>gemma</category>
      <category>handson</category>
      <category>lmstudio</category>
      <category>ai</category>
    </item>
    <item>
      <title>Deploying a Rust MCP Server to Azure Appservice</title>
      <dc:creator>xbill</dc:creator>
      <pubDate>Sun, 17 May 2026 12:39:30 +0000</pubDate>
      <link>https://forem.com/gde/deploying-a-rust-mcp-server-to-azure-appservice-g9c</link>
      <guid>https://forem.com/gde/deploying-a-rust-mcp-server-to-azure-appservice-g9c</guid>
      <description>&lt;p&gt;The rmcp crate and standard Rust libraries are used to build a basic MCP Server in Rust. This MCP Server is then built and deployed to Azure Appservice and validated locally with Gemini CLI.&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%2Fsn88v76qra6y1mj8uk5e.jpeg" 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%2Fsn88v76qra6y1mj8uk5e.jpeg" width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  What?! Yet Another MCP Demo?
&lt;/h4&gt;

&lt;p&gt;All your base belong to us.&lt;/p&gt;

&lt;h4&gt;
  
  
  Why not just use Python?
&lt;/h4&gt;

&lt;p&gt;Python has traditionally been the main coding language for ML and AI tools. One of the strengths of the MCP protocol is that the actual implementation details are independent of the development language. The reality is that not every project is coded in Python- and MCP allows you to use the latest AI appt roaches with other coding languages.&lt;/p&gt;

&lt;h4&gt;
  
  
  What is this Tutorial Trying to Do?
&lt;/h4&gt;

&lt;p&gt;Building on previous tutorials, the goal is to extend a Rust MCP server with basic support for deployment to Azure.&lt;/p&gt;

&lt;h4&gt;
  
  
  What is Rust?
&lt;/h4&gt;

&lt;p&gt;Rust is a high performance, memory safe, compiled language:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.rust-lang.org/" rel="noopener noreferrer"&gt;Rust&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Rust provides memory safe operations beyond C/C++ and also can provide exceptional performance gains as it is compiled directly to native binaries.&lt;/p&gt;

&lt;h4&gt;
  
  
  So Why Am I reading this?
&lt;/h4&gt;

&lt;p&gt;So what is different about this lab compared to all the others out there?&lt;/p&gt;

&lt;p&gt;This is one of the first deep dives into deploying a Rust based MCP server hosted on Azure. The Azure ACI service was targeted for compatibility with Docker Images.&lt;/p&gt;

&lt;h4&gt;
  
  
  Rust Setup
&lt;/h4&gt;

&lt;p&gt;Instructions to install Rust are available here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.rust-lang.org/learn/get-started" rel="noopener noreferrer"&gt;Getting started&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For a Linux like environment the command looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl — proto ‘&lt;span class="o"&gt;=&lt;/span&gt;https’ — tlsv1.2 &lt;span class="nt"&gt;-sSf&lt;/span&gt; https://sh.rustup.rs | sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rust also depends on a working C compiler and OpenSSL setup. For a Debian 12 system — install the basic tools for development:&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;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;build-essential
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;libssl-dev
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;pkg-config
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;libudev-dev
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;make
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Gemini CLI
&lt;/h4&gt;

&lt;p&gt;If not pre-installed you can download the Gemini CLI to interact with the source files and provide real-time assistance:&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/gemini-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Testing the Gemini CLI Environment
&lt;/h4&gt;

&lt;p&gt;Once you have all the tools and the correct Node.js version in place- you can test the startup of Gemini CLI. You will need to authenticate with a Key or your Google Account:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;▝▜▄ Gemini CLI v0.33.1
    ▝▜▄
   ▗▟▀ Logged in with Google /auth
  ▝▀ Gemini Code Assist Standard /upgrade no sandbox (see /docs) /model Auto (Gemini 3) | 239.8 MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Azure App Service
&lt;/h3&gt;

&lt;p&gt;Azure App Service is a fully managed Platform-as-a-Service (PaaS) that enables developers to build, deploy, and scale web applications, APIs, and mobile backends quickly. It supports multiple languages (&lt;a href="https://www.google.com/search?q=.NET&amp;amp;rlz=1CAIWTJ_enUS1155&amp;amp;oq=what+is+azure+app+service&amp;amp;gs_lcrp=EgZjaHJvbWUyBggAEEUYOTIHCAEQABiABDIHCAIQABiABDIHCAMQABiABDIHCAQQABiABDIHCAUQABiABDIICAYQABgWGB4yCAgHEAAYFhgeMggICBAAGBYYHjIICAkQABgWGB7SAQgzNzkzajBqN6gCALACAA&amp;amp;sourceid=chrome&amp;amp;ie=UTF-8&amp;amp;ved=2ahUKEwiLxOi4mKWTAxUfkYkEHW3NNloQgK4QegYIAQgAEAQ" rel="noopener noreferrer"&gt;.NET&lt;/a&gt;, &lt;a href="https://www.google.com/search?q=Java&amp;amp;rlz=1CAIWTJ_enUS1155&amp;amp;oq=what+is+azure+app+service&amp;amp;gs_lcrp=EgZjaHJvbWUyBggAEEUYOTIHCAEQABiABDIHCAIQABiABDIHCAMQABiABDIHCAQQABiABDIHCAUQABiABDIICAYQABgWGB4yCAgHEAAYFhgeMggICBAAGBYYHjIICAkQABgWGB7SAQgzNzkzajBqN6gCALACAA&amp;amp;sourceid=chrome&amp;amp;ie=UTF-8&amp;amp;ved=2ahUKEwiLxOi4mKWTAxUfkYkEHW3NNloQgK4QegYIAQgAEAU" rel="noopener noreferrer"&gt;Java&lt;/a&gt;, &lt;a href="https://www.google.com/search?q=Node.js&amp;amp;rlz=1CAIWTJ_enUS1155&amp;amp;oq=what+is+azure+app+service&amp;amp;gs_lcrp=EgZjaHJvbWUyBggAEEUYOTIHCAEQABiABDIHCAIQABiABDIHCAMQABiABDIHCAQQABiABDIHCAUQABiABDIICAYQABgWGB4yCAgHEAAYFhgeMggICBAAGBYYHjIICAkQABgWGB7SAQgzNzkzajBqN6gCALACAA&amp;amp;sourceid=chrome&amp;amp;ie=UTF-8&amp;amp;ved=2ahUKEwiLxOi4mKWTAxUfkYkEHW3NNloQgK4QegYIAQgAEAY" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt;, &lt;a href="https://www.google.com/search?q=Python&amp;amp;rlz=1CAIWTJ_enUS1155&amp;amp;oq=what+is+azure+app+service&amp;amp;gs_lcrp=EgZjaHJvbWUyBggAEEUYOTIHCAEQABiABDIHCAIQABiABDIHCAMQABiABDIHCAQQABiABDIHCAUQABiABDIICAYQABgWGB4yCAgHEAAYFhgeMggICBAAGBYYHjIICAkQABgWGB7SAQgzNzkzajBqN6gCALACAA&amp;amp;sourceid=chrome&amp;amp;ie=UTF-8&amp;amp;ved=2ahUKEwiLxOi4mKWTAxUfkYkEHW3NNloQgK4QegYIAQgAEAc" rel="noopener noreferrer"&gt;Python&lt;/a&gt;, PHP) on Windows or Linux, offering built-in CI/CD, auto-scaling, and high security.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://azure.microsoft.com/en-us/products/app-service" rel="noopener noreferrer"&gt;https://azure.microsoft.com/en-us/products/app-service&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The console will look similar to this:&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%2F25k8diq2s6jn64gh2ejg.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%2F25k8diq2s6jn64gh2ejg.png" width="700" height="394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Why would I want Gemini CLI with Azure? Isn’t that a Google Thing?
&lt;/h4&gt;

&lt;p&gt;Yes- Gemini CLI leverages the Google Cloud console and Gemini models but it is also open source and platform agnostic. Many applications are already cross-cloud so this enables familiar tools to be run natively on Microsoft Azure.&lt;/p&gt;

&lt;h4&gt;
  
  
  Azure CLI
&lt;/h4&gt;

&lt;p&gt;The Azure Command-Line Interface (CLI) is a cross-platform tool used to connect to Azure and execute administrative commands on your cloud resources. [&lt;a href="https://learn.microsoft.com/en-us/cli/azure/what-is-azure-cli?view=azure-cli-latest" rel="noopener noreferrer"&gt;1&lt;/a&gt;, &lt;a href="https://www.codemag.com/Article/2001021/Azure-CLI" rel="noopener noreferrer"&gt;2&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;It allows you to manage services like virtual machines, storage accounts, and networks through a terminal using either interactive prompts or automated scripts.&lt;/p&gt;

&lt;p&gt;More information is here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://learn.microsoft.com/en-us/cli/azure/what-is-azure-cli?view=azure-cli-latest" rel="noopener noreferrer"&gt;What is the Azure CLI?&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Setup the Basic Environment
&lt;/h4&gt;

&lt;p&gt;At this point you should have a working Rust environment and a working Gemini CLI installation. All of the relevant code examples and documentation is available in GitHub.&lt;/p&gt;

&lt;p&gt;The next step is to clone the GitHub repository to your local environment:&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;cd&lt;/span&gt; ~
git clone https://github.com/xbill9/gemini-cli-azure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run &lt;strong&gt;init.sh&lt;/strong&gt; from the cloned directory.&lt;/p&gt;

&lt;p&gt;The script will attempt to determine your shell environment and set the correct variables:&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;source &lt;/span&gt;init.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your session times out or you need to re-authenticate- you can run the &lt;strong&gt;set_env.sh&lt;/strong&gt; script to reset your environment variables:&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;source &lt;/span&gt;set_env.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Variables like PROJECT_ID need to be setup for use in the various build scripts- so the &lt;strong&gt;set_env&lt;/strong&gt; script can be used to reset the environment if you time-out.&lt;/p&gt;

&lt;p&gt;Refresh the Azure credentials:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;xbill@penguin:~/gemini-cli-azure/mcp-aci-rust-azure&lt;span class="nv"&gt;$ &lt;/span&gt;az login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally install the packages and dependencies:&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;cd&lt;/span&gt; ~/gemini-cli-azure/mcp-aci-rust-azure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Build The Rust MCP Server
&lt;/h4&gt;

&lt;p&gt;Some background information on building and configuring a Rust MCP server is here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/gde/building-a-secure-http-transport-mcp-server-with-rust-and-gemini-cli-l56"&gt;Building a Secure HTTP Transport MCP Server with Rust, and Gemini CLI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The mcp-appservice-rust-azure subdirectory has the complete Rust MCP server in one subdirectory.&lt;/p&gt;

&lt;h4&gt;
  
  
  Minimal System Information Tool Build
&lt;/h4&gt;

&lt;p&gt;The first step is to build the basic tool directly with Rust. This allows the tool to be debugged and tested locally before adding the MCP layer.&lt;/p&gt;

&lt;p&gt;First build the tool locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;xbill@penguin:~/gemini-cli-azure/mcp-appservice-rust-azure&lt;span class="nv"&gt;$ &lt;/span&gt;make
Building the Rust project...
    Finished &lt;span class="sb"&gt;`&lt;/span&gt;dev&lt;span class="sb"&gt;`&lt;/span&gt; profile &lt;span class="o"&gt;[&lt;/span&gt;unoptimized + debuginfo] target&lt;span class="o"&gt;(&lt;/span&gt;s&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in &lt;/span&gt;0.24s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then lint check the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;xbill@penguin:~/gemini-cli-azure/mcp-appservice-rust-azure&lt;span class="nv"&gt;$ &lt;/span&gt;make lint
Linting code...
    Finished &lt;span class="sb"&gt;`&lt;/span&gt;dev&lt;span class="sb"&gt;`&lt;/span&gt; profile &lt;span class="o"&gt;[&lt;/span&gt;unoptimized + debuginfo] target&lt;span class="o"&gt;(&lt;/span&gt;s&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in &lt;/span&gt;0.22s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and run local tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;xbill@penguin:~/gemini-cli-azure/mcp-appservice-rust-azure&lt;span class="nv"&gt;$ &lt;/span&gt;make &lt;span class="nb"&gt;test
&lt;/span&gt;Running tests...
   Compiling mcp-appservice-rust-azure v1.0.0 &lt;span class="o"&gt;(&lt;/span&gt;/home/xbill/gemini-cli-azure/mcp-appservice-rust-azure&lt;span class="o"&gt;)&lt;/span&gt;
    Finished &lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;test&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt; profile &lt;span class="o"&gt;[&lt;/span&gt;unoptimized + debuginfo] target&lt;span class="o"&gt;(&lt;/span&gt;s&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in &lt;/span&gt;4.12s
     Running unittests src/main.rs &lt;span class="o"&gt;(&lt;/span&gt;target/debug/deps/mcp_appservice_rust_azure-dfdea0b8d8bf4738&lt;span class="o"&gt;)&lt;/span&gt;

running 1 &lt;span class="nb"&gt;test
test &lt;/span&gt;tests::test_greeting ... ok

&lt;span class="nb"&gt;test &lt;/span&gt;result: ok. 1 passed&lt;span class="p"&gt;;&lt;/span&gt; 0 failed&lt;span class="p"&gt;;&lt;/span&gt; 0 ignored&lt;span class="p"&gt;;&lt;/span&gt; 0 measured&lt;span class="p"&gt;;&lt;/span&gt; 0 filtered out&lt;span class="p"&gt;;&lt;/span&gt; finished &lt;span class="k"&gt;in &lt;/span&gt;0.00s

xbill@penguin:~/gemini-cli-azure/mcp-appservice-rust-azure&lt;span class="nv"&gt;$ &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last step is to build the production version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;xbill@penguin:~/gemini-cli-azure/mcp-appservice-rust-azure&lt;span class="nv"&gt;$ &lt;/span&gt;make release
Building Release...
    Finished &lt;span class="sb"&gt;`&lt;/span&gt;release&lt;span class="sb"&gt;`&lt;/span&gt; profile &lt;span class="o"&gt;[&lt;/span&gt;optimized] target&lt;span class="o"&gt;(&lt;/span&gt;s&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in &lt;/span&gt;0.36s
xbill@penguin:~/gemini-cli-azure/mcp-appservice-rust-azure&lt;span class="err"&gt;$&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The MCP server can be started locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The MCP tool can then be tested locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🟢 local-rust - Ready (1 tool)
  Tools:
  - mcp_local-rust_greeting

&amp;gt; mcp_local-rust_greeting hello local

Executing Greeting Tool: Executing the greeting tool on the local Rust MCP server.

╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ greeting (local-rust MCP Server) {"message":"hello local"} │
│ │
│ Hello World MCP! hello local │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
  Greeting Completed: Greeting successful. Standing by for next instruction.

✦ Hello World MCP! hello local
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Deploy To Azure Appservice
&lt;/h4&gt;

&lt;p&gt;A basic Dockerfile is used to build an image for deployment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;xbill@penguin:~/gemini-cli-azure/mcp-appservice-rust-azure&lt;span class="nv"&gt;$ &lt;/span&gt;make deploy
Building the Docker image...
&lt;span class="o"&gt;[&lt;/span&gt;+] Building 2.2s &lt;span class="o"&gt;(&lt;/span&gt;14/14&lt;span class="o"&gt;)&lt;/span&gt; FINISHED docker:default
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;internal] load build definition from Dockerfile 0.0s
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; transferring dockerfile: 763B 0.0s 0.0s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Get the deployment status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;xbill@penguin:~/gemini-cli-azure/mcp-appservice-rust-azure&lt;span class="nv"&gt;$ &lt;/span&gt;make status
mcp-appservice-rust-azure is not running locally.
Checking App Service status &lt;span class="k"&gt;for &lt;/span&gt;mcp-app-penguin...
Name State HostNames
&lt;span class="nt"&gt;---------------&lt;/span&gt; &lt;span class="nt"&gt;-------&lt;/span&gt; &lt;span class="nt"&gt;---------------------------------&lt;/span&gt;
mcp-app-penguin Running mcp-app-penguin.azurewebsites.net
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Get the Endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;xbill@penguin:~/gemini-cli-azure/mcp-appservice-rust-azure&lt;span class="nv"&gt;$ &lt;/span&gt;make endpoint
https://mcp-app-penguin.azurewebsites.net
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check Gemini MCP settings:&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;"mcpServers"&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;"mcp-appservice-rust-azure"&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;"httpUrl"&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://mcp-app-penguin.azurewebsites.net/mcp"&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;"local-rust"&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;"httpUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://127.0.0.1:8080/mcp"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The service will be visible on the Azure console:&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%2Fkal26otv9gd6sqspkr0u.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%2Fkal26otv9gd6sqspkr0u.png" width="800" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Final Test
&lt;/h4&gt;

&lt;p&gt;Start up Gemini CLI and check the MCP server status:&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; /mcp list                                                                                                                                         

Configured MCP servers:

🟢 mcp-appservice-rust-azure - Ready (1 tool)
  Tools:
  - mcp_mcp-appservice-rust-azure_greeting


 &amp;gt; mcp_mcp-appservice-rust-azure_greeting Hello Appservice!

╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ greeting (mcp-appservice-rust-azure MCP Server) {"message":"Hello Appservice!"} │
│ │
│ Hello World MCP! Hello Appservice! │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

✦ OK. The greeting tool responded: "Hello World MCP! Hello Appservice!"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Summary
&lt;/h4&gt;

&lt;p&gt;A complete HTTP transport MCP server was built using Rust. This application was tested locally with Gemini CLI. Then, the entire solution was deployed to Azure Appservice. The remote MCP server was validated with Gemini CLI locally.&lt;/p&gt;

</description>
      <category>mcps</category>
      <category>rust</category>
      <category>azure</category>
      <category>azureappservice</category>
    </item>
    <item>
      <title>Building a Ride Analysis Web App with Antigravity and the Strava API</title>
      <dc:creator>Akira Kikusato</dc:creator>
      <pubDate>Sat, 16 May 2026 13:00:00 +0000</pubDate>
      <link>https://forem.com/gde/building-a-ride-analysis-web-app-with-antigravity-and-the-strava-api-439g</link>
      <guid>https://forem.com/gde/building-a-ride-analysis-web-app-with-antigravity-and-the-strava-api-439g</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;I ride bikes a lot these days, and like many cyclists I use Strava to log my rides. Even on the free tier it automatically syncs with smartwatches, cycling computers, and smart trainers, which is plenty for just keeping a record. But the more I learned about training, the more I wanted richer analytics and planning — and most of that lives behind Strava's paid subscription.&lt;/p&gt;

&lt;p&gt;While poking around, I noticed Strava offers a public &lt;a href="https://developers.strava.com/" rel="noopener noreferrer"&gt;Strava API&lt;/a&gt;. That was enough motivation to build my own analytics on top of it.&lt;/p&gt;

&lt;p&gt;Concretely, I wanted these features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ride and training management&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Review past rides … ①&lt;/li&gt;
&lt;li&gt;Visualize power and heart-rate distributions by intensity zone … ②&lt;/li&gt;
&lt;li&gt;View power and heart-rate traces color-coded by intensity zone … ③&lt;/li&gt;
&lt;li&gt;Show recent training load and fatigue to get a sense of current condition … ④&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Ride and training planning&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Build training plans by intensity and goal for upcoming events … ⑤&lt;/li&gt;
&lt;li&gt;Recommend the next workout based on recent condition (training load and fatigue) … ⑥&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;I built the app using Antigravity. There are two parts: the analytics app itself, and an agent that suggests the next workout based on recent condition. This post covers the analytics app. The agent will be a separate post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview of the App: "PerfRide"
&lt;/h2&gt;

&lt;p&gt;The result is a web app called &lt;strong&gt;PerfRide&lt;/strong&gt; that uses the Strava API to manage ride records and training plans for road cycling.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/kikuriyou" rel="noopener noreferrer"&gt;
        kikuriyou
      &lt;/a&gt; / &lt;a href="https://github.com/kikuriyou/PerfRide" rel="noopener noreferrer"&gt;
        PerfRide
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A performance management toolkit for road cyclists
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;PerfRide 🚴&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;A performance management toolkit for road cyclists, powered by the &lt;a href="https://developers.strava.com/" rel="nofollow noopener noreferrer"&gt;Strava API&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Simulate climbs, optimize race pacing, plan periodized training, and track your fitness — all in one app.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;📊 Dashboard&lt;/h3&gt;
&lt;/div&gt;
&lt;p&gt;Connect with Strava to view your recent rides, weekly training summary, and fitness progress chart (CTL / ATL / TSB). Includes per-ride detail with heart rate zones, power profile, and elevation overlay.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;🏔️ Climb Simulator&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;Predict climbing times based on power, weight, and real segment data. Uses physics-based simulation (air resistance, rolling resistance, drivetrain loss). Search segments by map or use your Strava starred segments.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;🎯 Pace Optimizer&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;Calculate optimal pacing strategy for time trials based on course elevation profile. Based on the research paper &lt;em&gt;"A numerical design methodology for optimal pacing strategy in the individual time trial discipline of cycling"&lt;/em&gt; (Sports Engineering, 2025).&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;📅 Training Planner&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;Generate periodized training plans for your target race…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/kikuriyou/PerfRide" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The main features (including some experimental ones) are:&lt;/p&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;Description&lt;/th&gt;
&lt;th&gt;Maps to&lt;/th&gt;
&lt;th&gt;Needs Strava&lt;/th&gt;
&lt;th&gt;Experimental&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Dashboard&lt;/td&gt;
&lt;td&gt;Activity list, Fitness/Fatigue/Form charts&lt;/td&gt;
&lt;td&gt;①, ②, ③, ④&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Weekly Plan&lt;/td&gt;
&lt;td&gt;This week's workout plan&lt;/td&gt;
&lt;td&gt;⑤, ⑥&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Climb Simulator&lt;/td&gt;
&lt;td&gt;Predicts climb time from power and weight using physics-based math&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pace Optimizer&lt;/td&gt;
&lt;td&gt;Computes optimal pacing based on a course profile&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Training Planner&lt;/td&gt;
&lt;td&gt;Generates a phased training plan working backward from a goal race&lt;/td&gt;
&lt;td&gt;⑤&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Settings&lt;/td&gt;
&lt;td&gt;User parameters: FTP, weight, max HR, etc.&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&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%2F2mjhum8d6z8c7xuty7yb.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%2F2mjhum8d6z8c7xuty7yb.png" alt="PerfRide landing page" width="800" height="567"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;PerfRide landing page&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Dashboard
&lt;/h3&gt;

&lt;p&gt;Once connected to Strava, the dashboard shows your recent rides and a weekly summary (ride count, distance, elevation gain, moving time). It also derives fitness metrics from roughly the last 13 weeks of activity data and visualizes the following three indicators along with trends in distance and elevation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fitness (CTL: Chronic Training Load)&lt;/strong&gt;: Long-term accumulated training load. Higher = better aerobic base.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fatigue (ATL: Acute Training Load)&lt;/strong&gt;: Fatigue from recent training. Higher = more tired.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Form (TSB: Training Stress Balance)&lt;/strong&gt;: Fitness − Fatigue. Indicates how race-ready you are (+10 to +25 is generally considered optimal for racing).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Clicking on a ride drills into details like heart-rate zone distribution, power profile, and elevation chart.&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%2F2m5kbfl7795dmx9kmg63.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%2F2m5kbfl7795dmx9kmg63.png" alt="Dashboard page" width="800" height="863"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Dashboard page&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Weekly Plan
&lt;/h3&gt;

&lt;p&gt;The Weekly Plan shows "what training you should do this week" laid out day by day. The Dashboard surfaces a card for just today's session, and the Weekly Plan page shows the full week (session type, target TSS, status) along with past plan history.&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%2F0ej7mu3wpvw9i790dvw9.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%2F0ej7mu3wpvw9i790dvw9.png" alt="Weekly plan page" width="800" height="636"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Weekly plan page&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The plan itself is generated by a separate agent that runs early every Monday morning and builds out the following week automatically. It looks at recent Fitness/Fatigue/Form and user settings, then proposes sessions aligned with a periodization cycle (Base → Build → Peak → Taper). I'll cover the agent in a separate post.&lt;/p&gt;
&lt;h3&gt;
  
  
  About the experimental features
&lt;/h3&gt;

&lt;p&gt;The three features below — Climb Simulator, Pace Optimizer, Training Planner — are currently marked as &lt;strong&gt;experimental&lt;/strong&gt;. They work, but the UX flow and parameters are still rough. I built them quickly with help from Antigravity and LLMs, referenced some papers, but haven't fully polished them yet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Climb Simulator&lt;/strong&gt; estimates climb time. Enter power, weight, distance, and elevation gain, and it computes a predicted time using physics-based math. If you're connected to Strava, you can also estimate times for your starred segments.&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%2Fa5eqcj4o4p2cyub4caxq.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%2Fa5eqcj4o4p2cyub4caxq.png" alt="Climb Simulator page" width="800" height="437"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Climb Simulator page&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pace Optimizer&lt;/strong&gt; computes optimal power distribution based on a course profile. It's based on a 2025 paper, &lt;a href="https://link.springer.com/article/10.1007/s12283-025-00493-9" rel="noopener noreferrer"&gt;"A numerical design methodology for optimal pacing strategy in the individual time trial discipline of cycling"&lt;/a&gt;. The core idea: push higher power on climbs and lower power on descents to shorten total time while keeping Normalized Power (NP) roughly constant. Intuitively, at lower speeds on climbs, aerodynamic drag is smaller, so extra watts translate more directly into time saved. There's still room to improve, but it's a feature grounded in recent research.&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%2Fs81hbds6uinbpo65sych.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%2Fs81hbds6uinbpo65sych.png" alt="Pace Optimizer page" width="800" height="801"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Pace Optimizer page&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Training Planner&lt;/strong&gt; generates a phased training plan working backward from a goal race date. The phases are split roughly like this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Phase&lt;/th&gt;
&lt;th&gt;Share of time&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Base&lt;/td&gt;
&lt;td&gt;35%&lt;/td&gt;
&lt;td&gt;Build aerobic foundation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Build 1&lt;/td&gt;
&lt;td&gt;25%&lt;/td&gt;
&lt;td&gt;Tempo and threshold work&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Build 2&lt;/td&gt;
&lt;td&gt;20%&lt;/td&gt;
&lt;td&gt;VO2max and high-intensity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Peak&lt;/td&gt;
&lt;td&gt;10%&lt;/td&gt;
&lt;td&gt;Race-specific simulation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Taper&lt;/td&gt;
&lt;td&gt;Remainder&lt;/td&gt;
&lt;td&gt;Recovery and tuning&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%2Fpuw55yhhj19vsf0gfcso.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%2Fpuw55yhhj19vsf0gfcso.png" alt="Training Planner page" width="800" height="751"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Training Planner page&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;
&lt;h3&gt;
  
  
  System overview
&lt;/h3&gt;

&lt;p&gt;The app is structured as &lt;strong&gt;frontend + BFF + external APIs&lt;/strong&gt;, with the next-workout-suggestion agent split off as a separate service.&lt;/p&gt;

&lt;p&gt;The frontend doesn't call the Strava API directly. Instead it goes through Next.js API Routes (BFF pattern), which lets me keep access tokens, refresh logic, and a cache layer on the server. The browser never sees secrets, and rate-limit-friendly caching only needs to live in one place.&lt;/p&gt;

&lt;p&gt;There's no database for ride history — Strava is the source of truth. Activity lists, ride details, and segment info are fetched from the Strava API on demand and cached for a short window inside the API Routes (BFF layer). That removes the need for a sync job and doubles as rate-limit protection. The only data I persist app-side is per-user settings, tokens, and weekly plans, all stored in Cloud Storage. No schema migrations, no per-environment ops; for personal-scale use this setup is plenty.&lt;/p&gt;

&lt;p&gt;The agent that suggests and adjusts the next workout combines "LLM + domain logic," and Python has a stronger library ecosystem for that (and I'm more comfortable in Python for ML work), so I split it out as its own FastAPI service on Cloud Run. Details in a future post.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────────────────┐
│                    Frontend                          │
│  Next.js 16 (App Router) + TypeScript + React 19    │
│  - Auth: NextAuth.js                                 │
│  - Charts: Recharts                                  │
│  - Maps: Leaflet + React-Leaflet                     │
└─────────────────────────────────────────────────────┘
                          │
                          ▼
┌─────────────────────────────────────────────────────┐
│               API Routes (BFF)                       │
│  Next.js API Routes (server-side)                    │
│  - Strava access token management / refresh          │
│  - Cloud Storage read/write (settings/cache/plans)   │
└─────────────────────────────────────────────────────┘
            │                          │
            ▼                          ▼
┌─────────────────────────────┐  ┌─────────────────────────┐
│     External Services        │  │        Storage          │
│  - Strava API (OAuth 2.0)    │  │  - Cloud Storage        │
│  - Nominatim (geocoding)     │  │   (JSON objects only)   │
└─────────────────────────────┘  └─────────────────────────┘
            │
            ▼
┌─────────────────────────────────────────────────────┐
│   Agent Service (covered in a future post)           │
│  Python / FastAPI / Google ADK + Gemini             │
│  - Daily Recommendation                              │
│  - Weekly Plan Generation                            │
└─────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The main tech stack:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Stack&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Frontend&lt;/td&gt;
&lt;td&gt;Next.js 16 (App Router) / TypeScript / React 19&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Visualization&lt;/td&gt;
&lt;td&gt;Recharts (charts) / Leaflet + React-Leaflet (maps)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auth&lt;/td&gt;
&lt;td&gt;NextAuth.js (Strava OAuth 2.0)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent&lt;/td&gt;
&lt;td&gt;Python / FastAPI / Google ADK + Gemini (covered in a future post)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Storage&lt;/td&gt;
&lt;td&gt;Cloud Storage (JSON objects only; no relational DB)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deployment&lt;/td&gt;
&lt;td&gt;Cloud Run (Web and Agent deployed as separate services)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  Handling Strava API rate limits
&lt;/h3&gt;

&lt;p&gt;According to Strava's &lt;a href="https://developers.strava.com/docs/rate-limits/" rel="noopener noreferrer"&gt;official docs&lt;/a&gt;, as of May 2026 the default rate limits are as follows, applied per application. Going over returns &lt;code&gt;429 Too Many Requests&lt;/code&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;15 min&lt;/th&gt;
&lt;th&gt;1 day&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Overall&lt;/td&gt;
&lt;td&gt;200 req&lt;/td&gt;
&lt;td&gt;2,000 req&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Non-Upload (read-heavy)&lt;/td&gt;
&lt;td&gt;100 req&lt;/td&gt;
&lt;td&gt;1,000 req&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The request count limits weren't really a problem in practice. The bigger constraint is &lt;strong&gt;Connected Athletes = 1&lt;/strong&gt;. With that default, only one user (me) can authorize the app, so I can't easily share it with friends. To raise it, you submit a form via Strava's Developer Program — they approved my request and bumped the limit within a day or two.&lt;/p&gt;
&lt;h2&gt;
  
  
  Notes on development
&lt;/h2&gt;

&lt;p&gt;In the end the split landed at: frontend and BFF (Next.js API Routes) in TypeScript, and the agent (LLM + domain logic) in Python (FastAPI). I write Python day-to-day at work and don't have deep TypeScript experience, but writing the web side in TypeScript wasn't really a problem this time. Two main reasons (with the caveat that this app is small):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;You can grok the logic by talking to the LLM.&lt;/strong&gt; Asking "explain the logic of this chart" or "show me where this is implemented" gets me the shape of the logic and the right code to read.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tweaking physics constants and formulas is mostly language-agnostic.&lt;/strong&gt; Editing constants like &lt;code&gt;const GRAVITY = 9.81&lt;/code&gt; or basic arithmetic and trig formulas doesn't really depend on the language — as long as you can find the right spot. Iterative optimization code is a different story; for that you do need to understand the implementation itself.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;On the other hand, the agent (next-workout suggestion and adjustment, covered separately) leans on the Python LLM ecosystem and my own familiarity, so I kept it separate. I did briefly experiment with using Python for the web backend, but the integration with the frontend created more debugging overhead, so I settled on "TypeScript for the UI-adjacent layer, Python for the LLM/inference layer." Carefully written interface definitions might mitigate that friction. Either way, the right split depends on the app's size and the kind of logic involved, and I'll keep refining my heuristic here.&lt;/p&gt;
&lt;h2&gt;
  
  
  Source code
&lt;/h2&gt;

&lt;p&gt;The source code is available here. The README walks through how to set it up yourself. It runs locally, and I've also made it deployable to Cloud Run so I can access it on the go from a phone. Use the deploy script (&lt;code&gt;deploy.sh.example&lt;/code&gt;) as a starting point and plug in your own project ID.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/kikuriyou" rel="noopener noreferrer"&gt;
        kikuriyou
      &lt;/a&gt; / &lt;a href="https://github.com/kikuriyou/PerfRide" rel="noopener noreferrer"&gt;
        PerfRide
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A performance management toolkit for road cyclists
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;PerfRide 🚴&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;A performance management toolkit for road cyclists, powered by the &lt;a href="https://developers.strava.com/" rel="nofollow noopener noreferrer"&gt;Strava API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Simulate climbs, optimize race pacing, plan periodized training, and track your fitness — all in one app.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;📊 Dashboard&lt;/h3&gt;
&lt;/div&gt;

&lt;p&gt;Connect with Strava to view your recent rides, weekly training summary, and fitness progress chart (CTL / ATL / TSB). Includes per-ride detail with heart rate zones, power profile, and elevation overlay.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;🏔️ Climb Simulator&lt;/h3&gt;

&lt;/div&gt;

&lt;p&gt;Predict climbing times based on power, weight, and real segment data. Uses physics-based simulation (air resistance, rolling resistance, drivetrain loss). Search segments by map or use your Strava starred segments.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;🎯 Pace Optimizer&lt;/h3&gt;

&lt;/div&gt;

&lt;p&gt;Calculate optimal pacing strategy for time trials based on course elevation profile. Based on the research paper &lt;em&gt;"A numerical design methodology for optimal pacing strategy in the individual time trial discipline of cycling"&lt;/em&gt; (Sports Engineering, 2025).&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;📅 Training Planner&lt;/h3&gt;

&lt;/div&gt;

&lt;p&gt;Generate periodized training plans for your target race…&lt;/p&gt;
&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/kikuriyou/PerfRide" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;This post introduced PerfRide, a minimal app built on top of the Strava API. With agentic coding tools like Antigravity, even outside your home language and library ecosystem, you can put together analytics that fit your own needs without much friction. As a bonus, it can save on subscription costs for paid features. For personal projects, I think it's a strong approach — give it a try.&lt;/p&gt;

&lt;p&gt;I'll write up the agent features ("next recommended workout" and "automated weekly plan generation") in a separate post.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article was originally published in Japanese on &lt;a href="https://zenn.dev/kikuriyou/articles/2605122159_ride-analysis-app" rel="noopener noreferrer"&gt;Zenn&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>cycling</category>
      <category>nextjs</category>
      <category>googlecloud</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Through the Blue Frames: UX From Google Glass to Gemini</title>
      <dc:creator>Allen Firstenberg</dc:creator>
      <pubDate>Fri, 15 May 2026 15:00:00 +0000</pubDate>
      <link>https://forem.com/gde/through-the-blue-frames-ux-from-google-glass-to-gemini-51e0</link>
      <guid>https://forem.com/gde/through-the-blue-frames-ux-from-google-glass-to-gemini-51e0</guid>
      <description>&lt;p&gt;It's a busy few weeks for me.&lt;br&gt;
Three weeks ago I attended a GDE Summit and Google Cloud Next.&lt;br&gt;
Two weeks ago, I was one of those honored as a Voice AI 100 at the 10th Project Voice conference.&lt;br&gt;
Next week I will be attending my eleventh Google I/O - my tenth as a GDE.&lt;/p&gt;

&lt;p&gt;More on all of these shortly and how they illustrate my past 15 years as a developer.&lt;/p&gt;

&lt;p&gt;But first - I think about what last week marked. Because 13 years ago last week I walked into Google's offices on the top floor of Chelsea Market in NYC and unboxed my first pair of Google Glass. (The first blue framed Glass in NYC.) And that event has shaped me and how I think about the role of personal computing to this day.&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%2Fied1n6x7busgaw0a450n.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%2Fied1n6x7busgaw0a450n.jpg" alt="Unboxing Google Glass" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Although I was already a GDE at that time, I became the first Glass GDE. I made dozens of presentations to groups about how to develop for Glass and how we needed to think about developing for Glass. I got over my fears of speaking, leaned into the experience of working with people, started wearing my trademark blue shirts, and met some amazing folks in art and engineering. I wrote a book about it, too.&lt;/p&gt;

&lt;p&gt;Most of all, I began to digest what a post-smartphone interface would be like. When I spoke at Augmented World Expo NYC in 2014 about Google Glass, I saw lots of demonstrations of goggles and AR popping off phone screens, and I didn't think that was it.&lt;/p&gt;

&lt;p&gt;Instead, the message I tried to advocate was that the AR and VR worlds had much to learn from our experiences developing for Glass. Concepts such as "there when you need it, out of the way when you don't". I also said that the future of Glass had much to learn from AR and VR as well. Not in what they were showing, but rather that our devices need to be more contextual and understand the environment we were working in. Head mounted wearables had a unique feature no other did - they could "see" the same perspective we did without any action on our part.&lt;/p&gt;

&lt;p&gt;At Google I/O in 2016, the first at Shoreline Amphitheater, a reporter saw I was wearing Glass and asked me what I thought about the keynote earlier that day. He expected me to talk about the new augmented reality platform that Google had announced. But I wasn't interested in that. I saw what I realized was truly the next generation of the Google Glass interface - Google Assistant and the Google Home.&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%2Fv3b84s9gx5kzbyl3dk4h.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%2Fv3b84s9gx5kzbyl3dk4h.jpg" alt="Google Assistant in 2016" width="800" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Google Assistant, and the Voice First interfaces I was now helping people understand, started refining the message that I delivered at AWE a couple of years earlier. Voice agents needed context to work, but they mostly remained silent partners until we asked them something. On Google Home devices, they were mostly passive, ubiquitous, presences in the world we lived in.&lt;/p&gt;

&lt;p&gt;The interface was also new. My message at the time was that, since digital computers were first available, we had to teach people how to use them - what holes to punch, what keys to click, how to use a mouse, or what swiping gestures were necessary on our phone.&lt;/p&gt;

&lt;p&gt;For the first time, devices like Google Assistant and Alexa were turning that around. Now we were teaching computers how to understand us. They weren't perfect, and there were still many lessons we needed to figure out, such as discovery and monetization, but the interfaces were taking bold new steps in trying to figure out these answers.&lt;/p&gt;

&lt;p&gt;Personally and professionally, this was a time when I continued to expand and grow. I didn't just do presentations, I collaborated on a weekly podcast, participated in the frequent Voice Lunch discussions, and held weekly office hours. When Glass was discontinued, it started my move into wearables in general, and then into becoming a Google Assistant GDE.&lt;/p&gt;

&lt;p&gt;But as Google lost interest in Assistant, and Amazon struggled with the future of Alexa, I knew it was time for me to find the next generation of the future of interfaces. As I started to explore the world of LLMs, I realized that these were taking many of the concepts we had in voice and starting to bring them to everyone and to far more modalities than voice alone.&lt;/p&gt;

&lt;p&gt;I became, briefly, an AI GDE as conversational interfaces started to take off. It was clear to me that the agents we were beginning to talk about were the evolution of the agents we were talking about in the voice world. And it was no surprise that we were talking about "context windows" and how important context was in these LLMs being able to work with our queries.&lt;/p&gt;

&lt;p&gt;It was also clear that, while text was the default modality for these conversations, that was just the stepping stone. Voice was a clear next step. Incorporating images was an obvious next step. Perhaps we had learned some of the lessons I was advocating for?&lt;/p&gt;

&lt;p&gt;I was hopeful. At I/O 2022, a whole 10 years after Glass launched, Google was talking about using AI to "bridge the physical and digital worlds" to use the context of what you could see in front of you to help with your search queries.&lt;/p&gt;

&lt;p&gt;"If only," I thought, "they had some... glasses.. or something to make that easier."&lt;/p&gt;

&lt;p&gt;We saw the first tease of that at I/O in 2024 in a demonstration of Project Astra, where glasses were able to answer questions about the context they were "seeing". At I/O 2025, it went two steps further - we were told this technology would be part of the forthcoming Android XR, and we could try on and test a prototype!&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%2Fnhib7c8pu7ar9dk9cwq5.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%2Fnhib7c8pu7ar9dk9cwq5.jpg" alt="Trying on Project Astra in 2025" width="800" height="1067"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But there were many unanswered questions. Most importantly in my mind - how would developers tap into this interface? Glass and Assistant were notable because they were platforms, allowing developers to use the new interface that was available. Would Android XR let us seamlessly ask Gemini a question and get it answered by our app, all through voice? Or would it force a clunky "launch" and change in interaction model? Do we have a discovery model? Can we monetize our apps to pay for their development? Had we learned the lessons yet?&lt;/p&gt;

&lt;p&gt;My conferences these weeks tell the tale of my quest to answer that final question. The GDE summit let me connect with developers across different fields, cross-pollinating ideas, and reminding me of this journey I started nearly 15 years ago. Cloud Next reminds me of the underlying workhorse that AI, LLMs, and agents are bringing to the table. Project Voice reminds me of the people who were delivering that next generation interface to millions of households and the small role I played in it.&lt;/p&gt;

&lt;p&gt;And I/O?&lt;/p&gt;

&lt;p&gt;That reminds me of the future. The next step.&lt;/p&gt;

&lt;p&gt;Next week we will see if Google has truly learned the lessons from Glass and Assistant and AI. We'll see if they let us do ambient and ubiquitous computing in a whole new way. We'll learn, I hope, when these devices will be available for everyone. And, perhaps most importantly, we'll learn if they'll come with blue frames.&lt;/p&gt;

&lt;p&gt;We'll hear and see next week. And I'll give voice to my thoughts then.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Acknowledgements&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Along this journey, I've walked alongside many amazing people. Some pointed me in new directions. Some collaborated in shared understanding. Any list I give would be entirely inadequate, and likely missing a few who should be included, but I wanted to try to mention some. Google and the Google Developer Expert program, as a whole, who have provided great opportunities to attend many of these conferences. Jonathan Beri, who invited me to my first I/O in 2012. Jen Tong and Timothy Jordan, my mentors during the Glass years. Jessica Earley-Cha, one of my mentors during the Assistant years. Jason Salas, my co-author. Mark Tucker, my podcast co-host. Gerwin Sturm, Steven Gray, Linda Lawton, Denis Valasek, Noble Ackerson, and Mike Wolfson, my fellow GDEs who helped me explore these new worlds. And, most of all, my family - my parents who started me on this path with computers decades ago, and my child who keeps me grounded every day.&lt;/p&gt;

</description>
      <category>androidxr</category>
      <category>googleglass</category>
      <category>googleassistant</category>
      <category>voicefirst</category>
    </item>
    <item>
      <title>GemmaFin - Breaking the Cycle of Debt with Conversational AI</title>
      <dc:creator>Vinicius F. Caridá</dc:creator>
      <pubDate>Fri, 15 May 2026 14:31:00 +0000</pubDate>
      <link>https://forem.com/gde/gemmafin-breaking-the-cycle-of-debt-with-conversational-ai-4l7n</link>
      <guid>https://forem.com/gde/gemmafin-breaking-the-cycle-of-debt-with-conversational-ai-4l7n</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/google-gemma-2026-05-06"&gt;Gemma 4 Challenge: Build with Gemma 4&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Note: This project is aimed at solving a critical social issue in Brazil, but we are submitting it in English to align with the global nature of the Dev.to Challenge. Our ultimate goal is to localize the final platform to Brazilian Portuguese (pt-BR) to serve our local communities.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;GemmaFin - Breaking the Cycle of Debt with Conversational AI&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In 2026, Brazil is facing a structural household debt crisis. A staggering 80.9% of families are in debt, and a large portion of the population is trapped in a cycle of high-interest credit card revolving debt and the rising epidemic of unregulated online gambling ("Bets"). Traditional budgeting apps have failed to solve this because they require a high level of financial literacy and impose severe cognitive friction—forcing exhausted workers to manually type numbers, navigate drop-down menus, and categorize every penny. &lt;/p&gt;

&lt;p&gt;This crisis is severely exacerbated by historical gaps in the public education system. Millions of vulnerable Brazilians lack basic financial literacy, making it nearly impossible for them to decode complex banking jargon, comprehend the crushing compound interest rates applied to their debts, or make informed strategic decisions about their money.&lt;/p&gt;

&lt;p&gt;GemmaFin subverts this paradigm. Built specifically for low-income families and informal workers, GemmaFin is a Progressive Web App (PWA) that mimics a simple messaging interface. In Brazil, WhatsApp is more than an app; it is the default operating system for communication. Studies show that over 99% of smartphones in the country have it installed. Even individuals with low digital literacy use it daily with ease. By adopting this highly familiar, chat-based UI, GemmaFin removes the steep learning curve of traditional financial apps, ensuring true accessibility.&lt;/p&gt;

&lt;p&gt;Instead of filling out spreadsheets, the user simply "talks" to the app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Audio Inputs for the Informal Economy:&lt;/strong&gt; A user can send a voice memo saying, "I did some electrical work today and got 200 Reais on Pix, but spent 50 at the barber."&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Visual Inputs for Messy Realities:&lt;/strong&gt; A user can snap a photo of a crumpled, faded grocery receipt or upload a screenshot of their bank statement.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Real-Time Point-of-Sale Advisor:&lt;/strong&gt; Users frequently face complex daily dilemmas, such as deciding whether to buy an appliance in 12 installments or pay cash for a 5% discount. Users can ask GemmaFin in real-time, and the AI will analyze their current liquidity, the discount offered, and potential yield if the money were invested, delivering a simple, mathematically sound recommendation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Debt Rescue &amp;amp; Refinancing:&lt;/strong&gt; When GemmaFin detects that a user is about to enter high-interest revolving credit (which can exceed 400% annually in Brazil), it proactively intervenes. The AI acts as an "Agentic Nudge," suggesting safer alternatives, like taking a lower-interest personal loan to pay off the credit card, acting as a real-time financial shield.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The AI autonomously parses these unstructured multimodal inputs, categorizes the income and expenses, updates the local ledger, and generates simplified visual dashboards to prevent insolvency before it happens.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

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

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/vfcarida" rel="noopener noreferrer"&gt;
        vfcarida
      &lt;/a&gt; / &lt;a href="https://github.com/vfcarida/Gemma-4-Challenge_finance" rel="noopener noreferrer"&gt;
        Gemma-4-Challenge_finance
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Gemma-4-Challenge_finance
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;GemmaFin - Breaking the Cycle of Debt with Conversational AI&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/vfcarida/Gemma-4-Challenge_finance/./public/banner.jpg"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fvfcarida%2FGemma-4-Challenge_finance%2FHEAD%2F.%2Fpublic%2Fbanner.jpg" alt="GemmaFin Cover"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.google/technology/ai/google-gemma-4-ai-model/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/72067680a477cf53173f603074061c73a867cd2b8597feacb3af4b83f2472bd6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4d6f64656c2d47656d6d615f345f4532422d626c756576696f6c6574" alt="Gemma 4"&gt;&lt;/a&gt;
&lt;a href="https://opensource.org/licenses/MIT" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/fdf2982b9f5d7489dcf44570e714e3a15fce6253e0cc6b5aa61a075aac2ff71b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d79656c6c6f772e737667" alt="License: MIT"&gt;&lt;/a&gt;
&lt;a href="https://web.dev/progressive-web-apps/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/0c7cb75ac130bc205ab9cc64314a3563d7af39bdfdc323d78d712ef2e152c14f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5057412d52656164792d6f72616e6765" alt="PWA"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;An AI-powered personal finance Progressive Web App (PWA) specifically designed for low-income Brazilian families and informal workers. It leverages the multimodal power of Gemma 4 E2B to turn financial management from a burden into a conversation.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;📖 Overview&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;In 2026, Brazil is facing a structural household debt crisis. A staggering &lt;strong&gt;80.9% of families are in debt&lt;/strong&gt;, and a large portion of the population is trapped in a cycle of high-interest credit card revolving debt and the rising epidemic of unregulated online gambling ("Bets"). Traditional budgeting apps have failed to solve this because they require a high level of financial literacy and impose severe cognitive friction—forcing exhausted workers to manually type numbers, navigate drop-down menus, and categorize every penny.&lt;/p&gt;
&lt;p&gt;This crisis is severely exacerbated by historical gaps in the public education system. Millions of vulnerable Brazilians lack basic financial literacy…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/vfcarida/Gemma-4-Challenge_finance" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  How I Used Gemma 4
&lt;/h2&gt;

&lt;p&gt;To build a financial assistant for vulnerable populations, two things are absolutely non-negotiable: Privacy and Zero-Friction Multimodality. For these reasons, the Gemma 4 E2B (Effective 2 Billion) model was the perfect and only logical fit for this architecture.&lt;/p&gt;

&lt;p&gt;Here is how Gemma 4 E2B powers the core of GemmaFin:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;On-Device Privacy (Zero Data Exposure):&lt;/strong&gt; Financial data (bank statements, income audio memos) is highly sensitive. Sending this data to the cloud is a massive privacy risk. Because the E2B model is optimized for edge devices and runs locally with an incredibly small memory footprint, all inference happens completely on-device. The user's financial life never leaves their phone.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Native Audio &amp;amp; Vision Understanding:&lt;/strong&gt; Classical OCR fails miserably on crumpled, poorly lit receipts. Gemma 4 E2B natively supports text, high-resolution images, and raw audio. The model directly listens to the user's voice memos about informal jobs and reads bank screenshots end-to-end without relying on fragile, third-party speech-to-text or OCR pipelines.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Agentic Workflows via &lt;code&gt;&amp;lt;|think|&amp;gt;&lt;/code&gt; and Function Calling:&lt;/strong&gt; GemmaFin doesn't just chat; it acts. Using Gemma 4's native &lt;code&gt;&amp;lt;|think|&amp;gt;&lt;/code&gt; reasoning mode, the model mathematically calculates the user's new balance internally before responding. It then leverages native structured JSON function calling to autonomously trigger the local &lt;code&gt;update_ledger&lt;/code&gt; function. This transforms unstructured real-world chaos into clean, categorized SQLite/LocalStorage database entries entirely in the background.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key Features
&lt;/h2&gt;

&lt;p&gt;GemmaFin is a complete interactive financial assistant capable of performing historical analysis and answering complex questions in natural language.&lt;/p&gt;

&lt;p&gt;🚀 &lt;strong&gt;Core Functionalities&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Multimodal Processing (Simulated Gemma 4):&lt;/strong&gt; GemmaFin is no ordinary chat. It simulates the advanced orchestration of Gemma 4 to process different types of media:

&lt;ul&gt;
&lt;li&gt;  &lt;em&gt;Voice (Audio-to-Action):&lt;/em&gt; Record earnings and expenses via voice. The AI transcribes, categorizes, and updates your balance instantly.&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Vision (Bank Statement OCR):&lt;/em&gt; Send a screenshot of your bank statement or a photo of a receipt. The AI automatically identifies transactions, saving the user from manual typing.&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Exposed Reasoning (&lt;code&gt;&amp;lt;|think|&amp;gt;&lt;/code&gt;):&lt;/em&gt; Animated thought blocks show the AI's "step-by-step" logic (transcription -&amp;gt; extraction -&amp;gt; calculation), increasing transparency and user trust.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  &lt;strong&gt;Interactive Data Visualization:&lt;/strong&gt; We transform dry numbers into easy-to-understand visual insights:

&lt;ul&gt;
&lt;li&gt;  &lt;em&gt;Comprehensive Monthly Report:&lt;/em&gt; Comparative bar charts (Income vs. Expenses) showing the evolution over the last 3 months.&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Trend Analysis:&lt;/em&gt; The AI detects and warns about price variations in critical categories like Groceries and Gas.&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Budget Goals:&lt;/em&gt; Circular progress indicators that help the user stay within the limits set for the month.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  &lt;strong&gt;"WhatsApp-First" Conversational Experience:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;em&gt;Familiar Interface:&lt;/em&gt; Design optimized for the Brazilian user, using visual patterns to lower the learning curve.&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Smart Suggestions (Quick Replies):&lt;/em&gt; Quick response buttons that guide the user to the next logical actions.&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Personalized Tips:&lt;/em&gt; Savings advice based on the actual consumption profile, such as brand substitution suggestions or service optimization.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;🧠 &lt;strong&gt;Brain with Historical Context&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Implemented a simulated database with 3 months of financial history (March, April, May). When you send a photo of a bank statement, GemmaFin doesn't just read the expense, it compares it to last month: "Last month you spent R$ 72.00 at the grocery store... an 11% increase."&lt;/p&gt;

&lt;p&gt;⚙️ &lt;strong&gt;Smart Engine&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Replaced generic messages with an intent-understanding engine. You can ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  "How much did I spend on groceries?" → Opens the new Comparison Card.&lt;/li&gt;
&lt;li&gt;  "View month summary" → Opens the Comprehensive Monthly Report.&lt;/li&gt;
&lt;li&gt;  "Set goal" → Shows goal progress by category.&lt;/li&gt;
&lt;li&gt;  "Savings tips" → Generates personalized advice based on the low-income profile.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;📱 &lt;strong&gt;Visualization Components&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;FullReportCard&lt;/code&gt;:&lt;/strong&gt; Grouped bar chart (Income vs. Expenses) for the last 3 months and trend table by category.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;ComparisonCard&lt;/code&gt;:&lt;/strong&gt; Comparative horizontal bars for specific categories.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;BudgetGoalCard&lt;/code&gt;:&lt;/strong&gt; Circular progress indicators for spending goals.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;Quick Replies&lt;/code&gt;:&lt;/strong&gt; Suggestion chips to facilitate navigation after each response.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;Typing Indicator&lt;/code&gt;:&lt;/strong&gt; "GemmaFin is typing..." animation to make the interaction more human.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>gemmachallenge</category>
      <category>gemma</category>
    </item>
    <item>
      <title>Deploying a Rust MCP Server to Azure ACI</title>
      <dc:creator>xbill</dc:creator>
      <pubDate>Fri, 15 May 2026 13:02:34 +0000</pubDate>
      <link>https://forem.com/gde/deploying-a-rust-mcp-server-to-azure-aci-15nb</link>
      <guid>https://forem.com/gde/deploying-a-rust-mcp-server-to-azure-aci-15nb</guid>
      <description>&lt;p&gt;The rmcp crate and standard Rust libraries are used to build a basic MCP Server in Rust. This MCP Server is then built and deployed to Azure ACI and validated locally with Gemini CLI.&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%2Fwpkz7byui6vcb3um2z9c.jpeg" 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%2Fwpkz7byui6vcb3um2z9c.jpeg" width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Yet another MCP Demo?
&lt;/h4&gt;

&lt;p&gt;All Hail Ferris- Lord Master of MCP!&lt;/p&gt;

&lt;h4&gt;
  
  
  Why not just use Python?
&lt;/h4&gt;

&lt;p&gt;Python has traditionally been the main coding language for ML and AI tools. One of the strengths of the MCP protocol is that the actual implementation details are independent of the development language. The reality is that not every project is coded in Python- and MCP allows you to use the latest AI appt roaches with other coding languages.&lt;/p&gt;

&lt;h4&gt;
  
  
  What is this Tutorial Trying to Do?
&lt;/h4&gt;

&lt;p&gt;Building on previous tutorials, the goal is to extend a Rust MCP server with basic support for deployment to Azure.&lt;/p&gt;

&lt;h4&gt;
  
  
  What is Rust?
&lt;/h4&gt;

&lt;p&gt;Rust is a high performance, memory safe, compiled language:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.rust-lang.org/" rel="noopener noreferrer"&gt;Rust&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Rust provides memory safe operations beyond C/C++ and also can provide exceptional performance gains as it is compiled directly to native binaries.&lt;/p&gt;

&lt;h4&gt;
  
  
  So Why Am I reading this?
&lt;/h4&gt;

&lt;p&gt;So what is different about this lab compared to all the others out there?&lt;/p&gt;

&lt;p&gt;This is one of the first deep dives into deploying a Rust based MCP server hosted on Azure. The Azure ACI service was targeted for compatibility with Docker Images.&lt;/p&gt;

&lt;h4&gt;
  
  
  Rust Setup
&lt;/h4&gt;

&lt;p&gt;Instructions to install Rust are available here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.rust-lang.org/learn/get-started" rel="noopener noreferrer"&gt;Getting started&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For a Linux like environment the command looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl — proto ‘&lt;span class="o"&gt;=&lt;/span&gt;https’ — tlsv1.2 &lt;span class="nt"&gt;-sSf&lt;/span&gt; https://sh.rustup.rs | sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rust also depends on a working C compiler and OpenSSL setup. For a Debian 12 system — install the basic tools for development:&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;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;build-essential
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;libssl-dev
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;pkg-config
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;libudev-dev
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;make
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Gemini CLI
&lt;/h4&gt;

&lt;p&gt;If not pre-installed you can download the Gemini CLI to interact with the source files and provide real-time assistance:&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/gemini-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Testing the Gemini CLI Environment
&lt;/h4&gt;

&lt;p&gt;Once you have all the tools and the correct Node.js version in place- you can test the startup of Gemini CLI. You will need to authenticate with a Key or your Google Account:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;▝▜▄ Gemini CLI v0.33.1
    ▝▜▄
   ▗▟▀ Logged in with Google /auth
  ▝▀ Gemini Code Assist Standard /upgrade no sandbox (see /docs) /model Auto (Gemini 3) | 239.8 MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Azure Container Instances
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://www.google.com/search?q=Azure+Container+Instances&amp;amp;sca_esv=9e0af5be28576de2&amp;amp;rlz=1CAIWTJ_enUS1110&amp;amp;sxsrf=ANbL-n7o0MyASoiBM0kA0-E5qMMzLudrbw%3A1775144526115&amp;amp;ei=To7OadXFBoOYptQP9JuB0A8&amp;amp;biw=1396&amp;amp;bih=632&amp;amp;ved=2ahUKEwiIvt3awM-TAxUolYkEHTTxLJIQgK4QegYIAQgAEAM&amp;amp;uact=5&amp;amp;oq=azure+aci&amp;amp;gs_lp=Egxnd3Mtd2l6LXNlcnAiCWF6dXJlIGFjaTIKECMYgAQYJxiKBTILEAAYgAQYkQIYigUyBRAAGIAEMgcQABiABBgKMgUQABiABDIFEAAYgAQyBRAAGIAEMgYQABgWGB4yBhAAGBYYHjIGEAAYFhgeSOwPUABY2gxwAHgBkAEAmAGVAaABqQmqAQMwLjm4AQPIAQD4AQGYAgmgAvYJwgIKEAAYgAQYQxiKBcICDhAAGIAEGLEDGIMBGIoFwgIREC4YgAQYsQMY0QMYgwEYxwHCAhAQABiABBixAxhDGIMBGIoFwgILEC4YgAQYxwEYrwHCAg0QABiABBixAxhDGIoFwgIIEAAYgAQYsQPCAgsQABiABBixAxiDAZgDAJIHAzAuOaAHsFWyBwMwLjm4B_YJwgcFMi04LjHIBzuACAA&amp;amp;sclient=gws-wiz-serp" rel="noopener noreferrer"&gt;Azure Container Instances&lt;/a&gt; (ACI) is a serverless, managed service that allows you to run Docker containers in the cloud without managing virtual machines. It is ideal for rapid deployment, bursting, and simple, isolated applications, offering per-second billing and quick startup times. ACI supports Linux and Windows containers, with options for volume mounting and GPU resources.&lt;/p&gt;

&lt;p&gt;More details are available here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://azure.microsoft.com/en-us/products/container-instances" rel="noopener noreferrer"&gt;https://azure.microsoft.com/en-us/products/container-instances&lt;/a&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%2F5hs6pgp6pcmoke09tywz.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%2F5hs6pgp6pcmoke09tywz.png" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Why would I want Gemini CLI with Azure? Isn’t that a Google Thing?
&lt;/h4&gt;

&lt;p&gt;Yes- Gemini CLI leverages the Google Cloud console and Gemini models but it is also open source and platform agnostic. Many applications are already cross-cloud so this enables familiar tools to be run natively on Microsoft Azure.&lt;/p&gt;

&lt;h4&gt;
  
  
  Azure CLI
&lt;/h4&gt;

&lt;p&gt;The Azure Command-Line Interface (CLI) is a cross-platform tool used to connect to Azure and execute administrative commands on your cloud resources. [&lt;a href="https://learn.microsoft.com/en-us/cli/azure/what-is-azure-cli?view=azure-cli-latest" rel="noopener noreferrer"&gt;1&lt;/a&gt;, &lt;a href="https://www.codemag.com/Article/2001021/Azure-CLI" rel="noopener noreferrer"&gt;2&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;It allows you to manage services like virtual machines, storage accounts, and networks through a terminal using either interactive prompts or automated scripts.&lt;/p&gt;

&lt;p&gt;More information is here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://learn.microsoft.com/en-us/cli/azure/what-is-azure-cli?view=azure-cli-latest" rel="noopener noreferrer"&gt;What is the Azure CLI?&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Setup the Basic Environment
&lt;/h4&gt;

&lt;p&gt;At this point you should have a working Rust environment and a working Gemini CLI installation. All of the relevant code examples and documentation is available in GitHub.&lt;/p&gt;

&lt;p&gt;The next step is to clone the GitHub repository to your local environment:&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;cd&lt;/span&gt; ~
git clone https://github.com/xbill9/gemini-cli-azure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run &lt;strong&gt;init.sh&lt;/strong&gt; from the cloned directory.&lt;/p&gt;

&lt;p&gt;The script will attempt to determine your shell environment and set the correct variables:&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;source &lt;/span&gt;init.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your session times out or you need to re-authenticate- you can run the &lt;strong&gt;set_env.sh&lt;/strong&gt; script to reset your environment variables:&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;source &lt;/span&gt;set_env.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Variables like PROJECT_ID need to be setup for use in the various build scripts- so the &lt;strong&gt;set_env&lt;/strong&gt; script can be used to reset the environment if you time-out.&lt;/p&gt;

&lt;p&gt;Refresh the Azure credentials:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;xbill@penguin:~/gemini-cli-azure/mcp-aci-rust-azure$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;az login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally install the packages and dependencies:&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;cd&lt;/span&gt; ~/gemini-cli-azure/mcp-aci-rust-azure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Build The Rust MCP Server
&lt;/h4&gt;

&lt;p&gt;Some background information on building and configuring a Rust MCP server is here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://xbill999.medium.com/building-a-secure-http-transport-mcp-server-with-rust-and-gemini-cli-b4e807e7aa1d" rel="noopener noreferrer"&gt;Building a Secure HTTP Transport MCP Server with Rust, and Gemini CLI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The mcp-aci-rust-azure subdirectory has the complete Rust MCP server in one subdirectory.&lt;/p&gt;

&lt;h4&gt;
  
  
  Minimal System Information Tool Build
&lt;/h4&gt;

&lt;p&gt;The first step is to build the basic tool directly with Rust. This allows the tool to be debugged and tested locally before adding the MCP layer.&lt;/p&gt;

&lt;p&gt;First build the tool locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;xbill@penguin:~/gemini-cli-azure/mcp-aci-rust-azure$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;make
&lt;span class="go"&gt;Building the Rust project...
   Compiling mcp-aci-rust-azure v1.0.0 (/home/xbill/gemini-cli-azure/mcp-aci-rust-azure)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 8.58s
&lt;/span&gt;&lt;span class="gp"&gt;xbill@penguin:~/gemini-cli-azure/mcp-aci-rust-azure$&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then lint check the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;xbill@penguin:~/gemini-cli-azure/mcp-aci-rust-azure$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;make lint
&lt;span class="go"&gt;Linting code...
    Checking mcp-aci-rust-azure v1.0.0 (/home/xbill/gemini-cli-azure/mcp-aci-rust-azure)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.89s
&lt;/span&gt;&lt;span class="gp"&gt;xbill@penguin:~/gemini-cli-azure/mcp-aci-rust-azure$&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and run local tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;xbill@penguin:~/gemini-cli-azure/mcp-aci-rust-azure$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;make &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;span class="go"&gt;Running tests...
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.12s
     Running unittests src/main.rs (target/debug/deps/mcp_aci_rust_azure-093b4404046a4149)

running 1 test
test tests::test_greeting ... ok

&lt;/span&gt;&lt;span class="gp"&gt;test result: ok. 1 passed;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;0 failed&lt;span class="p"&gt;;&lt;/span&gt; 0 ignored&lt;span class="p"&gt;;&lt;/span&gt; 0 measured&lt;span class="p"&gt;;&lt;/span&gt; 0 filtered out&lt;span class="p"&gt;;&lt;/span&gt; finished &lt;span class="k"&gt;in &lt;/span&gt;0.00s
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;xbill@penguin:~/gemini-cli-azure/mcp-aci-rust-azure$&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last step is to build the production version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;xbill@penguin:~/gemini-cli-azure/mcp-aci-rust-azure$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;make release
&lt;span class="go"&gt;Building Release...
    Finished `release` profile [optimized] target(s) in 0.36s
&lt;/span&gt;&lt;span class="gp"&gt;xbill@penguin:~/gemini-cli-azure/mcp-aci-rust-azure$&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The MCP server can be started locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The MCP tool can then be tested locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🟢 local-rust - Ready (1 tool)
  Tools:
  - mcp_local-rust_greeting

 &amp;gt; mcp_local-rust_greeting hello local

  Executing Greeting Tool: Executing the greeting tool on the local Rust MCP server.

╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ greeting (local-rust MCP Server) {"message":"hello local"} │
│ │
│ Hello World MCP! hello local │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
  Greeting Completed: Greeting successful. Standing by for next instruction.


✦ Hello World MCP! hello local
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Deploy To ACI
&lt;/h4&gt;

&lt;p&gt;A basic Dockerfile is used to build an image for deployment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;xbill@penguin:~/gemini-cli-azure/mcp-aci-rust-azure$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;make deploy
&lt;span class="go"&gt;Building the Docker image...
[+] Building 2.2s (14/14) FINISHED docker:default
&lt;/span&gt;&lt;span class="gp"&gt; =&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;internal] load build definition from Dockerfile 0.0s
&lt;span class="gp"&gt; =&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; transferring dockerfile: 763B 0.0s 0.0s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Get the deployment status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;xbill@penguin:~/gemini-cli-azure/mcp-aci-rust-azure$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;make status
&lt;span class="go"&gt;mcp-aci-rust-azure PID file exists but process is not running.
Checking Azure Container Instance status for mcp-container-penguin...
Name State FQDN IP
--------------------- ------- ----------------------------------------------- -------------
mcp-container-penguin Running mcp-container-penguin.westus2.azurecontainer.io 4.149.223.153
&lt;/span&gt;&lt;span class="gp"&gt;xbill@penguin:~/gemini-cli-azure/mcp-aci-rust-azure$&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Get the Endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;xbill@penguin:~/gemini-cli-azure/mcp-aci-rust-azure$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;make endpoint
&lt;span class="go"&gt;mcp-container-penguin.westus2.azurecontainer.io
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check Gemini MCP settings:&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;"mcpServers"&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;"mcp-aci-rust-azure"&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;"httpUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://mcp-container-penguin.westus2.azurecontainer.io:8080/mcp"&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;"local-rust"&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;"httpUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://127.0.0.1:8080/mcp"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The service will be visible on the Azure console:&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%2Fu7fm78gzsx10lnkkjhhw.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%2Fu7fm78gzsx10lnkkjhhw.png" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Final Test
&lt;/h4&gt;

&lt;p&gt;Start up Gemini CLI and check the MCP server status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🟢 mcp-aci-rust-azure - Ready (2 tools)
  Tools:
  - mcp_mcp-aci-rust-azure_greeting


 &amp;gt; mcp_mcp-aci-rust-azure_greeting hello aci!

╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ greeting (mcp-aci-rust-azure MCP Server) {"message":"hello aci!"} │
│ │
│ Hello World MCP! hello aci! │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

✦ Hello World MCP! hello aci!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Summary
&lt;/h4&gt;

&lt;p&gt;A complete HTTP transport MCP server was built using Rust. This application was tested locally with Gemini CLI. Then, the entire solution was deployed to Azure ACI. The remote MCP server was validated with Gemini CLI locally.&lt;/p&gt;

</description>
      <category>mcpserver</category>
      <category>gemini</category>
      <category>iac</category>
      <category>azure</category>
    </item>
    <item>
      <title>Deploying a Rust MCP Server to Azure Functions</title>
      <dc:creator>xbill</dc:creator>
      <pubDate>Fri, 15 May 2026 13:01:46 +0000</pubDate>
      <link>https://forem.com/gde/deploying-a-rust-mcp-server-to-azure-functions-3agg</link>
      <guid>https://forem.com/gde/deploying-a-rust-mcp-server-to-azure-functions-3agg</guid>
      <description>&lt;p&gt;The rmcp crate and standard Rust libraries are used to build a basic MCP Server in Rust. This MCP Server is then built and deployed to Azure Functions and validated locally with Gemini CLI.&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%2F5jwbgsyw2vfbzgvgkfnc.jpeg" 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%2F5jwbgsyw2vfbzgvgkfnc.jpeg" width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  More MCP Demos?
&lt;/h4&gt;

&lt;p&gt;Yup. A2A- is next!&lt;/p&gt;

&lt;h4&gt;
  
  
  Why not just use Python?
&lt;/h4&gt;

&lt;p&gt;Python has traditionally been the main coding language for ML and AI tools. One of the strengths of the MCP protocol is that the actual implementation details are independent of the development language. The reality is that not every project is coded in Python- and MCP allows you to use the latest AI appt roaches with other coding languages.&lt;/p&gt;

&lt;h4&gt;
  
  
  What is this Tutorial Trying to Do?
&lt;/h4&gt;

&lt;p&gt;Building on previous tutorials, the goal is to extend a Rust MCP server with basic support for deployment to Azure.&lt;/p&gt;

&lt;h4&gt;
  
  
  What is Rust?
&lt;/h4&gt;

&lt;p&gt;Rust is a high performance, memory safe, compiled language:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.rust-lang.org/" rel="noopener noreferrer"&gt;Rust&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Rust provides memory safe operations beyond C/C++ and also can provide exceptional performance gains as it is compiled directly to native binaries.&lt;/p&gt;

&lt;h4&gt;
  
  
  So Why Am I reading this?
&lt;/h4&gt;

&lt;p&gt;So what is different about this lab compared to all the others out there?&lt;/p&gt;

&lt;p&gt;This is one of the first deep dives into deploying a Rust based MCP server hosted on Azure. The Azure ACI service was targeted for compatibility with Docker Images.&lt;/p&gt;

&lt;h4&gt;
  
  
  Rust Setup
&lt;/h4&gt;

&lt;p&gt;Instructions to install Rust are available here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.rust-lang.org/learn/get-started" rel="noopener noreferrer"&gt;Getting started&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For a Linux like environment the command looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl — proto ‘&lt;span class="o"&gt;=&lt;/span&gt;https’ — tlsv1.2 &lt;span class="nt"&gt;-sSf&lt;/span&gt; https://sh.rustup.rs | sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rust also depends on a working C compiler and OpenSSL setup. For a Debian 12 system — install the basic tools for development:&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;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;build-essential
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;libssl-dev
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;pkg-config
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;libudev-dev
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;make
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Gemini CLI
&lt;/h4&gt;

&lt;p&gt;If not pre-installed you can download the Gemini CLI to interact with the source files and provide real-time assistance:&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/gemini-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Testing the Gemini CLI Environment
&lt;/h4&gt;

&lt;p&gt;Once you have all the tools and the correct Node.js version in place- you can test the startup of Gemini CLI. You will need to authenticate with a Key or your Google Account:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;▝▜▄ Gemini CLI v0.33.1
    ▝▜▄
   ▗▟▀ Logged in with Google /auth
  ▝▀ Gemini Code Assist Standard /upgrade no sandbox (see /docs) /model Auto (Gemini 3) | 239.8 MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Azure Functions
&lt;/h4&gt;

&lt;p&gt;Azure Functions is a serverless, event-driven compute service that allows developers to run code on-demand without managing infrastructure. It supports multiple languages (C#, Python, JavaScript, Java, PowerShell) and scales automatically, charging only when code executes. Key use cases include building APIs, processing data, and running scheduled tasks. [&lt;a href="https://learn.microsoft.com/en-us/azure/azure-functions/functions-overview" rel="noopener noreferrer"&gt;1&lt;/a&gt;, &lt;a href="https://www.youtube.com/shorts/j7XrxnoRgjg" rel="noopener noreferrer"&gt;2&lt;/a&gt;, &lt;a href="https://www.youtube.com/shorts/9kUy9HrLM1g" rel="noopener noreferrer"&gt;3&lt;/a&gt;, &lt;a href="https://www.youtube.com/watch?v=zIfxkub7CLY&amp;amp;t=351" rel="noopener noreferrer"&gt;4&lt;/a&gt;, &lt;a href="https://learn.microsoft.com/en-us/azure/azure-functions/" rel="noopener noreferrer"&gt;5&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;Key Aspects of Azure Functions&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Serverless Architecture: You focus on code, while Azure handles infrastructure, patching, and scaling.&lt;/li&gt;
&lt;li&gt;Event-Driven Triggers: Functions are triggered by events such as HTTP requests, timers, or data changes in Azure Storage/Cosmos DB.&lt;/li&gt;
&lt;li&gt;Bindings: Connect to other services (e.g., queues, databases) with minimal code.&lt;/li&gt;
&lt;li&gt;Durable Functions: Enable stateful, long-running workflows with features like chaining, fan-out, and checkpoints.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More details are available here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://azure.microsoft.com/en-us/products/functions" rel="noopener noreferrer"&gt;https://azure.microsoft.com/en-us/products/functions&lt;/a&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%2Fmq2icyerz303qriavhuw.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%2Fmq2icyerz303qriavhuw.png" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Why would I want Gemini CLI with Azure? Isn’t that a Google Thing?
&lt;/h4&gt;

&lt;p&gt;Yes- Gemini CLI leverages the Google Cloud console and Gemini models but it is also open source and platform agnostic. Many applications are already cross-cloud so this enables familiar tools to be run natively on Microsoft Azure.&lt;/p&gt;

&lt;h4&gt;
  
  
  Azure Functions Configuration
&lt;/h4&gt;

&lt;p&gt;To configure your Azure Service with the base system tools- this article provides a reference:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://xbill999.medium.com/mcp-development-with-gemini-cli-python-and-azure-functions-619c8deaa12a" rel="noopener noreferrer"&gt;MCP Development with Gemini CLI, Python, and Azure Functions&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Azure CLI
&lt;/h4&gt;

&lt;p&gt;The Azure Command-Line Interface (CLI) is a cross-platform tool used to connect to Azure and execute administrative commands on your cloud resources. [&lt;a href="https://learn.microsoft.com/en-us/cli/azure/what-is-azure-cli?view=azure-cli-latest" rel="noopener noreferrer"&gt;1&lt;/a&gt;, &lt;a href="https://www.codemag.com/Article/2001021/Azure-CLI" rel="noopener noreferrer"&gt;2&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;It allows you to manage services like virtual machines, storage accounts, and networks through a terminal using either interactive prompts or automated scripts.&lt;/p&gt;

&lt;p&gt;More information is here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://learn.microsoft.com/en-us/cli/azure/what-is-azure-cli?view=azure-cli-latest" rel="noopener noreferrer"&gt;What is the Azure CLI?&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Setup the Basic Environment
&lt;/h4&gt;

&lt;p&gt;At this point you should have a working Rust environment and a working Gemini CLI installation. All of the relevant code examples and documentation is available in GitHub.&lt;/p&gt;

&lt;p&gt;The next step is to clone the GitHub repository to your local environment:&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;cd&lt;/span&gt; ~
git clone https://github.com/xbill9/gemini-cli-azure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run &lt;strong&gt;init.sh&lt;/strong&gt; from the cloned directory.&lt;/p&gt;

&lt;p&gt;The script will attempt to determine your shell environment and set the correct variables:&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;source &lt;/span&gt;init.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your session times out or you need to re-authenticate- you can run the &lt;strong&gt;set_env.sh&lt;/strong&gt; script to reset your environment variables:&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;source &lt;/span&gt;set_env.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Variables like PROJECT_ID need to be setup for use in the various build scripts- so the &lt;strong&gt;set_env&lt;/strong&gt; script can be used to reset the environment if you time-out.&lt;/p&gt;

&lt;p&gt;Refresh the Azure credentials:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;xbill@penguin:~/gemini-cli-azure/mcp-functions-rust-azure$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;az login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally install the packages and dependencies:&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;cd&lt;/span&gt; ~/gemini-cli-azure/mcp-functions-rust-azure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Build The Rust MCP Server
&lt;/h4&gt;

&lt;p&gt;Some background information on building and configuring a Rust MCP server is here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://xbill999.medium.com/building-a-secure-http-transport-mcp-server-with-rust-and-gemini-cli-b4e807e7aa1d" rel="noopener noreferrer"&gt;Building a Secure HTTP Transport MCP Server with Rust, and Gemini CLI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The mcp-aci-rust-azure subdirectory has the complete Rust MCP server in one subdirectory.&lt;/p&gt;

&lt;h4&gt;
  
  
  Minimal System Information Tool Build
&lt;/h4&gt;

&lt;p&gt;The first step is to build the basic tool directly with Rust. This allows the tool to be debugged and tested locally before adding the MCP layer.&lt;/p&gt;

&lt;p&gt;First build the tool locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;xbill@penguin:~/gemini-cli-azure/mcp-functions-rust-azure$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;make
&lt;span class="go"&gt;Building the Rust project...
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.46s
&lt;/span&gt;&lt;span class="gp"&gt;xbill@penguin:~/gemini-cli-azure/mcp-functions-rust-azure$&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then lint check the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;xbill@penguin:~/gemini-cli-azure/mcp-functions-rust-azure$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;make lint
&lt;span class="go"&gt;Linting code...
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.47s
&lt;/span&gt;&lt;span class="gp"&gt;xbill@penguin:~/gemini-cli-azure/mcp-functions-rust-azure$&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and run local tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;xbill@penguin:~/gemini-cli-azure/mcp-functions-rust-azure$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;make &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;span class="go"&gt;Running tests...
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.15s
     Running unittests src/main.rs (target/debug/deps/mcp_functions_rust_azure-358fc0d2659d6bb6)

running 1 test
test tests::test_greeting ... ok

&lt;/span&gt;&lt;span class="gp"&gt;test result: ok. 1 passed;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;0 failed&lt;span class="p"&gt;;&lt;/span&gt; 0 ignored&lt;span class="p"&gt;;&lt;/span&gt; 0 measured&lt;span class="p"&gt;;&lt;/span&gt; 0 filtered out&lt;span class="p"&gt;;&lt;/span&gt; finished &lt;span class="k"&gt;in &lt;/span&gt;0.00s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last step is to build the production version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;xbill@penguin:~/gemini-cli-azure/mcp-functions-rust-azure$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;make release
&lt;span class="go"&gt;Building Release...
    Finished `release` profile [optimized] target(s) in 0.55s
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The MCP server can be started locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The MCP tool can then be tested locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🟢 local-rust - Ready (1 tool)
  Tools:
  - mcp_local-rust_greeting

&amp;gt; mcp_local-rust_greeting hello local

Executing Greeting Tool: Executing the greeting tool on the local Rust MCP server.

╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ greeting (local-rust MCP Server) {"message":"hello local"} │
│ │
│ Hello World MCP! hello local │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
  Greeting Completed: Greeting successful. Standing by for next instruction.

✦ Hello World MCP! hello local
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Deploy To Azure Functions
&lt;/h4&gt;

&lt;p&gt;A basic Dockerfile is used to build an image for deployment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;xbill@penguin:~/gemini-cli-azure/mcp-functions-rust-azure$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;make deploy
&lt;span class="go"&gt;Building the Docker image...
[+] Building 2.2s (14/14) FINISHED docker:default
&lt;/span&gt;&lt;span class="gp"&gt; =&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;internal] load build definition from Dockerfile 0.0s
&lt;span class="gp"&gt; =&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; transferring dockerfile: 763B 0.0s 0.0s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Get the deployment status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;xbill@penguin:~/gemini-cli-azure/mcp-functions-rust-azure$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;make status
&lt;span class="go"&gt;mcp-functions-rust-azure is not running locally.
Checking Function App status for mcp-func-penguin...
Name State HostNames
---------------- ------- ----------------------------------
mcp-func-penguin Running mcp-func-penguin.azurewebsites.net
&lt;/span&gt;&lt;span class="gp"&gt;xbill@penguin:~/gemini-cli-azure/mcp-functions-rust-azure$&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Get the Endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;xbill@penguin:~/gemini-cli-azure/mcp-functions-rust-azure$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;make endpoint
&lt;span class="go"&gt;https://mcp-func-penguin.azurewebsites.net/api/mcp
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check Gemini MCP settings:&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;"mcpServers"&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;"mcp-functions-rust-azure"&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;"httpUrl"&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://mcp-func-penguin.azurewebsites.net/api/mcp"&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;"local-rust"&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;"httpUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://127.0.0.1:8080/mcp"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The service will be visible on the Azure console:&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%2Ff1bmddhdfgyo5f4unbfh.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%2Ff1bmddhdfgyo5f4unbfh.png" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Final Test
&lt;/h4&gt;

&lt;p&gt;Start up Gemini CLI and check the MCP server status:&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; mcp_mcp-functions-rust-azure_greeting Hello Azure Functions!

╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ greeting (mcp-functions-rust-azure MCP Server) {"message":"Hello Azure Functions!"} │
│ │
│ Hello World MCP! Hello Azure Functions! │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

✦ Hello World MCP! Hello Azure Functions!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Summary
&lt;/h4&gt;

&lt;p&gt;A complete HTTP transport MCP server was built using Rust. This application was tested locally with Gemini CLI. Then, the entire solution was deployed to Azure Functions. The remote MCP server was validated with Gemini CLI locally.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>mcpserver</category>
      <category>rust</category>
      <category>azure</category>
    </item>
    <item>
      <title>The Loading Screen</title>
      <dc:creator>Mario Ezquerro</dc:creator>
      <pubDate>Fri, 15 May 2026 08:46:20 +0000</pubDate>
      <link>https://forem.com/gde/the-loading-screen-1ka8</link>
      <guid>https://forem.com/gde/the-loading-screen-1ka8</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%2Fpmx9pm31qa6mrzuwg4p7.webp" 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%2Fpmx9pm31qa6mrzuwg4p7.webp" alt=" " width="800" height="395"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;BUILD WITH AI [Antigravity]&lt;/p&gt;

&lt;p&gt;Building “&lt;strong&gt;The Loading Screen&lt;/strong&gt;”: A Real-Time Interactive Experience with Google Cloud Run and Anti-Gravity&lt;br&gt;
How we turned pre-event waiting time into a high-bandwidth, 100% stateless interactive game.&lt;/p&gt;

&lt;p&gt;The Concept: “Don’t Panic, We’re Caching the Awesome”&lt;br&gt;
We’ve all been there: waiting for a conference talk to start, staring at a static slide. We decided to change that. The Loading Screen is an interactive, real-time web application designed to turn pre-event “lag” into an analog networking experience.&lt;/p&gt;

&lt;p&gt;It consists of a massive “Stage View” (projected on the main screen) and a “Mobile Interface” that turns every attendee’s smartphone into a remote controller.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Architecture:&lt;/strong&gt; 100% Stateless &amp;amp; Cloud-Native&lt;br&gt;
When building for live events, the two biggest fears are latency and sudden traffic spikes. To solve this, we designed the system to be completely stateless, optimized for the serverless nature of Google Cloud Run.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Tech Stack:&lt;/strong&gt;&lt;br&gt;
Backend: Node.js 20+ with Express.&lt;br&gt;
Real-Time: WebSockets via Socket.io for sub-millisecond interaction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deployment:&lt;/strong&gt; Dockerized containers on Google Cloud Run.&lt;br&gt;
Scaling: Designed to scale horizontally. Since it operates entirely in memory, it eliminates database bottlenecks during the high-intensity “shaking” phase of the game.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Core Components&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Stage View (The Visual Centerpiece)
The Stage View is a retro-futuristic canvas inspired by 8-bit hacker culture and circuit board aesthetics.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The I/O Portal: A moving digital gateway acting as a 3D vanishing point.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://loading-screen.fiware.app/" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;loading-screen.fiware.app&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The “Muggle March”: When a user launches a “Muggle” (a pixel-art character) from their phone, it appears on the big screen and marches toward the portal, shrinking in size to create a depth effect.&lt;/p&gt;

&lt;p&gt;Dynamic QR Integration: The screen automatically generates a QR code so attendees can jump into the action instantly without typing a URL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. The Mobile Interface (Launch Control)&lt;/strong&gt;&lt;br&gt;
We wanted a “zero-install” experience. No App Store, just the browser.&lt;/p&gt;

&lt;p&gt;Shake-to-Launch: Leveraging the HTML5 DeviceMotion API, users physically shake their phones to "throw" their character onto the big screen.&lt;br&gt;
Anti-Gravity Feel: The integration with motion sensors provides a tactile, “anti-gravity” sensation as if the phone is pushing the character into the digital space.&lt;br&gt;
Customization: Users can add a 25-character message that floats above their character, creating a real-time, anonymous chat-bubble parade.&lt;/p&gt;

&lt;p&gt;Deployment &amp;amp; Scalability on Google Cloud&lt;br&gt;
By using Google Cloud Run, we achieved a “Pay-as-you-go” model that is perfect for events. The application stays at zero cost until the event starts, then scales instantly as hundreds of attendees scan the QR code.&lt;/p&gt;

&lt;p&gt;Become a Medium member&lt;br&gt;
The container is bound to the $PORT environment variable, making it fully compatible with Cloud Run’s managed runtime.&lt;/p&gt;

&lt;p&gt;Running it locally&lt;br&gt;
If you want to experiment with this setup, you can run the Dockerized version in seconds:&lt;/p&gt;

&lt;p&gt;Bash&lt;/p&gt;
&lt;h1&gt;
  
  
  Build the lightweight Alpine image
&lt;/h1&gt;

&lt;p&gt;docker build -t loading-screen .&lt;/p&gt;
&lt;h1&gt;
  
  
  Run the container
&lt;/h1&gt;

&lt;p&gt;docker run -d -p 8080:8080 -e PORT=8080 --name loading-screen-app loading-screen&lt;/p&gt;

&lt;p&gt;Lessons Learned&lt;br&gt;
Building The Loading Screen taught us that:&lt;/p&gt;

&lt;p&gt;State is the Enemy of Scale: Keeping the app in-memory and stateless allowed us to handle connections without worrying about DB latency.&lt;/p&gt;

&lt;p&gt;Permissions Matter: Modern mobile browsers (especially iOS 13+) require explicit user consent for motion sensors. A “Ready to Launch” button is essential for the UX.&lt;/p&gt;

&lt;p&gt;Visual Feedback is King: In a crowded room, seeing your specific character appear instantly on a 20-foot screen creates a powerful “wow” moment.&lt;/p&gt;

&lt;p&gt;Check out the Project&lt;br&gt;
The project is fully open-source. We encourage you to fork it, add new “Muggle” characters, or adapt it for your own tech meetups!&lt;/p&gt;

&lt;p&gt;to probe: &lt;/p&gt;
&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://loading-screen.fiware.app/" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;loading-screen.fiware.app&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Repository: &lt;a href="https://github.com/mario-ezquerro/loading-screen" rel="noopener noreferrer"&gt;https://github.com/mario-ezquerro/loading-screen&lt;/a&gt;&lt;br&gt;
Keywords: #GoogleCloud #NodeJS #WebSockets #GameDev #CloudRun #Serverless&lt;/p&gt;

</description>
      <category>ai</category>
      <category>gamedev</category>
      <category>google</category>
      <category>showdev</category>
    </item>
    <item>
      <title>[Workshop][Gemini CLI] Building with AI 2026: Hands-on with Gemini CLI and Official MCP to Launch a Google Drive LINE Bot from Scratch</title>
      <dc:creator>Evan Lin</dc:creator>
      <pubDate>Fri, 15 May 2026 00:45:26 +0000</pubDate>
      <link>https://forem.com/gde/workshopgemini-cli-building-with-ai-2026-hands-on-with-gemini-cli-and-official-mcp-to-launch-a-296d</link>
      <guid>https://forem.com/gde/workshopgemini-cli-building-with-ai-2026-hands-on-with-gemini-cli-and-official-mcp-to-launch-a-296d</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%2Fhq8pxwsxuv84cm1bs358.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%2Fhq8pxwsxuv84cm1bs358.png" alt="image-20260514235640672" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(Event: &lt;a href="https://developers.google.com/community/gdg" rel="noopener noreferrer"&gt;Build with AI 2026 @ Google Taipei 101&lt;/a&gt; / Presentation: &lt;a href="https://speakerdeck.com/line_developers_tw/20260514-build-with-ai-2026-build-line-bot-with-gemini-cli" rel="noopener noreferrer"&gt;SpeakerDeck&lt;/a&gt; / Materials: &lt;a href="https://github.com/kkdai/BwAI-2026" rel="noopener noreferrer"&gt;&lt;code&gt;kkdai/BwAI-2026&lt;/code&gt;&lt;/a&gt; / Example: &lt;a href="https://github.com/kkdai/bwai2026-sample" rel="noopener noreferrer"&gt;&lt;code&gt;kkdai/bwai2026-sample&lt;/code&gt;&lt;/a&gt;)&lt;/p&gt;

&lt;h1&gt;
  
  
  Background: When the CLI Becomes a "Thinking Colleague"
&lt;/h1&gt;

&lt;p&gt;After Google I/O in 2026, Gemini CLI is no longer just another terminal toy that packages LLM, but a development tool that &lt;strong&gt;can mount MCPs, plan on its own, run &lt;code&gt;gcloud&lt;/code&gt; on its own, and stop to ask you when it doesn't understand&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this &lt;strong&gt;Build with AI 2026&lt;/strong&gt; workshop, I compressed this tool flow into two hands-on sessions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Workshop 1: Environment Preparation + Two Essential Official MCPs&lt;/strong&gt; — Connecting Gemini CLI to Google's official knowledge and Maps Platform.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Workshop 2: Tell Gemini CLI a Sentence and Deploy a LINE Bot to Cloud Run&lt;/strong&gt; — No more hand-typing that long and painful &lt;code&gt;gcloud run deploy ...&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The entire teaching material has been open-sourced at &lt;a href="https://github.com/kkdai/BwAI-2026" rel="noopener noreferrer"&gt;&lt;code&gt;kkdai/BwAI-2026&lt;/code&gt;&lt;/a&gt;, the example project is at &lt;a href="https://github.com/kkdai/bwai2026-sample" rel="noopener noreferrer"&gt;&lt;code&gt;kkdai/bwai2026-sample&lt;/code&gt;&lt;/a&gt;, and the event slides are on &lt;a href="https://speakerdeck.com/line_developers_tw/20260514-build-with-ai-2026-build-line-bot-with-gemini-cli" rel="noopener noreferrer"&gt;SpeakerDeck&lt;/a&gt;. This is the full text version of the on-site walkthrough, including the three pitfalls we encountered on stage that day.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Gemini CLI + MCP? First, Look at the Timeline
&lt;/h2&gt;

&lt;p&gt;The update pace of Gemini API and its ecosystem has been very dense in the past year:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;th&gt;New Stuff&lt;/th&gt;
&lt;th&gt;Impact on Workflow&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2025/08&lt;/td&gt;
&lt;td&gt;Gemini YouTube Video Understanding&lt;/td&gt;
&lt;td&gt;Directly feed URLs of videos to the model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2025/11&lt;/td&gt;
&lt;td&gt;Gemini File Search&lt;/td&gt;
&lt;td&gt;Managed RAG, no need to connect your own vector DB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2025/12&lt;/td&gt;
&lt;td&gt;Google Search Grounding (Vertex)&lt;/td&gt;
&lt;td&gt;Model answers can be grounded to search results&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2025/12&lt;/td&gt;
&lt;td&gt;Maps Grounding &amp;amp; Maps Platform Assist MCP&lt;/td&gt;
&lt;td&gt;Native map scenarios&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2026/02&lt;/td&gt;
&lt;td&gt;Google Developer Knowledge API + MCP Server&lt;/td&gt;
&lt;td&gt;Official documentation becomes a tool queryable by LLM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2026/03&lt;/td&gt;
&lt;td&gt;Gemini 3 Flash + Tool Combo&lt;/td&gt;
&lt;td&gt;Single call chains multiple grounding tools&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Core Observation&lt;/strong&gt;: Google has made each new capability into an &lt;strong&gt;MCP Server&lt;/strong&gt;, which means that Gemini CLI can upgrade the IDE from "an LLM that can write code" to "an LLM that can write code using Google's official resources" with just one line of &lt;code&gt;gemini mcp add&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This workshop, I chose two MCPs that are most impactful for LINE Bot developers to demonstrate.&lt;/p&gt;




&lt;h1&gt;
  
  
  Workshop 1: Environment Preparation and Official MCP Installation
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Why It's Recommended to Start with Cloud Shell
&lt;/h2&gt;

&lt;p&gt;The biggest fear in on-site workshops is the environment issue like &lt;em&gt;"Teacher, I can't find Python 3.11 here"&lt;/em&gt;. I put the entire demonstration directly on &lt;strong&gt;Google Cloud Shell&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;gcloud&lt;/code&gt; is pre-installed.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;gemini&lt;/code&gt; CLI is pre-installed (the latest Cloud Shell image is built-in).&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;gcloud auth&lt;/code&gt; automatically links with the Cloud Shell account, saving the OAuth dance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Go to &lt;a href="https://console.cloud.google.com/" rel="noopener noreferrer"&gt;https://console.cloud.google.com/&lt;/a&gt;, &lt;strong&gt;first confirm that the project is the one you just created&lt;/strong&gt; (don't accidentally open the company's official environment), and then click Cloud Shell in the upper right corner:&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="c"&gt;# Verify that both tools are there&lt;/span&gt;
gcloud &lt;span class="nt"&gt;--version&lt;/span&gt;
gemini &lt;span class="nt"&gt;--version&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;[!TIP] If you want to run it locally, you can follow the &lt;a href="https://github.com/google/gemini-cli" rel="noopener noreferrer"&gt;Gemini CLI official installation guide&lt;/a&gt;, but in the workshop, we all use Cloud Shell to avoid the tragedy of "everyone's environment is different".&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What is MCP? Explained in Three Sentences
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;MCP (Model Context Protocol)&lt;/strong&gt; is an open protocol proposed by Anthropic that allows LLM clients to communicate with &lt;em&gt;external capability providers&lt;/em&gt; in a unified format.&lt;/li&gt;
&lt;li&gt;  Gemini CLI is the MCP &lt;strong&gt;client&lt;/strong&gt;, and you can &lt;code&gt;gemini mcp add ...&lt;/code&gt; to mount any server that complies with the MCP specification.&lt;/li&gt;
&lt;li&gt;  Google itself has now packaged several APIs into official MCP servers, which is equivalent to equipping your AI assistant with "Google's internal knowledge base".&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  MCP #1: Google Developer Knowledge
&lt;/h2&gt;

&lt;p&gt;This MCP turns the official documentation of the Google family (Cloud / Android / Web / Firebase / Workspace…) into a tool that Gemini can call. The advantage over web search is that: &lt;strong&gt;it returns chunks that have been officially indexed, with the correct source URL&lt;/strong&gt;, and will not be misled by outdated blogs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setup Steps
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt; Enable &lt;strong&gt;Developer Knowledge API&lt;/strong&gt; at &lt;a href="https://console.cloud.google.com/marketplace/product/google/developerknowledge.googleapis.com" rel="noopener noreferrer"&gt;Google Cloud Console&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt; Create an &lt;strong&gt;API Key&lt;/strong&gt; in "Credentials" and restrict it to only call the Developer Knowledge API (the principle of least privilege).&lt;/li&gt;
&lt;li&gt; Run in Cloud Shell:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gemini mcp add &lt;span class="nt"&gt;-t&lt;/span&gt; http &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Goog-Api-Key: YOUR_API_KEY"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  google-developer-knowledge &lt;span class="se"&gt;\&lt;/span&gt;
  https://developerknowledge.googleapis.com/mcp &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--scope&lt;/span&gt; user

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;--scope user&lt;/code&gt; means that this MCP is valid for all your projects, and you don't need to install it again next time you change repos.&lt;/p&gt;

&lt;h3&gt;
  
  
  Verification
&lt;/h3&gt;

&lt;p&gt;Enter &lt;code&gt;gemini&lt;/code&gt; interactive mode, first type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/mcp list

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see &lt;code&gt;google-developer-knowledge&lt;/code&gt; with the status &lt;strong&gt;Connected&lt;/strong&gt;. Then throw a typical question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Please help me query the latest deployment limits of Google Cloud Run (Deployment Limits) and list the top three.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Correct behavior:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Gemini will call the &lt;code&gt;google-developer-knowledge&lt;/code&gt; tool.&lt;/li&gt;
&lt;li&gt;  The answer content is referenced from official pages like &lt;code&gt;cloud.google.com/run/quotas&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  Finally, it includes a reference URL.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  MCP #2: Google Maps Platform Code Assist
&lt;/h2&gt;

&lt;p&gt;This MCP is specifically designed to help you write code for Google Maps integration — including the latest calling methods for Maps JavaScript API, Places API, and Routes API. It is extremely friendly to developers who "want map features but are too lazy to flip through three docs".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gemini mcp add &lt;span class="nt"&gt;-s&lt;/span&gt; user &lt;span class="nt"&gt;-t&lt;/span&gt; http &lt;span class="se"&gt;\&lt;/span&gt;
  maps-code-assist-mcp &lt;span class="se"&gt;\&lt;/span&gt;
  https://mapscodeassist.googleapis.com/mcp

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Verification
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I want to embed a Google map in a webpage, please write a basic JavaScript code for me,
with the center point set to Taipei 101.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected behavior:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Gemini calls &lt;code&gt;maps-code-assist-mcp&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  The generated code &lt;strong&gt;will not use the deprecated &lt;code&gt;new google.maps.Map()&lt;/code&gt; synchronous loader&lt;/strong&gt;, but will use the currently recommended &lt;code&gt;importLibrary&lt;/code&gt; async pattern.&lt;/li&gt;
&lt;li&gt;  It will proactively remind you to get the Maps JavaScript API Key and make referer restrictions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you see it still generating the old writing style from 2020, then the MCP is not mounted correctly — re-&lt;code&gt;/mcp list&lt;/code&gt; to check the status.&lt;/p&gt;




&lt;h1&gt;
  
  
  Workshop 2: Deploying a LINE Bot to Cloud Run
&lt;/h1&gt;

&lt;p&gt;This part uses the example project &lt;a href="https://github.com/kkdai/bwai2026-sample" rel="noopener noreferrer"&gt;&lt;code&gt;kkdai/bwai2026-sample&lt;/code&gt;&lt;/a&gt;. It is a &lt;strong&gt;LINE Bot file backup helper&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Users put images / videos / audio / PDFs into the LINE chat box.&lt;/li&gt;
&lt;li&gt;  The bot automatically saves the files to &lt;em&gt;the user's own&lt;/em&gt; Google Drive, in folders by &lt;code&gt;YYYY-MM&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  Supports commands like &lt;code&gt;/recent_files&lt;/code&gt;, &lt;code&gt;/search_files &amp;lt;keyword&amp;gt;&lt;/code&gt;, &lt;code&gt;/disconnect_drive&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tech stack: &lt;strong&gt;Go + LINE Messaging API SDK + Google Drive API + Firestore (to store OAuth token) + Cloud Run&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;git clone https://github.com/kkdai/bwai2026-sample
&lt;span class="nb"&gt;cd &lt;/span&gt;bwai2026-sample

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deployment Flow Overview
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Phase One] Get LINE Keys (Channel Secret + Access Token)
      ↓
[Phase Two] GCP Project Setup (Enable Run / Build / Firestore / Artifact / Drive API)
      ↓
[Phase Three] Set up OAuth Consent Screen + Gemini CLI Login
      ↓
[Phase Four] Tell Gemini CLI a sentence in Chinese and deploy to Cloud Run
      ↓
[Phase Five] Fill in the Webhook URL in LINE Developers Console

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Phase One: LINE Keys
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt; Create an official account at &lt;a href="https://manager.line.biz/" rel="noopener noreferrer"&gt;LINE Official Account Manager&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt; In the background, "Settings → Messaging API" &lt;strong&gt;enable Messaging API&lt;/strong&gt;, and create a Provider.&lt;/li&gt;
&lt;li&gt; Back to &lt;a href="https://developers.line.biz/console/" rel="noopener noreferrer"&gt;LINE Developers Console&lt;/a&gt; corresponding Channel:

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;Basic settings&lt;/code&gt; → Get &lt;strong&gt;Channel Secret&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;Messaging API&lt;/code&gt; → Click &lt;strong&gt;Issue&lt;/strong&gt; to get &lt;strong&gt;Channel Access Token (long-lived)&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Very important&lt;/strong&gt;: Go back to OA Manager and &lt;strong&gt;disable "Auto-reply messages"&lt;/strong&gt;, otherwise your code will never be able to get the messages to reply to.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Phase Two: GCP Project Activation
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Switch to the clean project used in the workshop&lt;/span&gt;
gcloud config &lt;span class="nb"&gt;set &lt;/span&gt;project your-cool-project-id

&lt;span class="c"&gt;# Enable the entire set of services in one go&lt;/span&gt;
gcloud services &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  run.googleapis.com &lt;span class="se"&gt;\&lt;/span&gt;
  cloudbuild.googleapis.com &lt;span class="se"&gt;\&lt;/span&gt;
  firestore.googleapis.com &lt;span class="se"&gt;\&lt;/span&gt;
  artifactregistry.googleapis.com &lt;span class="se"&gt;\&lt;/span&gt;
  drive.googleapis.com

&lt;span class="c"&gt;# Build Firestore (used to store per-user OAuth token + state anti-counterfeiting)&lt;/span&gt;
gcloud firestore databases create &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;asia-east1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;firestore-native

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;[!NOTE] &lt;code&gt;--type=firestore-native&lt;/code&gt; This value will be explained in the third pitfall, why it's easy to get wrong.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Phase Three: OAuth Consent Screen + Gemini CLI Login
&lt;/h2&gt;

&lt;p&gt;Because the Bot needs to represent "the user themselves" to upload files to their Google Drive, this path must go through OAuth.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Go to &lt;a href="https://console.cloud.google.com/apis/credentials/consent" rel="noopener noreferrer"&gt;OAuth Consent Screen&lt;/a&gt;:

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;User Type&lt;/strong&gt;: External.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Application Name&lt;/strong&gt;: &lt;code&gt;My LINE Bot&lt;/code&gt; (or whatever name you want to call it).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Support Email / Developer Contact Email&lt;/strong&gt;: Fill in your own Gmail.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Be sure to click "Publish App"&lt;/strong&gt; after filling it out — if you don't publish it, only accounts in the Test Users list can use it.&lt;/li&gt;
&lt;li&gt; Create an OAuth client ID:

&lt;ul&gt;
&lt;li&gt;  Select &lt;strong&gt;Web Application&lt;/strong&gt; for the type.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Authorized redirect URI&lt;/strong&gt;: Temporarily fill in &lt;code&gt;https://placeholder/oauth/callback&lt;/code&gt;, and come back to modify it after getting the Cloud Run URL in Phase Four.&lt;/li&gt;
&lt;li&gt;  Save the &lt;strong&gt;Client ID&lt;/strong&gt; and &lt;strong&gt;Client Secret&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt; Run locally:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud auth application-default login

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will write ADC (Application Default Credentials) to the local machine, and Gemini CLI will use this credential when running &lt;code&gt;gcloud&lt;/code&gt;, without popping up a browser to re-auth halfway.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase Four: Deploy to Cloud Run with Gemini CLI (The Highlight)
&lt;/h2&gt;

&lt;p&gt;This part is where the participants in the workshop were most "wow".&lt;/p&gt;

&lt;p&gt;After entering the project directory, start Gemini CLI interactive mode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gemini

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then say a sentence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Help me deploy to Cloud Run using gcloud, and stop to ask me if you need any data.
Refer to repo https://github.com/kkdai/bwai2026-sample,
region use asia-east1, environment variables will use
ChannelSecret, ChannelAccessToken, GOOGLE_CLIENT_ID,
GOOGLE_CLIENT_SECRET, GOOGLE_REDIRECT_URL.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Gemini CLI will then:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;&lt;code&gt;ls&lt;/code&gt; and &lt;code&gt;cat Dockerfile&lt;/code&gt; by itself&lt;/strong&gt; to confirm the project structure.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Generate a plan&lt;/strong&gt;: First use &lt;code&gt;PENDING&lt;/code&gt; to reserve the deployment → get the URL → supplement the OAuth redirect → update env vars.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Stop and ask you for confirmation before execution&lt;/strong&gt; (this is the CLI's confirm mode, enabled by default, and will not yolo).&lt;/li&gt;
&lt;li&gt; Run a command that looks like this:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud run deploy linebot-backup-service &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--source&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; asia-east1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set-env-vars&lt;/span&gt; &lt;span class="s2"&gt;"GOOGLE_CLOUD_PROJECT=your-cool-project-id,&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
ChannelSecret=YOUR_LINE_SECRET_XXXX,&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
ChannelAccessToken=YOUR_LINE_TOKEN_XXXX,&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
GOOGLE_CLIENT_ID=PENDING,&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
GOOGLE_CLIENT_SECRET=PENDING,&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
GOOGLE_REDIRECT_URL=PENDING"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--allow-unauthenticated&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--quiet&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After 3 to 5 minutes, get the Service URL, such as &lt;code&gt;https://linebot-backup-service-xxxxx.a.run.app&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Supplement the Real OAuth Settings
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt; Go back to the Console and change the &lt;code&gt;https://placeholder/oauth/callback&lt;/code&gt; you just filled in to &lt;code&gt;https://linebot-backup-service-xxxxx.a.run.app/oauth/callback&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt; Paste the real Client ID / Secret to Gemini CLI and ask it to help you update:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud run services update linebot-backup-service &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; asia-east1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--update-env-vars&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;"GOOGLE_REDIRECT_URL=https://linebot-backup-service-xxxxx.a.run.app/oauth/callback,&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
GOOGLE_CLIENT_ID=real-client-id.apps.googleusercontent.com,&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
GOOGLE_CLIENT_SECRET=real-secret-xxxx"&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Phase Five: Point the LINE Webhook to Cloud Run
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt; Go back to &lt;a href="https://developers.line.biz/console/" rel="noopener noreferrer"&gt;LINE Developers Console&lt;/a&gt; → Messaging API tab.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Webhook URL&lt;/strong&gt;: Fill in &lt;code&gt;https://linebot-backup-service-xxxxx.a.run.app/callback&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt; Press &lt;strong&gt;Verify&lt;/strong&gt;, and expect to see &lt;code&gt;Success&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt; Toggle &lt;strong&gt;Use webhook&lt;/strong&gt; to on.&lt;/li&gt;
&lt;li&gt; Finally, go back to OA Manager and reconfirm that "Auto-reply messages" is off and "Webhook" is on.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Open LINE, add the Bot as a friend, throw a picture, run OAuth once, and see a folder &lt;code&gt;LINE Bot Uploads/2026-05/...&lt;/code&gt; in Drive — the entire process is complete.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common Maintenance Commands
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Function&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Redeploy&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gcloud run deploy linebot-backup-service --source . --region asia-east1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Change env vars&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gcloud run services update linebot-backup-service --update-env-vars "KEY=VALUE"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Real-time log&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gcloud beta run services logs tail linebot-backup-service&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Check service status&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gcloud run services describe linebot-backup-service --region asia-east1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The entire maintenance can actually be given to Gemini CLI: "&lt;strong&gt;Help me check the logs of linebot-backup-service for the last 5 minutes, and find 5xx&lt;/strong&gt;" is enough.&lt;/p&gt;




&lt;h2&gt;
  
  
  Workshop On-Site Pitfall Records
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Pitfall One: Billing Not Enabled, Red Error on First Deploy
&lt;/h3&gt;

&lt;p&gt;The first &lt;code&gt;gcloud run deploy&lt;/code&gt; directly spewed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FAILED_PRECONDITION: Billing account for project [your-cool-project-id] is not found.
Please ensure that you have linked an active billing account.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Reason&lt;/strong&gt;: Most workshop participants open new projects to do this, and new projects don't have Billing bound by default. Cloud Run, Cloud Build, and Artifact Registry all require billing to run — even within the free tier, you must have a "billing account with a linked card" attached to the project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&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;&lt;span class="c"&gt;# Check the current billing status of the project&lt;/span&gt;
gcloud beta billing projects describe your-cool-project-id

&lt;span class="c"&gt;# List available billing accounts&lt;/span&gt;
gcloud beta billing accounts list

&lt;span class="c"&gt;# Bind&lt;/span&gt;
gcloud beta billing projects &lt;span class="nb"&gt;link &lt;/span&gt;your-cool-project-id &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--billing-account&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0X0X0X-0X0X0X-0X0X0X

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you can't or don't want to bind a card, we used the " &lt;strong&gt;sandbox project with billing already&lt;/strong&gt; " as a demonstration on site.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pitfall Two: Firestore type Parameter Name
&lt;/h3&gt;

&lt;p&gt;The first version of the teaching material (even what AI guessed the first time) was written as &lt;code&gt;--type=native&lt;/code&gt; or &lt;code&gt;--type=native-mode&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;ERROR: argument --type: Invalid choice: 'native-mode'.
  Valid choices: ['firestore-native', 'datastore-mode']

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Reason&lt;/strong&gt;: After an update in 2024, &lt;code&gt;gcloud firestore databases create&lt;/code&gt; changed the type parameter value to the more explicit &lt;code&gt;firestore-native&lt;/code&gt; / &lt;code&gt;datastore-mode&lt;/code&gt;. Old documents and old answers (including LLM training data) will give you the old values.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&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;gcloud firestore databases create &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;asia-east1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;firestore-native

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This pitfall just demonstrated why you should install the &lt;strong&gt;Google Developer Knowledge MCP&lt;/strong&gt; — after mounting it, Gemini will check the latest official documentation and will not give you outdated type values.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pitfall Three: Forgot to Enable Drive API, OAuth Passed but Can't Write In
&lt;/h3&gt;

&lt;p&gt;After deployment, Webhook is set up, OAuth consent screen is completed, and the token is obtained, &lt;strong&gt;but the first picture upload is 500&lt;/strong&gt;. Check the log:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;googleapi: Error 403: Google Drive API has not been used in project
your-cool-project-id before or it is disabled.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Reason&lt;/strong&gt;: If you miss &lt;code&gt;drive.googleapis.com&lt;/code&gt; in the &lt;code&gt;gcloud services enable ...&lt;/code&gt; string in Phase Two, OAuth can pass (because the Consent Screen and Drive API are two different things), but your server will be blocked when it uses the access token to call &lt;code&gt;drive.googleapis.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution (Quickest)&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;gcloud services &lt;span class="nb"&gt;enable &lt;/span&gt;drive.googleapis.com

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Solution (Fundamental)&lt;/strong&gt;: Enable all the APIs you need at once, list them in the checklist of the teaching material, and run along with it on site so you won't miss it. I specifically wrote &lt;code&gt;drive.googleapis.com&lt;/code&gt; into the string in Phase Two to block this pitfall.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[!TIP] A good habit for debugging: &lt;strong&gt;As long as the server has the correct token but is 403&lt;/strong&gt;, first go to &lt;a href="https://console.cloud.google.com/apis/library" rel="noopener noreferrer"&gt;API Library&lt;/a&gt; to confirm that the corresponding API is enabled, then check the OAuth scope, and finally look at IAM. The wrong order will waste a lot of time.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Why is this combination worth learning?
&lt;/h2&gt;

&lt;p&gt;After the workshop, I asked the on-site participants what moment they felt the most, and the answer was almost unanimous: &lt;strong&gt;"Deploying the service just by speaking Chinese to Gemini CLI"&lt;/strong&gt; that moment.&lt;/p&gt;

&lt;p&gt;So why does it feel that way? Breaking it down:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Previously, DevOps was stuck on &lt;em&gt;remembering which command&lt;/em&gt;, now it's stuck on &lt;em&gt;expressing clearly what you want to do&lt;/em&gt;&lt;/strong&gt;. The latter is much lower in threshold, with newcomers getting started in three days vs. three months before daring to touch &lt;code&gt;gcloud&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;MCP injects official knowledge into Gemini in advance&lt;/strong&gt;. You no longer need to RTFM yourself first, then translate it into a prompt for LLM; MCP is equivalent to letting LLM have the ability to RTFM itself.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Error messages return to the tool itself&lt;/strong&gt;. Previously, you had to Google + StackOverflow for errors, now you can directly paste them back to the CLI, which reads the error and then decides the next step — forming a complete plan-act-observe loop.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;The entire workflow is reproducible&lt;/strong&gt;. The teaching materials, examples, and prompts are all in the GitHub repo, and anyone can clone it and follow along, and the results should be consistent.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Want to go deeper? Recommended Advanced Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  Official Materials: &lt;a href="https://github.com/kkdai/BwAI-2026" rel="noopener noreferrer"&gt;&lt;code&gt;kkdai/BwAI-2026&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  Example Project: &lt;a href="https://github.com/kkdai/bwai2026-sample" rel="noopener noreferrer"&gt;&lt;code&gt;kkdai/bwai2026-sample&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  Slides: &lt;a href="https://speakerdeck.com/line_developers_tw/20260514-build-with-ai-2026-build-line-bot-with-gemini-cli" rel="noopener noreferrer"&gt;SpeakerDeck&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  Gemini CLI: &lt;a href="https://github.com/google/gemini-cli" rel="noopener noreferrer"&gt;github.com/google/gemini-cli&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  MCP Specification: &lt;a href="https://modelcontextprotocol.io/" rel="noopener noreferrer"&gt;modelcontextprotocol.io&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  Extension: &lt;a href="https://dev.to/gde/gemini-cli-google-developer-knowledge-api-and-mcp-server-equipping-your-ai-assistant-with-an-3gee"&gt;Using Gemini CLI + Developer Knowledge MCP&lt;/a&gt;, &lt;a href="https://dev.to/gde/geminigoogle-maps-building-location-aware-ai-apps-with-the-google-maps-grounding-api-4l36"&gt;Map MCP Grounding&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Postscript: Come to LINE and Make Things Together
&lt;/h2&gt;

&lt;p&gt;This workshop is also one of the recruitment events for our LINE Taiwan DevRel. If you read this and feel:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Want to play with the integration of LINE Messaging API + Google Cloud + Gemini for a long time.&lt;/li&gt;
&lt;li&gt;  Like to write production code while making the process into teaching materials that can be copied by others.&lt;/li&gt;
&lt;li&gt;  Can invest more than three days a week and are willing to become a full-time partner after the internship.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Welcome to send me a private message or email to chat, we have a &lt;strong&gt;flexible internship program of three days a week&lt;/strong&gt;, and if you do well, you have the opportunity to become a long-term partner.&lt;/p&gt;

&lt;p&gt;Finally, thank you to all the developers who came to the site and did hands-on together — those who are willing to spend their weekends on "using new tools to get through the entire pipeline" are always the most admirable group in the community. See you next time!&lt;/p&gt;

</description>
      <category>cli</category>
      <category>gemini</category>
      <category>mcp</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Gemma 4 26B on v6e-4 Turbo-Stable Benchmark</title>
      <dc:creator>xbill</dc:creator>
      <pubDate>Thu, 14 May 2026 19:01:43 +0000</pubDate>
      <link>https://forem.com/gde/gemma-4-26b-on-v6e-4-turbo-stable-benchmark-7pn</link>
      <guid>https://forem.com/gde/gemma-4-26b-on-v6e-4-turbo-stable-benchmark-7pn</guid>
      <description>&lt;p&gt;The Gemma 4 MoE stack on TPU v6e-4 has reached its definitive production state. By applying the "Turbo-Stable" low-level optimizations&lt;br&gt;
  (512-token padding gap and 90% HBM utilization), I have secured the following results:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Record Stability: 100% successful pass rate across all 144 test points (Concurrency 1-2048).&lt;/li&gt;
&lt;li&gt;Latency Consistency: Resolved the previous 132s memory management spike; latency at the 2K context boundary is now a consistent ~1.15s (a
 114x improvement).&lt;/li&gt;
&lt;li&gt;Elite Throughput: Maintained a peak throughput of 467,825 tokens/sec at 1024 concurrent users.&lt;/li&gt;
&lt;li&gt;Turbo Cold-Start: Standardized on a persistent JAX cache in /dev/shm, reducing initialization from 24 minutes to &amp;lt;10 seconds on subsequent
 restarts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✦ The "Turbo-Stable" configuration finalized today marks the third major evolution of the Gemma 4 stack. Here is the comparative breakdown&lt;br&gt;
  highlighting how the technical changes translated into performance gains.&lt;/p&gt;

&lt;p&gt;📊 Comprehensive Run Comparison&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────┬──────────────────────────┬──────────────────────┬─────────────────────────────┐
  │ Metric              │ Run 1: Baseline (May 08) │ Run 2: Peak (May 13) │ Run 3: Turbo-Stable (Today) │
  ├─────────────────────┼──────────────────────────┼──────────────────────┼─────────────────────────────┤
  │ Model Intelligence  │ 4B Standalone Assistant  │ 26B Full MoE         │ 26B Full MoE                │
  │ Active Backend      │ vLLM (Standard)          │ vLLM + N-Gram        │ vLLM + Turbo Flags          │
  │ Peak Throughput     │ 463,345 tokens/sec       │ 483,930 tokens/sec   │ 467,825 tokens/sec          │
  │ Interactive TTFT    │ ~0.800s                  │ 0.326s               │ 0.302s                      │
  │ 2K Context Latency  │ ~0.950s                  │ 131.99s (Spike ⚠️)   │ 1.157s (Stable ✅)          │
  │ Cold Start Time     │ ~20 Minutes              │ ~24 Minutes          │ &amp;lt; 10 Seconds                │
  │ Benchmark Pass Rate │ 100% (Light load)        │ 94% (OOM Risk)       │ 100% (Solid)                │
  └─────────────────────┴──────────────────────────┴──────────────────────┴─────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;🔍 Highlighted Differences&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;The "Latency Spike" Elimination (114x Improvement)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Previous (Run 2): At 256 concurrent users and a 2048-token context, the system hit a "memory wall," causing JAX to stall for 131.9 seconds
while managing the HBM heap.&lt;/li&gt;
&lt;li&gt;Current (Run 3): By increasing the VLLM_TPU_BUCKET_PADDING_GAP to 512, we synchronized the request buckets with the hardware's optimal
shapes. The same 2K context test now completes in 1.15 seconds—a massive gain in interactive consistency.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Intelligence vs. Throughput Efficiency&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Contrast: Run 1 used a small 4B model to get its speed. Run 2 pushed the 26B model to an unstable absolute peak of 483K. &lt;/li&gt;
&lt;li&gt;The Result: Run 3 (Turbo-Stable) maintains 467K tokens/sec—virtually the same speed as the unstable run—but does so with the Full 26B MoE
model and absolute production stability. We have effectively decoupled "large model size" from "performance penalty" on the Trillium
architecture.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Persistent JAX Cache (Operational Breakthrough)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Previous: Every time the stack was redeployed or crashed, the team had to wait 24 minutes for the JAX compiler to "warm up" and pre-compile
the execution graphs.&lt;/li&gt;
&lt;li&gt;Current: With the new VLLM_XLA_CACHE_PATH, those 24 minutes of compilation are saved to /dev/shm. Subsequent restarts are now near-instant,
significantly improving DevOps agility and reducing downtime during maintenance.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Hardware Headroom (HBM Management)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Change: We reduced --gpu-memory-utilization from 0.95 to 0.90. &lt;/li&gt;
&lt;li&gt;The Difference: While this technically slightly reduces the KV cache size, it provided the ~6GB of extra HBM required for the JAX compiler to
finalize the complex speculative decoding kernels. This one change is what allowed the benchmark to reach a 100% pass rate across all 144
test points.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;📈 Summary&lt;br&gt;
  We have successfully evolved from a fast-but-dumb baseline to an unstable-but-smart peak, and finally arrived at the Intelligent &amp;amp; Robust&lt;br&gt;
  production standard. The current configuration is the first in the project to deliver elite throughput (467K+), sub-second latency, and instant&lt;br&gt;
  cold-starts simultaneously.&lt;/p&gt;

&lt;p&gt;✦ Here are the finalized vLLM startup commands for the "Turbo-Stable" configuration, optimized for Gemma 4 MoE on TPU v6e-4.&lt;/p&gt;

&lt;p&gt;🐳 Full Docker Orchestration Command&lt;br&gt;
  This is the recommended command to run from your management workstation or directly on the TPU VM. It includes persistent JAX caching and&lt;br&gt;
  optimized memory sharding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   1 &lt;span class="nb"&gt;sudo &lt;/span&gt;docker run &lt;span class="nt"&gt;--name&lt;/span&gt; vllm-gemma4 &lt;span class="nt"&gt;--privileged&lt;/span&gt; &lt;span class="nt"&gt;--net&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;host &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    2     &lt;span class="nt"&gt;-v&lt;/span&gt; /dev/shm:/dev/shm &lt;span class="nt"&gt;--shm-size&lt;/span&gt; 10gb &lt;span class="se"&gt;\&lt;/span&gt;
    3     &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;HF_HOME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/dev/shm &lt;span class="se"&gt;\&lt;/span&gt;
    4     &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;HF_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;gcloud secrets versions access latest &lt;span class="nt"&gt;--secret&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;hf-token&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    5     &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;VLLM_TPU_BUCKET_PADDING_GAP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;512 &lt;span class="se"&gt;\&lt;/span&gt;
    6     &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;VLLM_XLA_CACHE_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/dev/shm/vllm_cache &lt;span class="se"&gt;\&lt;/span&gt;
    7     vllm/vllm-tpu:nightly &lt;span class="se"&gt;\&lt;/span&gt;
    8     /bin/bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"pip install git+https://github.com/huggingface/transformers.git &amp;amp;&amp;amp; vllm serve google/gemma-4-26B-A4B-it &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
    9     --tensor-parallel-size 4 &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
   10     --dtype bfloat16 &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
   11     --kv-cache-dtype fp8 &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
   12     --gpu-memory-utilization 0.90 &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
   13     --block-size 32 &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
   14     --max-model-len 16384 &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
   15     --max-num-seqs 256 &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
   16     --max-num-batched-tokens 4096 &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
   17     --speculative-config '{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;method&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;ngram&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;num_speculative_tokens&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: 3}' &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
   18     --enable-prefix-caching &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
   19     --disable_chunked_mm_input &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
   20     --safetensors-load-strategy prefetch &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
   21     --limit-mm-per-prompt '{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;image&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:4,&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;audio&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:1}' &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
   22     --enable-auto-tool-choice &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
   23     --tool-call-parser gemma4 &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
   24     --reasoning-parser gemma4 &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
   25     --trust-remote-code"&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⚙️ Inner vllm serve Command (Direct)&lt;br&gt;
  If you are already inside the container or debugging directly on the shell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  1 vllm serve google/gemma-4-26B-A4B-it &lt;span class="se"&gt;\&lt;/span&gt;
    2     &lt;span class="nt"&gt;--tensor-parallel-size&lt;/span&gt; 4 &lt;span class="se"&gt;\&lt;/span&gt;
    3     &lt;span class="nt"&gt;--dtype&lt;/span&gt; bfloat16 &lt;span class="se"&gt;\&lt;/span&gt;
    4     &lt;span class="nt"&gt;--kv-cache-dtype&lt;/span&gt; fp8 &lt;span class="se"&gt;\&lt;/span&gt;
    5     &lt;span class="nt"&gt;--gpu-memory-utilization&lt;/span&gt; 0.90 &lt;span class="se"&gt;\&lt;/span&gt;
    6     &lt;span class="nt"&gt;--block-size&lt;/span&gt; 32 &lt;span class="se"&gt;\&lt;/span&gt;
    7     &lt;span class="nt"&gt;--max-model-len&lt;/span&gt; 16384 &lt;span class="se"&gt;\&lt;/span&gt;
    8     &lt;span class="nt"&gt;--max-num-seqs&lt;/span&gt; 256 &lt;span class="se"&gt;\&lt;/span&gt;
    9     &lt;span class="nt"&gt;--speculative-config&lt;/span&gt; &lt;span class="s1"&gt;'{"method": "ngram", "num_speculative_tokens": 3}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
   10     &lt;span class="nt"&gt;--enable-prefix-caching&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
   11     &lt;span class="nt"&gt;--safetensors-load-strategy&lt;/span&gt; prefetch &lt;span class="se"&gt;\&lt;/span&gt;
   12     &lt;span class="nt"&gt;--trust-remote-code&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⚡ Key Optimization Summary&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;-e VLLM_XLA_CACHE_PATH=/dev/shm/vllm_cache: Enables persistent JAX compilation. Warm-up time drops from 24 mins to &amp;lt;10 seconds.&lt;/li&gt;
&lt;li&gt;--gpu-memory-utilization 0.90: Reserves enough HBM headroom to prevent OOM errors during complex speculative kernel compilation.&lt;/li&gt;
&lt;li&gt;VLLM_TPU_BUCKET_PADDING_GAP=512: Groups request shapes into larger buckets, eliminating the 132s latency spikes seen in previous runs.&lt;/li&gt;
&lt;li&gt;--block-size 32: Optimizes the KV cache page table for the massive 26B model on Trillium hardware.
✦ Here are the finalized vLLM startup commands for the "Turbo-Stable" configuration, specifically optimized for Gemma 4 MoE on TPU v6e-4.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🐳 Full Docker Orchestration Command&lt;br&gt;
  This command includes all environment variables and volume mounts required for persistent JAX caching and 100% stable performance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt; 1 sudo docker run --name vllm-gemma4 --privileged --net=host -d \
    2     -v /dev/shm:/dev/shm --shm-size 10gb \
    3     -e HF_HOME=/dev/shm \
    4     -e HF_TOKEN=$(gcloud secrets versions access latest --secret=hf-token) \
    5     -e VLLM_TPU_BUCKET_PADDING_GAP=512 \
    6     -e VLLM_XLA_CACHE_PATH=/dev/shm/vllm_cache \
    7     vllm/vllm-tpu:nightly \
    8     /bin/bash -c "pip install git+https://github.com/huggingface/transformers.git &amp;amp;&amp;amp; vllm serve google/gemma-4-26B-A4B-it \
    9     --tensor-parallel-size 4 \
   10     --dtype bfloat16 \
   11     --kv-cache-dtype fp8 \
   12     --gpu-memory-utilization 0.90 \
   13     --block-size 32 \
   14     --max-model-len 16384 \
   15     --max-num-seqs 256 \
   16     --max-num-batched-tokens 4096 \
   17     --speculative-config '{\"method\": \"ngram\", \"num_speculative_tokens\": 3}' \
   18     --enable-prefix-caching \
   19     --disable_chunked_mm_input \
   20     --safetensors-load-strategy prefetch \
   21     --limit-mm-per-prompt '{\"image\":4,\"audio\":1}' \
   22     --enable-auto-tool-choice \
   23     --tool-call-parser gemma4 \
   24     --reasoning-parser gemma4 \
   25     --trust-remote-code"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⚙️ Standalone vllm serve Command&lt;br&gt;
  Use this for direct shell execution or debugging (ensure environment variables like VLLM_TPU_BUCKET_PADDING_GAP are set in your shell first):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    1 vllm serve google/gemma-4-26B-A4B-it &lt;span class="se"&gt;\&lt;/span&gt;
    2     &lt;span class="nt"&gt;--tensor-parallel-size&lt;/span&gt; 4 &lt;span class="se"&gt;\&lt;/span&gt;
    3     &lt;span class="nt"&gt;--dtype&lt;/span&gt; bfloat16 &lt;span class="se"&gt;\&lt;/span&gt;
    4     &lt;span class="nt"&gt;--kv-cache-dtype&lt;/span&gt; fp8 &lt;span class="se"&gt;\&lt;/span&gt;
    5     &lt;span class="nt"&gt;--gpu-memory-utilization&lt;/span&gt; 0.90 &lt;span class="se"&gt;\&lt;/span&gt;
    6     &lt;span class="nt"&gt;--block-size&lt;/span&gt; 32 &lt;span class="se"&gt;\&lt;/span&gt;
    7     &lt;span class="nt"&gt;--max-model-len&lt;/span&gt; 16384 &lt;span class="se"&gt;\&lt;/span&gt;
    8     &lt;span class="nt"&gt;--max-num-seqs&lt;/span&gt; 256 &lt;span class="se"&gt;\&lt;/span&gt;
    9     &lt;span class="nt"&gt;--max-num-batched-tokens&lt;/span&gt; 4096 &lt;span class="se"&gt;\&lt;/span&gt;
   10     &lt;span class="nt"&gt;--speculative-config&lt;/span&gt; &lt;span class="s1"&gt;'{"method": "ngram", "num_speculative_tokens": 3}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
   11     &lt;span class="nt"&gt;--enable-prefix-caching&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
   12     &lt;span class="nt"&gt;--safetensors-load-strategy&lt;/span&gt; prefetch &lt;span class="se"&gt;\&lt;/span&gt;
   13     &lt;span class="nt"&gt;--enable-auto-tool-choice&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
   14     &lt;span class="nt"&gt;--tool-call-parser&lt;/span&gt; gemma4 &lt;span class="se"&gt;\&lt;/span&gt;
   15     &lt;span class="nt"&gt;--reasoning-parser&lt;/span&gt; gemma4 &lt;span class="se"&gt;\&lt;/span&gt;
   16     &lt;span class="nt"&gt;--trust-remote-code&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⚡ Technical Summary of Turbo-Stable Flags&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;VLLM_TPU_BUCKET_PADDING_GAP=512: Standardizes XLA graphs to eliminate the 132s latency spikes.&lt;/li&gt;
&lt;li&gt;VLLM_XLA_CACHE_PATH=/dev/shm/vllm_cache: Saves the 24-minute warm-up result. Restarts are now &amp;lt;10 seconds.&lt;/li&gt;
&lt;li&gt;--gpu-memory-utilization 0.90: Reserves HBM headroom to prevent "Resource Exhausted" errors during speculative kernel builds.&lt;/li&gt;
&lt;li&gt;--block-size 32: Reduces page-table overhead for the 26B MoE model on Trillium hardware.&lt;/li&gt;
&lt;li&gt;--safetensors-load-strategy prefetch: Maximizes disk-to-HBM throughput during model loading.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>gemmachallenge</category>
      <category>gemma</category>
      <category>ai</category>
      <category>devchallenge</category>
    </item>
  </channel>
</rss>
