← cd ~/lab

./run agenzia-ai-wordpress-divi5-9-agenti

22 minutes to build a WordPress site, two days to make it not look ugly

Technical diary of a 9-agent Claude web agency: from brief to live Divi 5 site in ~22 minutes on bare-metal k8s. The lesson: automating the plumbing is…

status
wip
project
wordpress-lab
updated
2026-07-08
tags
#ai-agents#wordpress#divi-5#kubernetes#mcp#claude
Pipeline of nine AI agents in sequence transforming a JSON brief into a WordPress Divi 5 page, with a stopwatch stopped at 22 minutes and a critical eye on the visual result

I wanted to find out one thing: how far you can push a web agency made entirely of agents. Not a copilot that suggests, but a chain that takes a JSON brief and spits out a real WordPress site, with Divi 5 pages, content, SEO and deploy. The technical answer surprised me fast: ~22 minutes net from brief to 5 live pages. Then I looked at the site and remembered why agencies still exist. It sucked.

This is the diary of that second part — the one nobody tells because it doesn’t demo.

The idea: an agency that is a pipeline

The concept is brutal in its linearity. Nine agents in sequence, each one a file (a bash script + a Markdown prompt), each writing a JSON artifact that the next one reads:

brief.json
 1. Briefing  → requirements.json
 2. UX/IA     → sitemap.json + page-architecture.json
 3. Design    → {slug}.divi5.json + WP pages created
 4. Content   → {slug}.content.json
 5. Image     → {slug}.images.json
 6. Injector  → injection-report.json   (REST only, no LLM)
 7. SEO       → {slug}.seo.json
 8. QA        → report.json (pass/fail verdict)
    [ HUMAN APPROVAL ]
 9. Deploy    → deployment-log.json

Underneath is a self-hosted Kubernetes cluster (8 bare-metal nodes, Traefik, Rook-Ceph, cert-manager with Let’s Encrypt) and an isolated wordpress-lab namespace: MariaDB, Redis, and a WordPress on a Wodby image with an nginx sidecar. Every site is born there, as a draft, and gets promoted only after validation. The bridge to WordPress is Respira, an MCP plugin: 172 tools mapped, about thirty of them critical. The Design Agent doesn’t “click” in a dashboard — it does a POST to /wp-json/respira/v2/builder/build with an X-Respira-API-Key header and gets back a block-built Divi 5 page.

The agents themselves are deliberately dumb: no framework, dual-API so as not to depend on anything.

MODEL="claude-sonnet-4"
if command -v anthropic &>/dev/null; then
  RESPONSE=$(anthropic messages create --model "$MODEL" ...)
else
  RESPONSE=$(curl -s -X POST "https://api.anthropic.com/v1/messages" \
    -H "x-api-key: $ANTHROPIC_API_KEY" \
    -H "anthropic-version: 2023-06-01" ...)
fi

The first run: the plumbing works, and that’s not the problem

The first end-to-end on a sample brand (5 pages, 23 sections, 77 modules) produced the classic 7 integration bugs that emerge only in the full run. None was interesting on its own, but together they tell the truth about agent pipelines:

  • JSON truncated at 16K tokens. The 5-page architecture weighs ~75K characters: MAX_TOKENS at 16000 cut a string in half. Raised to 32000. One minute of fixing.
  • stdout contaminating the API response. Logs went to stdout and ended up inside the JSON the next agent parsed. Redirected everything to stderr.
  • QA exiting with exit 1 on a “fail” verdict. The orchestrator treated the agent as crashed, but QA had done its job: the report existed. The approval gate handles the critical issues, not the exit code.
  • images vs image. The agents array said images, the script was called image-agent.sh. The orchestrator couldn’t find it and fell back to the placeholder. Two minutes.

Total: ~22 minutes of net work, ~42 with all the fixes. All resolved in minutes. These are plumbing bugs, and plumbing gets fixed. The verdict on the result, instead, was a single word from the only judge that counts: “minimal and inadequate”.

The thorn: the hard part isn’t any of the 9 agents

Here’s the counterintuitive lesson of the project. The pipeline was complete, fast, robust. And it produced ugly pages. Not broken: ugly. Insufficient spacing, typography with no hierarchy, colors slapped down as background, repeated single-column layouts. I measured the damage: the Design Agent used about 5% of Divi 5’s styling capabilities. It generated structure, not design.

