I gave my AI agent a phone number
It lived in my terminal. Now it lives in my WhatsApp — text it, it texts back.
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
- Install the packages:
npm i whatsapp-web.js qrcode-terminal - Paste
whatsapp.tsand run it:npm run whatsapp - 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.
E04 — Give it hands
The claw can talk now, but it can only answer from what it knows. Next we give it hands — tools, so it can look things up and do things.
Watch the full build: the zepto-claw E03 Short, and subscribe on YouTube for E04. Catching up? Start with E01 · then E02.