Skip to content

March 13, 2025

How I Built a Google Docs Add-On in Three Hours (Using Vibe Engineering)

By Gene Kim

So, I’m writing a book with Steve Yegge (famous for his 20 years at Amazon and Google) on how developers can use GenAI to do amazing things. The working title is “The CHOP Handbook: The End Of Programming As We Know It, and Why It Will Be The Best Thing Ever For Developers.”

We’re considering new titles like “Chat and Vibe Engineering for Professionals,” “Vibe Engineering In Production,” or maybe even “No Vibe Coding When I’m On Call” (thank you, Jessie Young!). Why the name change? Dr. Andrej Karpathy recently coined the term “vibe coding,” which has generated such a stir in the dev community.

Regardless of the title, our goal is to show developers how they can use GenAI to:

  • Build things faster.
  • Be more ambitious about things you can build.
  • Do it alone, rather than depending on a team.
  • Have more fun doing it.
  • And, explore vastly larger design spaces

In December, I marveled that I used Python to do statistical analysis in a Google Colab notebook, something I had previously done for decades only using SPSS. At the time, I thought that was a huge achievement in itself. 

However, last month, I did something that made that seem trivial by comparison: I wrote a Google Docs Add-On in three hours, using AI and “vibe engineering” —the term we’re leaning into for the book.

Why “vibe engineering,” as opposed to “vibe coding?” Dr. Karpathy talks about vibe coding where you sort of turn your brain off. We’re describing something different — you don’t turn your brain off, and instead, you crank it way up, because with the help of AI, you’re solving challenging problems you could never do alone. You are using AI as another engineering tool.

I built a Google Docs Add-On in a language I barely understand, TypeScript. I’ve spent hundreds of hours in JavaScript, and maybe 20 hours in TypeScript — and I’ll be the first to admin that I barely understand most ES6 syntax.

The purpose of the Google Docs add-on was to explore the sibling of CHOP (Chat-Oriented Programming), which started jokingly calling CHOW, or Chat-Oriented Writing. (GitHub repo link at bottom of the post!)

Short Aside: CHOP/CHOW Reminds Me of a DevOps Joke

It’s not just CHOP and CHOW.  There’s a whole universe of activities in which you can use the same techniques for getting an AI to help you do your work.  Maybe we can express this pattern as:

  • Chat-Oriented *: (Chat-Oriented Everything)
  • Chat-Oriented (?<activity>+)$: the more precise regular expression (harhar)

Some of you probably realize the joke I stole there. Theo Schlossnagle had this wonderful line about DevOps. He pointed out that “DevOps is often incomplete, misinterpreted, and too isolated. It’s not really DevOps anymore, but rather…” —and then he showed a bunch of regular expressions, which was hilarious.

  • DevOps: incomplete
  • Dev.*Ops: meaning “Dev Everything Ops”
  • (?<dept>+)Ops$: a more precise regex pattern that matches any department followed by “Ops”

Get it? DevOps, DevSecOps, MarketingDevSecOps, MarketingDevSecOpsSales, etc…

Let’s Skip JavaScript Editor Frameworks—Let’s Do a Google Docs Add-On!

Since last fall, I had been experimenting with JavaScript editor frameworks to find some way to better enable AI workflows to review and revise my text. I thought that Slate.js would be an amazing tool to create an easy editing environment. I had done some experiments, but nothing really seemed all that promising.

However, after talking to Steve on a Friday, we started running into a problem: I was getting better results using Claude to help review and revise text for the book than Steve was. In my mind, there is a very important meta observation here: CHOP and CHOW are orthogonal, but they involve the same techniques: context and prompts.

Months ago, in the CHOP domain, Steve noticed that I was getting pretty subpar results with AI-assisted coding—during our pair programming session, he showed me how much better I could get at prompting. Sometimes by prompting less, sometimes more.

In the CHOW domain, a need started becoming evident. We needed a tool that could standardize the prompt generation process so that we could both get the same results when doing CHOW.

That’s when the idea of using a Google Docs add-on came up. In his infectious and energetic way, Steve convinced me that building one was within my reach. Despite the fact that I knew absolutely nothing about them. I wasn’t sure I could pull this off.

However, buoyed by my many successes in the last couple of months, I decided to give it a try. After all, Steve was here to help me, and the payoff could be huge. We were spending so much time in Google Docs working on the book manuscript.

Just in case you don’t know what a Google Docs Add-On is, here’s a screenshot of one I use a lot for book projects.

  1. The Extensions menu item is where active Add-Ons reside
  2. The Sidebar that every Add-On renders — that’s essentially your UI
  3. The Table of Contents Add-On I use, so it can be more like Microsoft Word auto-heading numbering
  4. My CHOW Add-On, waiting to be activated!

