Open to senior marketing leadership opportunities across MENA and Europe

Personal Project

Personal Project

Marketing Debate · Multi-Agent Decision Engine

Claude × GPT-4o · 3 Rounds · Marked

Marketing Debate: Multi-Agent Campaign Decision Engine

A brief goes in with a market and a budget. A strategy and a media plan come out, along with a register of every number the system had to assume to get there. Seven specialist agents argue it over three rounds, a rival model hunts for the assumptions that hardened into facts, and the finished document marks every inferred number where it appears.

Multi-Agent AIClaude + GPT-4oAssumption RegisterNext.js 15Real-Time CanvasPersonal Build

Personal Project · Working build

7

Agents in Strategy Mode

The six-agent marketing panel plus a media planner: 21 turns across three rounds

0

Undebated Figures

At three rounds, no number in the finished document rested on an assumption minted after the panel stopped arguing. At two rounds, six did

409s

Brief to Strategy

Measured wall-clock on a live browser run: grounding, three rounds, audit, three synthesis parts

$1.56

Cost Per Strategy

Evaluate costs $0.42 and ideate $0.45, at current API pricing

A six-agent review of a campaign already on the table costs $0.42 and finishes in under two minutes. A full strategy and media plan built from a brief that states almost nothing costs $1.56 and takes about seven. At those prices the debate stops being a milestone and becomes a habit: every brief, every revision, and every media plan gets challenged before it gets approved. The team walks into the real meeting having already heard the strongest objections.

The Problem

One model agrees with you

Ask a single AI to review a campaign and you get your own brief back with better vocabulary. One model, one pass, no stakes: it hedges, rounds off conflict, and averages the risk away. That is not a review. It is agreement with formatting.

Real campaign reviews work because people with different mandates argue. The performance lead challenges the creative, brand challenges performance, and someone in the room refuses to be excited. That room is expensive, slow to assemble, and depends entirely on who shows up. Most briefs never get it. The ones that do get it once, at the end, when the thinking is already locked.

So I built the room.

Strategy Mode

The brief that says almost nothing

Evaluate and ideate both assume a populated brief. Real briefs are not like that. A client says 640 apartments in Sharjah, AED 4.2M, sell 60 percent before handover and stops there. No audience, no benchmarks, no competitive set.

Hand that to seven agents and each one quietly invents its own audience and its own CPL, then they argue past each other for three rounds. The debate looks convincing and means nothing.

So the design problem was never generating a strategy. It was generating one that admits what it made up.

Before round one: the grounding pass

A single Claude Sonnet call, measured at 57 to 65 seconds, turns the thin brief into a working one: category read, competitive set, audience segments, benchmarks. Every figure it had to infer goes into an assumption register that sits beside the working brief and is never folded into it, so an inferred number cannot be read back later as a stated fact.

The seventh seat: media planner

The original six are a marketing team. None of them does media agency work. Performance owns CPL and ROAS, not channel mix, reach and frequency, flighting, or rate realism. Without that seat the media plan is a list of channels rather than something anyone could actually buy.

Provenance

Every number carries where it came from

Because the brief is thin, most numbers in the finished document are inferred rather than stated. So each one is marked with its origin at the point it appears, and the system is built so it cannot lie about that. Three states, and a number the brief stated never looks like a number the panel guessed.

Stated

Came from the brief.

Carries no mark at all, so a mark always means something.

Grounded

Inferred before round one, so the panel argued over it.

Marked †A1, linked to the register entry it rests on.

Synthesis

Minted after the debate ended, so nothing pressure-tested it.

Marked ‡S1, in a separate id namespace from grounding.

Four mechanisms enforce it, in code rather than in a prompt

1

The schema refuses it

A figure flagged as inferred with no assumption id fails Zod validation and never renders. An unlabelled inferred number cannot ship, because the type will not hold one.

2

Separate id namespaces

Grounding mints A1, A2, A3. Synthesis mints S1, S2, S3. The merge step sets the source field itself and rejects any id from the wrong namespace, so a synthesis part cannot pass off a number it just invented as one the panel debated.

3

The auditor is told to hunt for it