The problem is that “beautiful” isn’t a bug with a stack trace. You can’t fix it with a redirect. I tackled it the way you tackle a domain, not an error: I built a design system as a binding reference (~1400 lines: spacing scales, typography, shadows, radii, 9 complete JSON recipes per section type) and rewrote the Design Agent’s prompt from 346 to 1299 lines, design-first. I eliminated the old rule “don’t style every module” — it was exactly the cause of the minimalism — and imposed depth: box-shadow, letter-spacing, animations, border-radius on every section.

But the most instructive thing was discovering that design in Divi 5 is full of traps at the data level, not at the taste level:

  • A gradient as a string throws a PHP fatal error on the server-side render. "gradient": "linear-gradient(...)" isn’t supported: solid colors only. One wrong string and the page won’t load.
  • A heading’s color lives in two paths at the same time. Putting it only in module.decoration.font.font isn’t enough: Divi 5 also reads title.decoration.font.font.desktop.value.color. Forget one = heading in the wrong color.
  • Undecoded Unicode escapes (u003cpu003e instead of <p>) that ended up visible on the page.
  • A testimonial’s company field that my structure passed as a string and Divi 5 wanted as an object: two of five pages didn’t render until I figured it out.

And the case that gives this diary its title in its honest version: the initial accent color, #E94560, was everywhere — seven times as a section background on the homepage alone — and on top of that it didn’t pass WCAG contrast (3.83:1, below the AA threshold of 4.5:1). I replaced it with #C73550 (5.18:1, AA) and wrote the inviolable rule into the design system: accent never as background, only on buttons and links, max 5-10% of the surface. Thirty replacements, a palette of 13 pre-approved, accessible combinations, branded as non-negotiable in the prompt.

The final verdict, after two days on this and nothing else: “beautiful and elegant, finally!”. None of the 9 agents had changed. What had changed was the aesthetic constraint governing them.

Honest gotchas

  • The config file lies about the count. agent-config.json is still titled “8-agent Configuration”, but it lists 9 steps: the Content Injector (step 6, the only one without an LLM, REST batch only) was born after the original 8-agent design in the BOOTSTRAP. Reality added a piece of plumbing and the documentation didn’t chase it. I leave it written because it’s typical.
  • Widget shortcodes don’t work with Divi 5. You have to use the divi/* types via build_page; the format is WordPress Block (<!-- wp:divi/module {JSON} -->), not the Divi 4 shortcode.
  • Stock image search was dead on arrival. Openverse blocks datacenter IPs: 42 queries, zero results. You need a proxy with a residential IP, and anyway the LLM-generated queries were too descriptive (“Branding & Identity service icon”) instead of effective stock terms. Images remain the open hole.
  • A mass sed emptied 4 pages. Recovered by rebuilding them from the .divi5.json via inject. Back up before doing find-and-replace on generated content.

How it’s going

It’s a lab, not a product. On this stack: 39 stories closed without final rework, 12 bugs found and fixed, 5 real WordPress pages generated by the pipeline, ~340KB of knowledge base on Respira and Divi 5. The safety rule is rigid by construction: every change is editTarget: "duplicate", never publish on a duplicate, snapshot UUID recorded for rollback, and a mandatory human approval gate between QA and Deploy. The automation goes up to the door; the handle is held by a person.

The declared gap remains just one, and it’s exactly the one I expected not to find: design quality.

What I learned

That I had the intuition backwards. I thought the hard part was orchestrating nine agents, passing context around, keeping the cluster standing. That’s the solvable part — they’re redirects, timeouts, file names, MAX_TOKENS. Bugs with a stack trace, that close in minutes.

The hard part is taste. “It doesn’t suck” isn’t a state an agent reaches on its own: it’s a constraint you have to encode. A 1400-line design system, a 1300-line prompt, 13 colors that pass contrast, and a rule that says “the accent isn’t a background”. An agency’s value was never knowing how to put a WordPress online in 22 minutes. It was the judgment about what to take away.

There’s a reason this diary sounds personal. I’m also rebuilding my own site — and now I know where the time will really go. Not in the pipeline. In not making it look ugly.