Back to all articles
Project Notes

Meta Wants 20 Ad Creatives Where One Used to Do. I Built a Coworker.

How I turned a Teamwork user named Creative Bot into an autonomous Meta ad production system — brand-locked HTML rendering, comment-driven revisions, two clients live in two days, and the six failures that taught it judgment.

Conor Gotzens
5 min read
Educational content only. Examples and performance figures are illustrative and not guarantees. Results depend on your business context, implementation quality, and market conditions.

Meta's Andromeda update changed the math on ad creative. The delivery system now rewards campaigns that feed it many genuinely distinct creatives per campaign — different concepts, not one concept recolored. For a small agency, that's a production problem: a client who used to need four ads now needs twenty, on the same retainer. We tried Meta's built-in generative creatives first. Everything came back looking exactly like what it was.

So instead of buying another AI creative tool, I built a coworker. There is now a Teamwork user at our agency named Creative Bot. You assign it a task with a campaign brief, and 30 to 40 minutes later it comments back with a review gallery link and two dozen finished, on-brand ad creatives. You reply with revisions — plain text, or a screenshot with a circle drawn on it — and it posts a v2. Two clients are live on it. The build took two days.

Why the ads don't look AI-generated

The core decision is that no pixel of type, logo, or layout ever comes from an image model. Each ad is built as HTML and CSS in the client's exact brand system — real logo files, exact hex values, licensed fonts — composited with real photography, then screenshotted by a headless browser at 1080x1080, 1080x1350, and 1080x1920. The AI does the concepting, the copywriting, and the art direction. The rendering is deterministic code. A headline change is a 30-second re-render, not a redesign, which is what makes the revision loop cheap enough to actually use.

Every claim gets verified before it ships. The pipeline fetches the client's live landing page at run time and checks each price, credit count, and guarantee against it. For one client it caught that a seasonal order deadline had passed the week before — and shipped generic urgency instead of a dead date. Nobody asked it to. The rule in its instructions is simply that deadline dates must come from the live page.

The plumbing

The whole trigger is a task assignment. n8n polls Teamwork every five minutes for open tasks assigned to the bot; a PowerShell runner claims the task and launches a headless Claude Code session that does everything else: reads the brief from the parent task, loads the client's brand kit, picks photography from the client's Google Drive folder, renders, visually QAs its own output, deploys the review gallery, files the finals into the client's Drive, and comments back — as Creative Bot, its own Teamwork identity, via the REST API.

Revisions ride the same loop. The runner watches for comments newer than the bot's last delivery, so "a2: make the badge orange, kill concept 7" triggers a targeted re-render with no human dispatching anything. Pasted screenshots work too: the model views the image and treats your scribbled circle as a pointer.

Two details did more work than anything clever. First, a photo manifest: the bot views every image in the client's asset library once and writes down what each one actually shows, its orientation, and what it's good for — so "add a family dinner concept" resolves to the right photograph by content, not by filename luck. Second, a plain-markdown instruction file that accumulates editorial rules. More on that below.

Honest numbers

Client one: 54 finished creatives across 16 concepts in the first batch, built the same day I scraped their brand guide (which was scheduled to be deleted by its hosting platform five days later — archiving it first turned out to matter). Client two: onboarded from nothing to a delivered 24-file batch in one afternoon, then grew to 22 concepts and 66 files through two comment-driven revision rounds. Marginal inference cost: zero beyond the Claude subscription I already pay for, because headless Claude Code runs on the same plan. Hosting the review galleries costs nothing on Netlify's free tier. What's unproven, and the only number that ultimately matters: whether the extra creative volume moves client CPAs. That data is a quarter away, and I'll write it up either way.

What broke, in order

The failures were better teachers than the features.

  1. Teamwork's v3 API silently ignores its assignee filter. The bot's first poll returned every open task in the project — nine unrelated ops tickets — as if they were all its assignments. It "ran" all nine. The only reason nothing happened is that the CLI wasn't logged in yet. The v1 endpoint filters correctly; the fix is one URL.
  2. Five-minute polls versus forty-minute runs. A second poll fired mid-batch, decided the task was unclaimed, and launched a duplicate pipeline. I caught it three minutes in. Now there's a lock file and tasks are claimed before the run starts, not after.
  3. git init broke everything, invisibly. Putting the bot's own code under version control reset the tool's workspace trust, which made every subsequent headless run ignore its permission grants and die on its first action — with a zero-byte log. Two revision requests vanished into that hole before I found it.
  4. The scheduler died with a healthy-looking server. n8n 2.x only schedules published workflows. A CLI import plus a restart left the server running fine, serving its UI, and polling nothing. The log line that gave it away: "Processed 0 published workflows."
  5. I accused the bot of faking a logo, and I was wrong. The render showed what I took for typeset text. The bot's response to my revision demand was to hash-compare its logo assets against the client's official files, report byte-identical matches, and decline to re-render — correctly. It had quietly fetched the real files from the client's shared drive during intake. The real logo just is a stacked wordmark. My accusation cost nothing; its evidence-based pushback saved a full re-render.
  6. The taste failures. It invented "New this round" and "Previously approved" section labels on a client-facing review page — leaking iteration history a client shouldn't see. It exposed internal version suffixes in reference codes. Neither is a bug. Both became one-line rules in the instruction file, and neither has recurred.

That last pattern is the actual asset. The system's execution was solid within a day; what accumulated over the following days was judgment — never typeset a logo, never show a client the sausage-making, this audience prefers middle-aged subjects in photography, no em dashes in ad copy. The instruction file is starting to read less like a prompt and more like the editorial standards document every agency claims to have and almost none has written down.

The transferable lesson is the same one as my agent-team build, sharpened: put the AI where the work already lives. Nobody at the agency learned a new tool. They assign a task, the same way they assign one to me.