In strategy mode GPT-4o gets an extra mandate: find inferred figures the panel started quoting as established fact. In one measured run, three of its five flags were exactly that, each naming the assumption by id and the agent that let it through.

4

Visible at the point of use

The marks are glyphs and ids, never colour alone, so they survive greyscale printing and do not depend on colour vision. A fourth mark exists for a figure whose register entry is missing: the document names the dangling reference rather than quietly rendering the number clean.

The register is the deliverable, not an appendix

Each entry carries the assumption, its confidence, its basis, its source, what breaks if it is wrong, and how to validate it. The last two render at the same type size as the claim itself, side by side, because a low-confidence assumption is the most useful thing in the document: it tells you what to go and check on Monday. One entry from a real run, unedited:

†A1Source: groundingConfidence 45

“CPL for qualified off-plan leads in Sharjah via digital channels is approximately AED 220.”

If it is wrong

“If CPL is AED 350 or above, the media budget cannot generate enough leads to hit the 60% sell-through target without either increasing budget or improving conversion rate significantly.”

How to validate it

“Run a two-week paid social and search pilot before full budget commitment and read actual CPL against this figure.”

The Panel

Seven mandates, written to collide

Each agent owns territory that forces disagreement with another seat at the table. Six sit in evaluate and ideate; strategy adds the media planner for seven. All of them run on Claude Sonnet 4.6, in parallel, every round. Nobody wins by talking longest: turns are capped at 180 words.

Strategist

Owns positioning, funnel architecture, competitive whitespace, and sequencing. Rejects any tactic with no clear place in the funnel or no defensible position against competitors.

Creative

Owns the concept, the hook, and distinctiveness. Rejects safe, category-generic ideas and pushes for work the category has not seen before.

Performance

Owns CPL, CAC, ROAS, channel feasibility, and media cost realism. Challenges every cost assumption with benchmarks and rejects anything without a measurable path.

Skeptic

Attacks the idea. Probes assumptions, budget realism, timeline, audience fit, and brand risk. Never proposes alternatives: only names failure modes and quantifies the downside.

Audience

Represents the target segment. Attacks anything the audience would ignore, distrust, or find irrelevant, and explains why in their terms.

Brand

Owns consistency, brand equity, and long-term positioning risk. Judges every idea by what it does to the brand over a three-year horizon, not just this quarter.

Media Planner

Strategy mode

Owns the media plan: channel mix, reach and frequency, flighting, buying models, and rate realism. Rejects any plan with no buyable path, and names the buying model, the unit cost basis, and what the budget will not stretch to.

Debate rules, from the actual prompt

Take a position. Do not hedge.

Max 180 words per turn: position, reasoning, challenge, confidence 0 to 100.

In rounds two and three, every agent must name at least one agent it disagrees with and say why.

Cite numbers where possible. Estimates must be labelled as estimates.

The seat that cannot be emptied

Rosters are configurable, from a lean four-agent panel to the full seven, but the skeptic is mandatory in every configuration. The roster validator rejects any debate without it, and the UI locks its toggle with one line: “Required. The skeptic is what makes the debate real.” In strategy mode the media planner is locked the same way, for the same reason: “The media plan needs someone who buys media.”

The Cross-Model Audit

Where GPT-4o comes in

After round three, the transcript leaves the family. GPT-4o reads the entire debate as an adversarial auditor with one brief: find what the whole panel missed. Unexamined assumptions, math that does not add up, regulatory and cultural blind spots, contradictions between rounds, risks nobody raised.

It returns at most five flags, each with a severity and a name: which agent should have caught this. And it is explicitly told, “If the debate was genuinely thorough, return fewer flags. Never invent issues to fill the quota.”

The auditor is a different vendor’s model on purpose. A Claude panel reviewed by one more Claude would share the same training and the same blind spots. The audit only counts because it comes from outside.

In strategy mode it carries a second mandate, and it is the one that matters most: find the inferred figures the panel started quoting as established fact. Because every one of those figures was labelled at the moment it was invented, the auditor can name both the assumption and the agent that stopped treating it as one.

One flag, verbatim · severity high · missed by the media planner

“The AED 2.4M media budget (A4) is treated as a fact by multiple agents, but it is based on an assumption with only 40% confidence.”

