Skip to content

udacity/agentic-loop-webinar

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Build the Executive Assistant yourself

This folder contains everything you need to run the Ralph agentic loop and build the Executive Assistant app from scratch — one user story at a time, by your own Claude Code instance, with no human in the inner loop.

It contains a simplified version of the Ralph Loop designed to work with Claude Code only. Visit the Ralph Loop Repository to learn more or use the original version with AMP or other Models/LLM Ecosystems. Read the original Ralph Loop post here

What's in this folder

File Role
ralph.sh The bash loop that spawns one fresh Claude Code instance per iteration
ITERATION.md The per-iteration prompt — fed to Claude Code as input each iteration
prd.json The executable task list — 24 user stories, all passes: false, ready to be built
progress.txt Empty append-only log; Ralph writes learnings here between iterations
CLAUDE.md.template A starter project-root CLAUDE.md (rename and place at the repo root before you run)
seed/ Python utility + fixture data that populates your test Google account with fake emails and calendar events
README.md This file

What you'll build

A single-screen dashboard over your test Google account's Calendar and Gmail, with capabilities grouped into three categories:

  • Schedule — Today's Schedule, Next Free Block, Tomorrow Preview, Back-to-Back Alert, Week at a Glance, Meeting Context
  • Inbox — Needs a Reply (with triage tags), VIP Watch, Noise Report, Draft Replies
  • Smart (LLM-backed) — Action Items, Morning Brief, Day in a Sentence, What to Tackle First

The integration is live REST via the googleapis SDK. Drafts are the only thing the app writes back to Gmail.


Prerequisites

1. Tooling on your machine

  • Node.js 22+ — check with node -v. Install or upgrade from nodejs.org or via nvm.
  • Python 3.10+ (for the seeder only) — check with python3 --version.
  • Claude Code CLI: npm install -g @anthropic-ai/claude-code (then run claude once and complete sign-in).
  • git — check with git --version.

2. A throwaway Google account

Never run this against a real account. Create a fresh Gmail account just for this build — the seeder injects fake emails and calendar events, and the EA will create real Gmail drafts in it.

3. A Google Cloud Platform (GCP) account

The EA reads Gmail and Calendar through Google's REST APIs, which means you need a Google Cloud project that owns the API credentials. GCP is separate from your Gmail account — Gmail gives you a mailbox; GCP gives you a developer console where you create OAuth clients and turn APIs on/off.

  • Go to console.cloud.google.com and sign in with the throwaway Google account from step 2 (important — the credentials and the mailbox must belong to the same account).
  • If this is your first time, Google will prompt you to accept the GCP Terms of Service and pick a country. Do that.
  • GCP requires a billing account on the parent organization for some services, but this project only uses free-tier APIs (Gmail + Calendar read/draft). You should not need to add a credit card. If Google nags you for one to "activate" something, the Gmail and Calendar APIs themselves do not require it — skip that step.

4. Create a Google Cloud project and enable the APIs