Remarkably, in just three hours, I was able to build a functioning Google Docs Add-On. I was really, really blown away by my ability to accomplish this — I was bragging about it to almost everyone I talked with about it.

Here was the goal: Inside Google Docs, select text I wanted to review/revise/work with Claude. In my Add-On sidebar, click a button to have it generate a prompt. It would include the entire mansucript (spanning three different Google Doc files), include the task instructions, and the highlighted section being worked on. And generate a massive prompt that I could copy into Claude to review/critique/revise.

Once Again, Learn While Walking the Dog

Okay, so where do you start with a project like this when you don’t know anything?

Again, I found myself walking a dog, and as Simon Willison taught us to do, I started using ChatGPT in voice mode. I spent almost 45 minutes in this conversation, exploring two main topics.

My first question was simple: I described what I wanted to build and asked, “Is this even something that I could build as a Google Docs add-on?” I learned that they are written in Google Apps Script, which I had used almost 12 or 13 years ago. I kept asking it to prove that this was possible, and it eventually convinced me that it could indeed be done.

Once I had gained a bit of understanding, the next question came into focus: “Once I build my add-on, how do I actually deploy and use it?” ChatGPT explained that you can deploy it to the marketplace, or you can deploy it in test mode for your own documents. (It also described all the ways you can build and add on: You can build it as part of a document, or you build it so that you can use it in any document. I screwed this up a couple of times.)

In the next 20 minutes, I then asked about how one could write code not in the in-browser Google Apps Script IDE environment but on my laptop. I was surprised to learn that there is a tool called CLASP that does exactly that.

At that point, I had heard enough. I was convinced that I could build this. Let’s go!

Google Apps Script: My Second Encounter

Google Docs add-ons are written in Google Apps Script (GAS from here on). I used GAS once for one project about 12 years ago to build an email autoresponder, which still runs today. It was my first experience with writing JavaScript. You go to https://script.google.com/home/, and you’ll see an in-browser IDE. For a long time, GAS only executed an ancient version of JavaScript (ES3!!!), but now it supports ES6 (sort of).

(As much as I will complain about GAS, it is really quite remarkable. According to this article, “Apps Script is just as popular inside Google as it is among external users and developers. In fact, there are more than 70,000 weekly active scripts written by thousands of Googlers.” You can use it to add custom functions to Google Sheets and Google Docs. It enables access to the APIs of most Google properties. It’s like Visual Basic, but for Google Apps. Keep reading for caveats.)

To get started, I once asked ChatGPT to explain how to use CLASP to create a GAS project, synchronize files, and push my files. I studied the GitHub repo, reading the README and their fantastic tutorials.

I manage to get it working, so it’s time to code!

The Revelation of Augment Code

For this project, I wanted to try out Augment Code, which was absolutely awesome. In some ways, it is similar to using Claude Code. You don’t do a lot of highlighting of text. You just type what you want, and it suggests modifications to your code. To my surprise, it handled multi-file editing seamlessly—it just seems to know what files need to be changed (just like Claude Code). And it applies the code suggestions as fast (or faster) than Cursor.

This was a month ago, but the prompts I remember typing sounded like:

  • Create a button that brings up a dialog box. (I then learned that `ui.alert` can have a Yes/No button—who knew?)
  • Get the selection that is currently highlighted in the Google Docs editor.
  • Make a new button called “Reload Sidebar”. Make a button to put something in the clipboard.

In less than an hour, I managed to get a very simple Google Docs add-on working, with a simple sidebar and a counter. It was comprised of an HTML file, which renders the sidebar, and a .gs file, which is the JavaScript that was transpiled by CLASP using TypeScript.

I couldn’t believe I was actually starting to build something that looked like a real Google Docs add-on!

My next prompt was: “Make a new button called ‘Load Document’ and store it in a global variable.”

Then the sledding got pretty rough.

Google Apps Script API Documentation Leaves A Lot To Be Desired

I actually bought a book on GAS seven years ago: “Going GAS: From VBA to Google Apps Script.” When I found myself sufficiently bewildered by how Google Docs add-ons worked, I found myself reading it again, but I got a little impatient. I started hacking around and eventually realized two things.

First, my mental model of how the Google Docs add-ons work was completely wrong. There are actually two pieces to it:

1. The front end is the HTML file, and you can run JavaScript code that you put there inside of <script> tags.
2. The back end is the GS file.

To my surprise, there is no shared memory between the two. Communication occurs via remote procedure call, triggered by using the Google.script.run API. And I’m pretty sure that the front end can only run ES3, while the back end runs something different in those .GS files— something like, but not exactly JavaScript. But Clasp allows you to write it in TypeScript/ES6l and transpiles it into those .GS files.