Three of the five flags in that run were the same failure: a figure that entered as a labelled guess and was being handled as settled fact three rounds later.

How a Debate Runs

Brief in, decision out

Three modes. Strategy is the default: it starts from a market and a budget and builds the strategy and the media plan. Evaluate pressure-tests a campaign already on the table. Ideate starts from an audience and an objective and converges on the strongest five to seven ideas. The pipeline is the same in all three, and strategy adds one phase at the front.

Strategy

Default · 7 agents · ~409s · $1.56

Evaluate

6 agents · 108s · $0.42

Ideate

6 agents · 129s · $0.45

1

Brief

Typed into a structured form, or uploaded as the campaign deck: PDF, Word, PowerPoint, or plain text. Claude Sonnet extracts the structured fields with a per-field confidence score and a hard rule against inventing any budget figure, benchmark, or timeline it did not find in the document. Missing fields are flagged, not filled in. Strategy mode asks for far less on purpose: a market, a product, a budget, and an objective are enough to start.

2

Grounding pass

Strategy mode only. One Claude Sonnet call, measured at 57 to 65 seconds, turns the thin brief into a working brief: category read, competitive set, audience segments, benchmarks. Every figure it had to infer is written into an assumption register that sits beside the working brief and is never folded into it, so an inferred number cannot be read back as a stated fact.

3

Three rounds

Every rostered agent responds in parallel on Claude Sonnet 4.6, six in evaluate and ideate, seven in strategy. Round one sees only the brief. In rounds two and three each agent receives the full transcript and must name at least one agent it disagrees with. A drift-tolerant parser turns each raw response into a structured turn: position, reasoning, challenge, confidence.

4

Cross-model audit

The complete transcript goes to GPT-4o, which reads the debate as an adversarial auditor and returns up to five flags: what the whole panel missed, how severe it is, and which agent should have caught it. In strategy mode it carries a second mandate: find the inferred figures that got quoted as established fact.

5

Synthesis

Brief, transcript, and audit flags go to Claude Opus 4.8. Evaluate and ideate produce the verdict in one schema-validated call, with the exact schema error fed back for one retry on failure. Strategy runs three sequential calls, each validated on its own, so a failed part is recorded and skipped instead of taking the other two down. Dissent from the transcript must be carried through, not smoothed over.

6

Render and export

The entire run streams live over Server-Sent Events to the canvas: each agent is a node with a confidence arc, every challenge renders as a pulsing edge between the two agents, and the transcript sits in a drawer. Evaluate and ideate end in a structured verdict panel. Strategy ends in a ten-section document with every inferred number marked. Both export to JSON, PDF, and a Gamma deck.

What Comes Out

Ten sections, and a media plan someone could actually buy

A strategy run ends in a document with a fixed section order, where everything numeric points back to the register at the end of it.

01

Situation

02

Positioning

03

Segments

04

Messaging

05

Creative territories

06

Media plan

07

Roadmap

08

Measurement

09

What we would not do

10

Assumption register

The media-agency half

Nine columns per channel, so a plan cannot be a list of platform names with a percentage next to each one:

ChannelRoleFunnel stagePhaseBuying modelBudget shareBudget amountEstimated outcomeWhy this channel

Plus phased flighting, reach and frequency with its basis stated rather than asserted, and a block naming what the plan is deliberately not buying. That last block is where the discipline shows. From a real run, unedited:

Not buying · broker co-marketing as a paid media line

“The panel could not confirm whether broker commissions sit inside or outside the AED 4.2M total (‡S1). Funding broker activation as a media line risks double-counting against commission spend or building on a fiction. Broker enablement is handled in the roadmap as a sales workstream funded outside this media budget, not as a paid channel.”

And it holds together arithmetically

In the measured run, channel budget shares summed to exactly 100, phase shares to 100, and the total budget was correctly identified as the one genuinely stated number in the brief. Three surfaces carry it: a reading-width document page with its own print stylesheet, a 17-page PDF with two landscape pages so the nine-column media plan and the six-column register are never truncated, and a Gamma deck with the register split across slides.

Deciding the Round Count

Two rounds or three, settled by counting