Note: Google rearranges Cloud Console menus every few months. The conceptual steps below stay the same, but the exact button labels or nav paths may have shifted slightly by the time you read this. If something is named differently, look for the closest match — the screenshots in Google's official docs at developers.google.com/workspace/guides/create-credentials are kept current.

  1. Create the project:
    • In the Cloud Console top bar, click the project selector (says "Select a project") → NEW PROJECT.
    • Project name: anything memorable, e.g. ea-build.
    • Organization: "No organization" is fine for a personal Gmail account.
    • Click CREATE, then wait ~10 seconds for the project to provision.
    • Make sure the top-bar project selector now shows your new project — everything you do next happens inside that project.
  2. Enable the Gmail API:
    • Left nav (☰) → APIs & ServicesLibrary.
    • Search for Gmail API → click the result → click ENABLE.
    • Wait for the enable to complete (you land on the Gmail API's overview page).
  3. Enable the Google Calendar API:
    • Back to APIs & ServicesLibrary.
    • Search for Google Calendar API → click the result → click ENABLE.

If you ever see a "this API is not enabled" error at runtime, come back here — the API was probably enabled in a different project than the one your OAuth client lives in.

5. Configure the OAuth consent screen

Before you can create OAuth credentials, Google requires you to declare what your app is and who can use it.

  1. APIs & ServicesOAuth consent screen.
  2. User type: ExternalCREATE. (External just means "any Google account can consent" — Internal is only for Workspace orgs.)
  3. App information page — fill in only the required fields:
    • App name: e.g. Executive Assistant (local)
    • User support email: your throwaway account address
    • Developer contact email (at the bottom): your throwaway account address
    • Leave the optional logo / homepage / domains fields empty.
    • Click SAVE AND CONTINUE.
  4. Scopes page — click SAVE AND CONTINUE without adding any. (The scopes are requested by the seeder at OAuth time, not declared here. Declaring them up front means Google will require app verification, which you don't want for local-only use.)
  5. Test users page — click + ADD USERS and add your throwaway Gmail address. Click SAVE AND CONTINUE.
  6. Summary page — review and click BACK TO DASHBOARD.
  7. Confirm Publishing status: Testing. This is what lets your throwaway test user authorize the app without Google verification. Leave it in Testing forever — there is no reason to publish.

6. Create the OAuth client credentials

  1. APIs & ServicesCredentials+ CREATE CREDENTIALSOAuth client ID.
  2. Application type: Desktop app. (Desktop app is what the seeder's local OAuth loopback flow expects — do NOT pick Web application or anything else.)
  3. Name: anything, e.g. ea-seeder.
  4. Click CREATE. A dialog shows the new client ID and secret — click DOWNLOAD JSON. If you miss the dialog, you can re-download from the Credentials list (download icon ⬇ on the right side of your client's row).
  5. Save the downloaded JSON somewhere temporary for now — you'll move it into seed/credentials.json in Project setup step 2.
  6. Treat this file like a password. It contains your OAuth client secret. The .gitignore step in Project setup step 4 makes sure git ignores it; do not commit it.

7. Anthropic API key

The four LLM-backed capabilities (Draft Replies, Action Items, Day in a Sentence, What to Tackle First) need an API key. Get one at console.anthropic.comSettingsAPI KeysCreate Key. Copy it — you'll paste it into .env in step 4 of project setup. The other 10 capabilities work without it.


Project setup

Before you start: these steps assume you already have this folder on your machine. Everywhere you see your-test-account@gmail.com or sk-ant-..., replace with your actual address / API key.

1. Create the project directory and initialize git

mkdir ea-build && cd ea-build
git init -b main          # on older git (< 2.28) use: git init && git symbolic-ref HEAD refs/heads/main

Ralph commits after every passing story — without git, the loop can't function.

2. Lay down the loop/ and seed/ folders

Move your OAuth client JSON (downloaded in Prerequisites step 6) into seed/credentials.json. For example, if your browser saved it to Downloads:

mv ~/Downloads/client_secret_*.json seed/credentials.json

(seed/token.json will appear automatically after the first seeder run in step 5.)

You should now have:

ea-build/
├── loop/
│   ├── ralph.sh
│   ├── ITERATION.md
│   ├── prd.json
│   ├── progress.txt
│   └── CLAUDE.md.template
└── seed/
    ├── seed.py
    ├── requirements.txt
    ├── credentials.json     ← you provided this (secret!)
    ├── emails/              ← fixture emails
    └── calendar/            ← fixture events

3. Place the starter CLAUDE.md at the repo root

mv loop/CLAUDE.md.template CLAUDE.md

This tells Claude Code the quality commands (npm run typecheck, npm test) and the project structure conventions Ralph will follow.

4. Create your .env and .gitignore

In the project root, create .env (substitute your real values):

cat > .env <<'EOF'
INTERN_USER_EMAIL=your-test-account@gmail.com
ANTHROPIC_API_KEY=sk-ant-...
EOF

Not comfortable with the heredoc syntax? Just open .env in any text editor and paste the two lines, replacing the placeholders.

Then create .gitignore to keep secrets and noise out of git:

cat > .gitignore <<'EOF'
.env
node_modules/
seed/credentials.json
seed/token.json
EOF

⚠️ Do not skip seed/credentials.json in .gitignore — it contains your OAuth client secret. Committing it would expose your credentials in git history.

5. Run the seeder once

This populates your test account with fake emails and calendar events, AND produces seed/token.json (the cached OAuth refresh token the EA reuses at runtime).

cd seed
pip install -r requirements.txt           # or: python3 -m pip install -r requirements.txt
export INTERN_USER_EMAIL=your-test-account@gmail.com
python seed.py                            # or: python3 seed.py

Want a clean Python environment? python3 -m venv .venv && source .venv/bin/activate before the pip install keeps the seeder's deps out of your global Python. Add seed/.venv/ to your .gitignore if you do this.

A browser opens for OAuth consent. You will see a screen titled "Google hasn't verified this app" — this is expected because your OAuth app is in Testing mode without app verification (which is exactly what step 5 of the Prerequisites set up). To proceed:

  1. Click Advanced (or Show advanced).
  2. Click Go to (unsafe).
  3. Sign in with your throwaway test account.
  4. On the permissions screen, leave all scopes checked and click Continue. (Unchecking any will break the seeder or the EA at runtime.)

When the flow completes, the seeder runs, prints what it inserted, and seed/token.json appears next to credentials.json.

Verify in your test account's web Gmail and Google Calendar that the fake emails and events are there. Then come back to the project root:

cd ..

6. Initial commit + branch

git status                                # sanity check — .env and seed/credentials.json should NOT appear
git add .
git commit -m "chore: initial scaffold (seed + loop)"
git checkout -b ralph/executive-assistant-v1

If git status shows .env or seed/credentials.json as files to commit, stop and re-check .gitignore — those must be ignored before you commit anything.

The branch name matches branchName in loop/prd.json. Ralph checks out this branch each iteration.


Run the loop

From your ea-build/ project root:

./loop/ralph.sh         # default: up to 10 iterations
./loop/ralph.sh 30      # plenty of headroom — there are 24 stories

If you get permission denied: ./loop/ralph.sh, the executable bit didn't survive the copy: run chmod +x loop/ralph.sh and try again.

Always invoke from the project root, not from inside loop/. The script cds to the project root internally, but it needs to be launched from a directory where loop/ralph.sh resolves.

Expect the loop to run for a while — each iteration spawns a fresh Claude Code agent and lets it implement one user story end-to-end (typically several minutes per story). 24 stories at a few minutes each means a multi-hour run; budget accordingly or leave it going in a terminal while you do other things.

Each iteration:

  1. Spawns a fresh Claude Code instance (no memory of previous iterations).
  2. Feeds it ITERATION.md as the prompt.
  3. The agent picks the highest-priority story with passes: false, implements it, runs npm run typecheck and npm test, commits, flips passes: true, and appends to progress.txt.
  4. The loop reads the agent's output; if it contains <promise>COMPLETE</promise>, the loop exits. Otherwise it spawns the next iteration.

Memory between iterations lives in git history, prd.json, and progress.txt. That's the entire state.

Watching it work

The agent's output streams live to your terminal. After each iteration:

  • git log --oneline shows the new commit.
  • loop/prd.json shows which stories now pass.
  • loop/progress.txt shows what the agent learned.

When it finishes

After the last story passes:

npm start

Open http://localhost:3001 — you should see the Executive Assistant dashboard pulling live data from your test account.


Troubleshooting

  • "Claude Code CLI not found" — install it with npm install -g @anthropic-ai/claude-code and run claude once to sign in.
  • permission denied: ./loop/ralph.shchmod +x loop/ralph.sh, then retry.
  • Loop crashes immediately — check that loop/prd.json exists, you're running from the project root (not inside loop/), you're inside a git repo (git status works), and claude is on your PATH.
  • The agent can't typecheck/test on US-001 — the very first story creates package.json, tsconfig.json, and installs deps. If it fails, check that Node 22+ is installed and that you started from a truly empty project (no leftover node_modules or stale package.json confusing things).
  • OAuth invalid_grant or token expired at runtime — re-run python seed/seed.py to refresh seed/token.json. Confirm the Gmail API and Calendar API are both enabled in your Cloud project and your test account is listed as a test user on the consent screen.
  • "This API is not enabled" at runtime — usually means the OAuth client lives in a different project than the API. Go back to Prerequisites step 4 and confirm both APIs are enabled in the same Cloud project that owns your credentials.json.
  • LLM-backed capabilities show "unavailable"ANTHROPIC_API_KEY is missing or invalid in .env. Fix it and restart npm start.
  • The loop hit max iterations without completing — read loop/progress.txt's last entry to see what blocked the agent. Bump the max (./loop/ralph.sh 50) or fix the blocker manually and re-run.
  • Accidentally committed .env or seed/credentials.json — your secrets are now in git history. The safe move: rotate the secrets (delete and recreate the OAuth client in the Cloud Console; rotate your Anthropic API key in the Anthropic Console), then add the files to .gitignore and re-commit.

What's actually happening

ralph.sh is heavily commented but the actual logic is a few dozen lines of bash. The pattern is the whole point:

  1. A loop spawns a new agent per iteration with no shared context.
  2. The prompt (ITERATION.md) tells the agent the protocol: pick one story, implement it, prove it works, commit, log learnings, repeat.
  3. State lives in files on disk (prd.json, progress.txt) and in git history — not in any agent's memory.
  4. The agent self-terminates by emitting a sentinel string the loop greps for.

That's it. The "intelligence" is in the per-iteration agent; the loop is a dumb scheduler. The discipline is in the prompt protocol and the quality gates.

About

Repo to accompany the Udacity Agentic Loop Webinar on May 27,2026

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors