zepto-claw · Episode 3

I gave my AI agent a phone number

It lived in my terminal. Now it lives in my WhatsApp — text it, it texts back.

Building your own claw — a series where we build a tiny AI agent one small piece at a time.

▶ Watch the build on YouTube

My claw could think and remember. But it was stuck in a terminal. I can't text a terminal from the bus.

So I gave it a mouth — on WhatsApp. About 20 lines, and now it runs on my own number. I text it, it texts back. Same brain, same memory as the last two episodes.

The code

This lives in one new file, whatsapp.ts:

import pkg from "whatsapp-web.js";
const { Client, LocalAuth } = pkg;
import qrcode from "qrcode-terminal";
import { ask } from "./claude.js";
import { addMessage } from "./db.js";

const client = new Client({ authStrategy: new LocalAuth() });
const MARK = "🤖 ";  // tag our own replies so we can skip them

client.on("qr", (qr) => qrcode.generate(qr, { small: true }));

// message_create (not message) so notes you send yourself count too
client.on("message_create", async (msg) => {
  if (!msg.body.trim() || msg.body.startsWith(MARK)) return;
  const reply = await ask(msg.body);   // same brain, same memory
  addMessage("user", msg.body);
  addMessage("assistant", reply);
  await msg.reply(MARK + reply);
});

client.initialize();

How it works

whatsapp-web.js runs WhatsApp Web in the background. You scan one QR with your phone to link it, like linking WhatsApp to a laptop — so the claw is your number. Every message fires message_create, we hand it to the same ask() from E01 (which loads the memory from E02), and text the answer back.

The gotcha that bit me: the claw replies through your own account, so its reply also fires message_create — and it starts answering its own answers, forever. The fix is two lines: tag every reply with 🤖, and skip any message that starts with the tag. That's why the bubbles in the demo are all on my side, and the agent's are marked.

One more tweak: I gave ask() a chat persona (a short systemPrompt plus settingSources: []) so it answers like a friendly assistant on WhatsApp, not like a coding tool.

Try it yourself

  1. Install the packages: npm i whatsapp-web.js qrcode-terminal
  2. Paste whatsapp.ts and run it: npm run whatsapp
  3. Scan the QR (WhatsApp → Settings → Linked devices), then text yourself.

Tell it your name, ask later — it still knows. The memory is shared with the terminal.

One honest caveat: whatsapp-web.js is an unofficial client — it drives WhatsApp Web, it's not the official API. Great for a personal demo; for anything real, use the WhatsApp Cloud API, and don't point it at a number you can't risk.

Watch the full build: the zepto-claw E03 Short, and subscribe on YouTube for E04. Catching up? Start with E01 · then E02.