Both were built and run on the same brief, then every figure in each finished document was traced back to where it entered. The round count is a design decision, so it should be settled by data rather than by taste.

Measured

2 rounds

3 rounds

Marked figures in the document

28

26

Stated in the brief

1

9

Grounded, so the panel argued over it

21

17

Minted at synthesis, never debated

6

0

Assumption register entries

13

11

Cost per run

$1.28

$1.56

At three rounds, nothing in the document rested on an assumption minted after the panel had finished arguing. That is what the extra 21 seconds and 28 cents buys.

Round three also earned its place on content, not just on provenance: it produced two material challenges rather than restating round two. Whether broker commission sits outside the budget at all, and whether the plot is even freehold-eligible for the buyer the plan is targeting. Both went on to become flagged assumptions in the register.

The Verdict

What lands at the end of an evaluate or ideate run

The output is not a chat transcript. It is a decision document: schema-validated JSON rendered as a structured panel, where every field has to earn its place. Strategy mode wraps this same verdict in the ten-section document above.

The call

A two-to-four sentence recommendation with a 0-100 confidence score. Not a summary of the debate: a decision.

The plan

In evaluate mode: revised positioning, audience, channel mix with budget shares, and funnel. In ideate mode: five to seven ideas, each scored by every agent, with the skeptic’s strongest objection attached to each one.

KPIs

Measurable targets tied to the recommendation, so the verdict can be held to account after launch.

Risks

Each risk carries a severity and a mitigation. The audit flags feed directly into this list.

Dissent

The disagreements the panel never resolved, preserved as-is. The synthesizer is instructed not to smooth them over, so the team knows exactly where the open risk sits.

Execution steps

A numbered sequence with an owner and timing on every step. The verdict ends where the work begins.

Plus the handoff

Every verdict includes a self-contained design prompt for the campaign key visual and landing page, written to stand alone with no reference to the debate. Paste it into Claude and the next deliverable starts immediately. Exports: auto-downloaded JSON, a branded PDF, and Gamma markdown that turns the verdict into a deck.

From a Real Run

An AED 3.8M brief meets the panel

Excerpts from a captured evaluate-mode debate on a Dubai Marina tower launch brief: AED 3.8M budget, a 4,500 qualified-lead target, and a hero film concept. All quotes below are the actual output of that run, unedited.

Skeptic · Round 1

“This campaign is structurally overambitious relative to the budget, timeline, and brand credibility available to execute it.”

“At AED 3.8M with 45% allocated to paid digital, that is AED 1.71M for paid media. At the current blended CPL benchmark of AED 180-320, that buys roughly 5,300 to 9,500 raw leads. To hit 4,500 qualified leads, the qualification rate must hold at 47-85%. In premium off-plan, qualification rates typically run 15-30%. The numbers do not close.”

GPT-4o · Audit

Two of the five flags it returned, each naming the agent that should have caught it:

“Unrealistic Qualified Lead Target”: severity high, missed by the strategist. “Overambitious International Market CPL Assumptions”: severity high, missed by the audience agent.

Verdict · Claude Opus · Confidence 85

“Reset the qualified lead target to 1,800-2,000 (from 4,500) and reallocate budget to 45% paid digital (80% UAE-focused), 22% broker activation, 20% film production…”

The full verdict carried 4 KPIs, 4 risks with mitigations, 4 unresolved dissents, 8 execution steps with owners, and a complete design prompt for the key visual.

Screenshots

The debate, live

Two views of the web app: the canvas while the panel argues, and the verdict panel that ends the run. Below a derived minimum width, 868px for six agents and 1042px for seven, the canvas gives way to a card list rather than letting node labels collide.

Screenshot

Debate Canvas: Live Run

Marketing Debate canvas showing six agent nodes with confidence arcs and challenge edges during a live debate

Debate Canvas: Live Run

The live canvas mid-debate: each agent is a node with a confidence arc, and every challenge renders as an edge between the two agents involved.

Screenshot

Verdict Panel

Marketing Debate verdict panel showing the recommendation, KPIs, risks, dissent, and execution steps

Verdict Panel

The verdict panel: the call with its confidence score, KPIs, risks with mitigations, unresolved dissent, and execution steps with owners.