Where was that documented? I have no idea. (I was having lots of trouble finding documentation for things I was trying to do in GAS. And I think because there is so little documentation, Claude kept hallucinating APIs that didn’t exist. More on that later.)

But that actually paled in comparison to a much bigger problem.

Fixing The Horrible 15-Second, Six-Step Feedback Loop

The issue was that reloading modified GAS code required so many steps. I would make a change on my laptop, save the file, and push it to GAS using CLASP. And then I have to go back to my Google Docs instance, click the Extensions menu bar, and click the “Reload Sidebar” menu item.

This was really intolerable. I’m accustomed to hot code reloading in Clojure and ClojureScript, which is typical in many JavaScript environments—you save your file and see the changes immediately.

This situation felt like the opposite—it was probably 15 seconds to get feedback on my work, and so much clicking! When your AI is giving you bad API calls that don’t exist, it’s really interolable that it takes so work to determine whether your code works or not.

I spent about two hours across two days trying to get as close to a hot reload as possible. Fortunately, CLASP has a watch mode that can monitor for local file changes, which can trigger the TypeScript transpilation and push into GAS.

I eventually got it down to clicking a “Reload Sidebar” button, which was so much better than before, which required multiple clicks inside a menu item.

Now that I got a reasonable developer experience going, it was time to tackle the API documentation problem.

OpenAI Deep Research To The Rescue

I hit a brick wall because I managed to get the Google Docs add-on working for one document, but I couldn’t figure out how to deploy it so that I could use it in any Google Docs environment. I searched for help and couldn’t find anything.

I was at a total standstill. Fortunately, OpenAI Deep Research came to the rescue. The prompt:

  • I have written a Google Apps Script Workspace Add-On. I have a test deployment add-on deployed: deployment ID is xxxx. How do I use it in any Google Doc?

It came back after 10 minutes and gave me almost 10 pages of instructions on what to do — here’s the ChatGPT session doc, in case this helps someone in the future. After some hacking around, I finally got it working. (Note my use of OpenAI Deep Research to find the solution, and o3-mini-high to use that knowledge to solve my problems.)

The biggest problem was that I just couldn’t find the Add-On icon! Who knew that it would show up as an icon on the right sidebar? In the screenshot at the top of the post, my icon is #4. (Where was that documented? )

Oh, I also had to use Google Deep Research and o1-preview or o3-high to figure out how to create a working “Reload Sidebar” button! (Every other attempt with any other model closed the sidebar and terminated the program before the reload finished.)

(When I told Steve this, he quipped, “I complained about GAS not getting any love back in my platform rant in 2011. It’s been 13+ years, and those pancake heads at Google still haven’t figured out that, yes, platforms really do matter. I’m sure GAS wants to do more but gets zero resourcing.” Haha. You always learn a bunch hanging out with Steve. 😆)

But once I got the add-on running inside my Google Doc, things started really cooking. Looking through the Git repo, my prompts must have looked like this:

  • Create function to convert the Google Doc data to Markdown.
  • Write tests for the above that could run inside Google Apps Script in the in-browser IDE. (This wasn’t great, but some tests that are inconvenient to run are better than no tests at all, because I couldn’t understand the giant JavaScript function, with lots of regular expression.)
  • Concatenate multiple Google Docs together (because our manuscript spans multiple Google Docs).
  • Add word count to the sidebar.
  • Create a dropdown box in the sidebar to enable multiple prompts. (Wow! I barely know how dropdown boxes work!)
  • Build tests for assembling the different types of prompts.
  • Help me clean up the mess I made in the sidebar.html file, because I had <script> tags scattered all over the place.
  • Introduce some global variables to manage persistent state.
  • Remove global variables and use the Google Apps Script API for key-value pairs.

Oh, another thing I did to improve my developer experience was putting my log messages in the sidebar! Google Docs add-on logging can be cumbersome—the front end can’t log to the browser console (console.log doesn’t work), and the back end logs only show up in the in-browser GAS IDE.

The Success Moment

I started this project on a Saturday morning. Late on Sunday night, I texted Steve that I was going to do my first roundtrip using CHOW. That meant I would use my CHOW tool to highlight some text, click a button, which would take the Google Docs files and the selection to generate a prompt in JSON. It would then copy it to the clipboard, so I could paste it into Claude.

In Claude, I could critique the section, review and revise it, and then copy it back into our manuscript in Google Docs.

Here’s the screenshot I took of the Add-On, and a video of me using the tool.

