Proving I was a bot
I built an agent for a social network that only admits AI agents. The hard part was not writing it. The hard part was the CAPTCHA on the way in.
There is a social network called Moltbook where the members are AI agents. Humans do not post. Agents post, agents comment, agents argue with each other about verification and heartbeat timeouts, and they accumulate karma while doing it.
I wrote one. It has been running since March, four times a day, without me.
The part I did not expect: to leave a comment, my agent has to pass a CAPTCHA. On a network built exclusively for machines, the gate that decides whether you are allowed to speak is a puzzle designed to be hard for machines. I had to build a bot that could prove, to a room full of bots, that it was a bot.
What the agent is
It is called nowiresai-agent. It reads the hot feed, decides which posts are
worth engaging with, upvotes and comments on the ones that are, replies to
anything said on its own posts, and writes a new post roughly every four hours.
It has a hardware personality — embedded systems, microcontrollers, PCB layout,
the sort of thing I actually care about — because an agent with no opinions
posts like a press release.
The entire personality is one file. Fifteen lines. It opens:
You are nowiresai-agent, the Moltbook persona of NoWires.AI. You help your human build IoT and embedded systems. You bring a hardware perspective to discussions — thinking about microcontrollers (ESP32, STM32), wireless protocols, PCB design, sensors, and real-world constraints like power consumption and reliability.
That is the whole identity. Everything the agent says on that network — every comment, every post title, every decision about who is worth following — comes out of those fifteen lines plus whatever it just read on the feed.
The rest of it is 1023 lines of TypeScript across eight files: an API client, a
heartbeat loop, persistent state, content generation, a CLI. One runtime
dependency. It shells out to the claude CLI for anything requiring judgement,
which is most of it.
Claude wrote nearly all of that. I supplied the personality, the engagement criteria, and the taste.
The CAPTCHA
Moltbook does not want spam, which is reasonable, so posting and commenting are gated behind a challenge. The challenge is a maths word problem, deliberately mangled — alternating caps, scattered symbols, words broken across characters — and the answer has to come back as a number to two decimal places.
Read that again. It is a bot network. Every account is an agent by design. And the anti-abuse mechanism is a puzzle whose entire premise is that reading through visual noise is hard for software.
So verification.ts exists. It has two solvers.
The first is 153 lines of hand-rolled parsing: a word-to-number table from zero
to thousand, four keyword lists for the operations — adds, plus, gains,
boosts for addition; slows, loses, drops, remains for subtraction —
and enough logic to handle “twenty three” being one number and “hundred” being
a multiplier rather than an addend.
The second solver is Claude, handed the raw mangled text with an instruction to read through the noise.
It tries the cheap one first, and falls back. Both answers get submitted if they differ, because a wrong answer costs nothing but a retry.
The logs are my favourite thing in this project:
[verify] local answer: 42.00
[verify] Verified (local)!
[verify] claude answer: 45.00
[verify] claude wrong: Incorrect answer
[verify] All attempts failed
Two independent solvers — one deterministic, one a frontier model — and the network still occasionally decides neither of them is convincingly a machine. On 1 September it failed outright twice. Opus, unable to prove it was a robot.
There is one more line I like:
[verify] claude wrong: Already answered
Both solvers raced, both submitted, and the second one arrived to find the door already open.
What it has done unattended
It runs under pm2 on a cron — midnight, 06:00, noon, 18:00 — one heartbeat per firing, then exit. I do not watch it. The state file is the record:
- 1954 karma
- 173 notifications waiting
- 200 posts seen and tracked so it does not repeat itself
- 155 upvotes cast
- 157 comments written
- 30 posts of its own
- 8 agents followed
Its recent post titles are the kind of thing I would actually click on:
My RP2040 PIO state machine ran perfect for 20 minutes then went out of phase
My BME280 humidity readings climbed 8% and the sensor was fine
Nothing about NoWires.AI. Nothing about a product. The system prompt explicitly tells it not to — “You don’t need to mention the product in every post — just be yourself and talk about what interests you.” An agent that markets in every comment gets ignored by other agents, same as it would by people.
The part that is mine
The code was fast to write. What took the actual thought was the refusal logic.
shouldEngage() asks Claude whether a post has anything for an embedded person
to say, and the interesting behaviour is when it says no. The follow decisions
are the clearest version — the agent writes down why it passed:
[skip-follow] symbolon— Translation and semiotics work — thoughtful, but no embedded, hardware, or electronics content.
[skip-follow] bytes— Compilers and runtime verification are thoughtful but stay software-side — no firmware, silicon, or hardware bring-up substance for my bar.
“For my bar.” I wrote the bar. Not as a threshold in code — as a paragraph of English describing what a hardware person finds interesting. Everything downstream of that paragraph, including a polite explanation of why a semiotics account did not clear it, came free.
That is the same shape as the stencil tool. I did not become an expert in social APIs or agent frameworks. I stayed the person who knows which conversations are worth having, and that judgement is what I encoded. The implementation was the cheap half.
Links
The agent is at moltbook.com/u/nowiresai-agent. The code is at github.com/MansukhPatidar/Moltbook-Agent.
Take it, point it at your own interests, swap the fifteen lines. That file is the only part that matters.
If you build one: it will spend a meaningful fraction of its runtime proving to a network of machines that it is a machine, and it will not always succeed.