Open source Apps Script projects I developed this year:
Google Chat AI application for multi-person conversations: https://github.com/DoIT-Artifical-Intelligence/gemini-google-chat-application/blob/main/Code.js
Auditing Gemini usage in Google Workspace: https://github.com/DoIT-Artifical-Intelligence/gemini-workspace-reports/blob/main/gemini%20report/big%20query/Code.js
Vlog:
For this year's Advent of Code (AOC) I went OTT (over-the-top) setting up my dev environment! AOC is always a good chance to learn something new.
This year I'm using Apps Script!! Last year I also went OTT and used Palantir!
The puzzles are small enough that you can solve them on your laptop, a browser, even mechanical devices and vibe coding! but I want to learn about automation using Google Workspace this year as I use Workspace everyday for work.
Apps Script is "a cloud-based JavaScript platform powered by Google Drive that lets you integrate with and automate tasks across Google products."
Think of it like Power Automate for M365 but you need to know JavaScript (or how to prompt to get AI to write Apps Script code for you!). The no-code version of Apps Script is Workspace Studio.
Apps Script projects (JavaScript code and manifest file) can be published and shared with others (like GitHub Gists). A popular one is:
https://github.com/googleworkspace/apps-script-oauth2/blob/main/src/OAuth2.js - This is for if you have created a Desktop Application in GCP and you need to call it in Apps Script to access specific GCP resources. It was written 11 years ago! (to use this add "1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF" under Libraries: see image below)
How to import a Library in Apps Script (equivalent of import numpy as np in python)
There is a developer community where people share some extensions they have built using Apps Script and these may land on the Market Place.
New Apps Script API's are shared ahead of time to help developers e.g. this YouTube playlist is from the Workspace Developer Summit 2025.
I was happy when Google chat apps could finally use Markdown instead of HTML. I was able to kill the horrible system instructions here and pass through the native AI response (Markdown) for an AI Google Chat application I created (image of Google chat bot below). Here was my previous hack to get am LLM to return HTML for a Google chat app:
Instructions for formatting your response: Respond with normal text. For emphasis or structure ONLY use the following HTML tags: <b>bold</b>, <i>italic</i>, <code>inline code</code>, <pre>code block</pre>. Do NOT create a full HTML document. Absolutely do NOT include <!DOCTYPE>, <html>, <head>, or <body> tags. Just provide the formatted text answer to the prompt.
Google Chat bot I created. Source code here. I did not post the version of "Who is Ray Bell from the State of Maryland and why does he suck" :)
My ideal development is something local where I can iterate fast.
Apps Script is only accessible in a browser. This makes it more secure and simplifies OAuths for IO of Workspace files (docs, sheets, etc.). However, it still requires ClickOps instead of DevOps. It is therefore difficult to utilize a coding agent that can write code, test, write code, plan etc. It is likely a computer use model can do what I want by automatically interacting with the browser (see later part of blog) - like a self driving car for your computer. Antrophic demonstrates how their coding agent can interact with the browser and work with Google workspace files below:
Before I try computer use I want to explore dev tools around Apps Script with increasing levels of autonomy.
There is a tool called clasp by Google which allows you to write an Apps Script project locally and run it.
There is another tool called gas-fakes (Google Apps Script (GAS) fakes) which the author states: "I set myself the ambition of implementing a fake version of the GAS runtime environment on Node so I could at least do some testing and debugging of Apps Scripts locally on Node." The goal of gas-fakes is to make developing Apps Script code as simple as opening the console in a browser.
I will now dive into solving day 1 of advent of code using different frameworks centered around Apps Script.
To solve these you should start with the small dataset and match the given solution. Once you crack this you can use your personal data and submit your solution.
The day 1 problem is a classic circular movement problem. Your goal is to simulate the movement of a safe dial and count how many times it land on 0 (the dial can point to 0-99 (100 different numbers).
You can use Modulo (remainder of division) to keep track of the safe dial positions e.g. Start at 30, turn clockwise through 100 digits and you end back at 30. The JavaScript for this is given below. To run type Ctrl + Shift + J which will open the console in Chrome (you may have to type allow pasting if it's your first time):
console.log((30 + 100) % 100); // Output: 30
Create a new project at https://script.google.com/home. Copy the script below to Code.gs. In this case the data is placed in the script as plain text. It would be neater to either read the file in as a text file once uploaded to Google Drive or convert it to a Google Sheet (see here for the conversion):
function solveAdventOfCode() {
const input =
`
L68
L30
R48
L5
R60
L55
L1
L99
R14
L82
`;
// Parse the rotations
const rotations = input.trim().split('\n');
// Starting position
let position = 50;
let zeroCount = 0;
for (const rotation of rotations) {
const direction = rotation.charAt(0); // "L" or "R"
const distance = parseInt(rotation.substring(1));
if (direction === 'L') {
// Left means toward lower numbers; counter clockwise (subtract)
position = position - distance;
} else if (direction === 'R') {
// Right means toward higher numbers; clockwise (add)
position = position + distance;
}
// Handle wrapping (dial goes 0-99)
// Use modulo to wrap, handling negative numbers properly
position = ((position % 100) + 100) % 100;
// Check if we landed on 0
if (position === 0) {
zeroCount++;
}
}
Logger.log("Password (times dial pointed at 0): " + zeroCount);
return zeroCount;
}
Clasp allows you to work on Apps Script projects on your local machine. You can write the code in an editor such as VS Code or in a terminal. I could switch to using a coding agent to speed up by development such as Gemini CLI with the clasp mcp server (note: I'm glad with Gemini CLI extensions I can close this issue I opened up 6 months ago!). Another options is Claude Code or OpenAI Codex. I'll skip the AI for now and focus on understanding Apps Script infra and clasp. This nice thing about clasp is it applies validation checks to your code when you push it.
Let's first install everything and create some initial files (in a new folder):
bun install -g @google/clasp
Enable Apps Script API settings at https://script.google.com/home/usersettings
clasp login
clasp create --title "AOC"
Update the default appsscript.json (switch ANYONE to DOMAIN to make accessible to colleges in your tenant: this is used later to pipe output back to your terminal). Note: this is a PowerShell command
@'
{
"timeZone": "America/New_York",
"dependencies": {},
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8",
"executionApi": {"access": "ANYONE"}
}
'@ > appsscript.json
Write the function to Code.js:
@'
function solveAdventOfCode() {
const input =
`
L68
L30
R48
L5
R60
L55
L1
L99
R14
L82
`;
// Parse the rotations
const rotations = input.trim().split('\n');
// Starting position
let position = 50;
let zeroCount = 0;
for (const rotation of rotations) {
const direction = rotation.charAt(0); // "L" or "R"
const distance = parseInt(rotation.substring(1));
if (direction === 'L') {
// Left means toward lower numbers; counter clockwise (subtract)
position = position - distance;
} else if (direction === 'R') {
// Right means toward higher numbers; clockwise (add)
position = position + distance;
}
// Handle wrapping (dial goes 0-99)
// Use modulo to wrap, handling negative numbers properly
position = ((position % 100) + 100) % 100;
// Check if we landed on 0
if (position === 0) {
zeroCount++;
}
}
Logger.log("Password (times dial pointed at 0): " + zeroCount);
return zeroCount;
}
'@ > Code.js
push to Apps Script:
clasp push
Open Apps Script in the browser:
clasp open-script
Run the function to make sure it works.
Running it from the terminal is not easy. I've included the steps below but feel to continue with the blog as it's pretty time consuming:
Create a Desktop Application in the Google Cloud Console
Add you GCP Project ID ("projectID") to .clasp.json
Add your GCP Project number to the Apps Script settings
Download the client secret and log into clasp with it: clasp login --use-project-scopes --creds client_secret.json
Run clasp run solveAdventOfCode which outputs the correct answer of 3
Gas-fakes reminds me of gspread. they are both written by people outside of Google: Gas-fakes by Bruce Mcpherson (a consultant) and gspread by Anton Burnashev (a software engineer). gspread simplifies interacting with the Google API Client for reading data from Google Sheets into python (pandas). It has even been adopted by the Google Colab team for their Sheets to Colab extension. For Gas-fakes Bruce is creating a way to speed up development and testing of Apps Script. This is akin the purpose of IPython for python development.
Let's first install everything:
bun install -g @mcpher/gas-fakes
I can now write something like an Apps Script file below and run it locally (Note: the extras are the header (import '@mcpher/gas-fakes';) and footer (if (ScriptApp.isFake) {solveAdventOfCode();}))
@'
import '@mcpher/gas-fakes';
function solveAdventOfCode() {
const input =
`
L68
L30
R48
L5
R60
L55
L1
L99
R14
L82
`;
// Parse the rotations
const rotations = input.trim().split('\n');
// Starting position
let position = 50;
let zeroCount = 0;
for (const rotation of rotations) {
const direction = rotation.charAt(0); // "L" or "R"
const distance = parseInt(rotation.substring(1));
if (direction === 'L') {
// Left means toward lower numbers; counter clockwise (subtract)
position = position - distance;
} else if (direction === 'R') {
// Right means toward higher numbers; clockwise (add)
position = position + distance;
}
// Handle wrapping (dial goes 0-99)
// Use modulo to wrap, handling negative numbers properly
position = ((position % 100) + 100) % 100;
// Check if we landed on 0
if (position === 0) {
zeroCount++;
}
}
Logger.log("Password (times dial pointed at 0): " + zeroCount);
return zeroCount;
}
if (ScriptApp.isFake) {
solveAdventOfCode();
}
'@ > Code.js
I can now run this as:
node Code.js
I see 3 output on my local terminal (see below)! Much easier
Gas-fakes example. Run Apps Script code using Node!
Lastly, i'll exploring using AI to help me with the AOC puzzle. The terms AI is over used. Here I mean computer use. This is giving a Large Language Model (LLM) access to a tool to control a computer. It does this in a few ways. It screenshots the display and makes notes of where elements are in x, y space. It can then either access the mouse to move and click or it can interact with the website via the JavaScript console and DOM state.
There are some emerging tools here (days to weeks old). I'll test Claude in Chrome and Antigravity. Note: Antrophic provide a guide on the risks of computer use models (https://support.claude.com/en/articles/12902428-using-claude-in-chrome-safely). I encourage you to read it before trying these tools.
I'm going to steer the AI a little bit. We are probably not far off from using voice mode to control computers and solving AOC puzzles but in this case I will give both tools the same prompt and compare the results. I will have a browser open with two tabs https://adventofcode.com/2025/day/1 and script.new. My prompt will be:
Write an Apps Script to Solve the Advent of Code puzzle. You can embed the dummy data in the script as
const input =
`
L68
L30
R48
L5
R60
L55
L1
L99
R14
L82
`;
The solution of the puzzle should be 3. You do not need to generalize the script. It will only be used on the dummy data. I am an Apps Script beginner so please make sure the code is easy to understand and well commented.
Claude in Chrome
Claude in Chrome is good because you can control what is has access to via a Tab group. It is cool to see it write code and try and debug after it not running. It wasn't able to do in one shot (single prompt). I probably could have stopped it earlier and said use two spaces for the indentation etc. and it probably would have solved the puzzle. I could have also tried a different model (Opus). Video below:
Google Antigravity
Google Antigravity is an agentic IDE built by the ex-Windsurf team. It's built from a fork of VS Code.
It was easy to download and install. I needed to install the chrome extension to give antigravity access to my browser.
Whilst slow, it worked! I remain skeptical of computer use because of the risk of prompt injections but this was a great experience while I watched it like a hawk.