The first minute shows the add-on in action; the second minute demonstrates augment code making quick usability changes while pushing it into Google Apps Script. In the third minute, I showcase how quickly the “Apply” operations occur, and in the eighth minute, I illustrate how CHOW evaluates a section, critiques it, and uses Claude to implement changes.

Another challenge I encountered with the Google Docs add-on was obtaining logging information. I utilized the sidebar to display logs, and I was thrilled when Steve successfully installed the Google Docs add-on. Having others use your extension without publishing it in the marketplace can be quite cumbersome, but he managed to clone the repository and deploy it in his environment, which was great.

I was elated that Steve successfully installed the Google Docs add-on so he could use it himself. (He gave up trying to follow the instructions, and instead cloned my repo, and deploy it in his Google environment.)

Reinforced Lessons

As I reflected on what I had accomplished with this Google Docs add-on project, I realized something important about how AI is changing the way I learn and build.

You often don’t need to understand all the code: This was the strange realization from my Python experience: “I don’t actually need to understand all of this code. For easy stuff, I visually inspect the results, and if the results look correct, we’re good.”

But for some code, you definitely have to write tests. Luckily, Claude was great at it. (Honestly, I don’t understand how the tests work. It uses some mocking technique I don’t understand. I showed it to a longtime QA professional, and he instantly recognized it. All I cared about was that I could write tests that fail and pass.)

You need fast feedback. What use is fast code generation if you can’t test it equally quicklyI This was a weak point for GAS. I couldn’t figure out how to run automated tests inside of GAS, and I spent two hours making it easy to push changes and reload quickly. It was time very well spent.

Errors need to be easily accessible so you can quickly copy/paste into an LLM: Unfortunately, GAS is not great in this regard; because errors are buried inside the in-browser GAS IDE, and console messages can’t go to the browser console. (My solution was to copy them into the add-on DOM)

An Embarrassing Moment Exposing My Lack Of Understanding Of My Code

An embarrassing moment occurred when Steve questioned a specific portion of the code, Google.script.run, asking why it was called twice. He made fun of me, suggesting I didn’t catch the LLM doing something stupid.

I promised to fix it. But I realized the next day that it wasn’t slow due to the multiple calls; the multiple calls were actually required because of callbacks. In fact, it was being called three times: once for the script call, once on success, and once on failure.

There’s a lesson here, but what it is exactly eludes me right now.

(Moreover, my attempt to use async/await to fix the “callback hell” problem didn’t work. As I mentioned, I think it’s because the JavaScript in the HTML appears must be the ES3 version of JavaScript, which dates back to the early 2010s.)

Vibe Engineering Is Amazing

For me, this represents an entirely new way of programming and writing. I was able to build a program in a language and ecosystem I barely knew. I’m using this tool nearly every day, and I couldn’t have done it without AI. I was able to:

  • Build things faster.
  • Be more ambitious about the things I can build.
  • Do it alone rather than depending on a team.
  • Have more fun doing it.
  • And, explore vastly larger design spaces.

Oh, and here’s the link to the repo: https://github.com/realgenekim/chow-addon

Huzzah!

We’re Looking For GenAI/Dev Experience Reports

The Enterprise Technology Leadership Summit in Las Vegas in September will be featuring amazing experience reports — one of the focus areas is how technology leaders are using GenAI to make developers more productive! Register or submit a talk proposal here!

- About The Authors
Avatar photo

Gene Kim

Gene Kim has been studying high-performing technology organizations since 1999. He was the founder and CTO of Tripwire, Inc., an enterprise security software company, where he served for 13 years. His books have sold over 1 million copies—he is the WSJ bestselling author of Wiring the Winning Organization, The Unicorn Project, and co-author of The Phoenix Project, The DevOps Handbook, and the Shingo Publication Award-winning Accelerate. Since 2014, he has been the organizer of DevOps Enterprise Summit (now Enterprise Technology Leadership Summit), studying the technology transformations of large, complex organizations.

Follow Gene on Social Media

No comments found

Leave a Comment

Your email address will not be published.



Jump to Section

    More Like This

    How I Built a Google Docs Add-On in Three Hours (Using Vibe Engineering)
    By Gene Kim

    So, I'm writing a book with Steve Yegge (famous for his 20 years at…

    How I Broke My 20-Year SPSS Habit To Vibe Code Something in a Python Colab Notebook
    By Gene Kim

    So, I'm writing a book with Steve Yegge (famous for his 20 years at…

    Flow Engineering Immersion Course: Transform How Teams Work Together
    By Leah Brown

    We're excited to announce that the Flow Engineering Immersion Course, the third installment in…

    Becoming a Better Leader Part 2: Building Trust Through Understanding
    By Leah Brown

    Trust is the foundation of effective leadership. Yet in many organizations, trust remains elusive—especially…