What It Changes for the Team

The review every brief gets, not just the big ones

The strongest objections arrive before the money is committed, not in the post-mortem. A review that normally needs five specialists in a room runs on every brief and every revision, not just the flagship ones.

A thin brief is enough to start. Nobody has to assemble an audience definition and a benchmark set before the work can begin, and the working brief the system writes for itself is visible rather than implied.

The low-confidence rows are the agenda. Every assumption carries what breaks if it is wrong and how to check it, so the document hands over a list of things to verify instead of a set of conclusions to trust.

The media plan names its buying model, its unit cost basis, and what the budget will not stretch to, including a block of channels it deliberately refused and why.

The skeptic cannot be dropped from the roster. Roster validation rejects any debate without it, in code, so no verdict ships untested.

Campaign decks upload directly: PDF, Word, or PowerPoint in, structured brief out, with a confidence score on every extracted field. Nobody retypes a brief to get a second opinion.

Disagreement is preserved, not averaged away. The verdict records what the panel never resolved, which is usually the exact conversation the team needs to have next.

The handoff is part of the output: a ready-to-paste design prompt for the key visual and Gamma markdown for the deck, so the next deliverable starts the same hour the verdict lands.

Decisions the Measurements Forced

Four places where a number changed the design

Each of these has the same shape: something was measured, and the measurement made the original approach untenable.

Synthesis is three calls, not one

One Opus call could not hold a strategy document, a media plan, and a measurement framework without truncating, and a single failed parse threw away all of it. Three sequential validated calls mean a failed part is recorded and skipped. This was not theoretical: part two failed on a real run, and parts one and three still produced a valid document with the gap named rather than filled in.

A verdict is never fabricated

Part three owns the fields a verdict cannot do without. If it fails there is no schema-valid verdict, and inventing one would be worse than failing. So the partial document is written to disk first, then the error is raised naming which sections survived and where the file is. Recovery never means rerunning a seven-minute debate.

Stall detection had to become phase-aware

Grounding emits nothing for a full minute, so the 45-second timeout that suits agent turns would kill a healthy run. Each phase now gets its own window: 45s for rounds, 120s for grounding, 240s per synthesis part. The 240 is deliberate. A synthesis part measured 163s, and against the original 180s window that is 17 seconds of margin, which is a false stall waiting to happen in front of a client.

Self-hosting was forced by a stopwatch

A 409-second run cannot finish on any Vercel tier, which caps functions at 300 seconds. The system runs on a Hetzner box under pm2 behind Caddy, where no function ceiling applies and the event stream flushes immediately instead of buffering.

Found by testing, not by reading the code

The form never delivered events. Submitting the brief reached the debate page, the server ran the whole debate and persisted every event, and the client sat on “connecting” forever with no error. React was mounting the component, suspending, and remounting, and the teardown from that phantom first mount killed the stream. Arriving by page reload worked, which is what hid it. Proven pre-existing by stashing back a commit and reproducing it there.

The grounding pass was truncating. An 8,000-character register hit a 4,000-token cap and was reported as invalid JSON, which sends you looking in the wrong place. Both the cap and the error message were fixed, and truncation is now named as truncation.

Node labels collided at narrow widths. A seventh agent made a pre-existing overlap worse, and the cause was not node size but a fixed label width against shrinking spacing. The fix is a derived minimum canvas width, 868px for six nodes and 1042px for seven, below which the card list renders instead.

Challenges were misattributed. The parser picked the challenged agent by registry order rather than by position in the text, so “I disagree with Brand, not a creative idea” resolved to Creative. Earliest mention now wins.

Two checks are worth naming. A 14-case test proves no run phase can arm the wrong stall timer, including four reconnect scenarios where an entire debate history replays in a single burst. And a disconnect test kills the browser tab mid-debate, then confirms the run continued server-side and the reopened URL catches up without restarting it.

How It Is Built

How It Is Built

Grounding Pass

Claude Sonnet 4.6 · thin brief to working brief + register

Debating Agents

Claude Sonnet 4.6 · up to seven mandates, parallel per round

Adversarial Auditor

OpenAI GPT-4o · cross-model review, max five flags

Synthesizer

Claude Opus 4.8 · three sequentially validated parts

Provenance

Zod at every model boundary · inferred figures must name an assumption id

App

Next.js 15, React 19, TypeScript, Tailwind CSS 4

Debate Canvas

React Flow, framer-motion, animated challenge edges

Streaming

Server-Sent Events · seq-numbered replay, phase-aware stall windows

Brief Ingestion

pdf-parse, mammoth, jszip · PDF, DOCX, PPTX, TXT

Exports

@react-pdf/renderer PDF · Gamma markdown · JSON

Hosting

Hetzner under pm2, behind Caddy with flush_interval -1 for SSE

Second Surface

CLI runner with per-agent terminal colors · tsx + chalk

What I Built

What I Built

Every part of this system: the agent mandates, the orchestration, the streaming layer, the canvas, and the exports, was built by me using Claude Code as the development environment.

Wrote the six agent mandates so they collide by design: each owns territory that forces disagreement with another seat at the table, and rounds two and three make naming that disagreement mandatory

Wrote the seventh mandate, the media planner, for the work none of the original six does: channel mix, reach and frequency, flighting, buying models, and rate realism. Locked into every strategy panel alongside the skeptic

Added a grounding pass so a thin brief becomes a debatable one before round one, with every figure it had to infer written into a register that sits beside the working brief rather than inside it

Put provenance in the type system: a figure flagged as inferred with no assumption id fails Zod validation, so an unlabelled inferred number cannot ship

Gave grounding and synthesis separate id namespaces, A and S, and made the merge step own the source field and reject any id from the wrong one, so a synthesis part cannot pass off a number it just invented as one the panel debated

Split synthesis into three sequentially validated Opus calls after a single call truncated, so a failed part is recorded and skipped rather than taking the whole document down

Made stall detection phase-aware, 45s for rounds, 120s for grounding, 240s per synthesis part, after measuring a synthesis part at 163s against a 180s window, and covered it with a 14-case test so no phase can arm the wrong timer

Built and measured both a two-round and a three-round run on the same brief, counted where every figure in each document came from, and set the default from what the counts showed

Made the skeptic structurally mandatory: the roster validator rejects any debate without it. Enforced in code, not in a prompt

Put the audit seat outside the model family on purpose: a Claude panel reviewed by another Claude shares the same blind spots, so the auditor is GPT-4o with an explicit instruction to never invent issues to fill its quota

Built the SSE streaming layer so every event is simultaneously streamed and persisted with sequence numbers: a dropped connection replays the debate and catches up by polling

Built a drift-tolerant parser that turns free-text agent output into structured turns even when a model wanders off format

Enforced the verdict schema with Zod and an error-carrying retry: if the synthesis JSON fails validation, the exact schema error goes back into the prompt for one more attempt

Built three run modes: live, mock (scripted events, zero tokens) for UI work, and a fixture replay of a full captured real debate with realistic per-turn timing for demos

Built the export layer: a branded PDF via @react-pdf/renderer with bundled fonts, Gamma markdown for a deck, and a copyable self-contained design prompt

Shipped the CLI first as Phase 1, then layered the web app onto the same debate engine without forking the orchestration logic

Honest Limits

What this is not

A system built around marking what it made up should be equally clear about its own edges.

It is a decision tool and a demo, not a platform. Sessions are in-memory by design: if the process restarts mid-debate, the run is lost.

The register records assumptions from two points only, grounding and synthesis. The schema reserves a state for assumptions raised during the debate itself, but nothing writes it and the interface never labels one.

The agents are mandates, not people. Everything quoted here is attributed to a run, never to a named individual.

The fast demo is fixture mode: a bundled replay of one captured real debate, running client-side with no model calls. It is not an eight-second debate.

Cost figures are per run at current API pricing, and they will drift.

Seven agents argue. A rival model hunts for the assumptions they started treating as facts. The document that lands marks every number it had to invent, and tells you which one to go and check first.

The Sibling System

Marketing Debate decides whether the plan is right. The Agentic Marketing Team is the org that builds it: three departments handing work forward under an enforced claims contract, with adversaries that can send it back.

Back to AI Systems