Babanuj Β· Paid Ads Orchestration

Holistic paid-ads agent β€” build plan & live progress

An agent-first CLI that manages Google Ads, Amazon, Meta, and TikTok against one strategy β€” optimizing the whole portfolio, not any single platform. Built by a code factory: Claude plans and verifies, Codex implements, a second Claude reviews, Moe merges.

32PRs merged
πŸŽ‰First real proposal made
3 / 3Channels live-verified
✍️Awaiting Moe's strategy.md

Token meter β€” Codex (Coders): 2.19M across 28 runs, measured from worker logs Β· Claude (Reviewers + merge executors): β‰ˆ1.65M from run reports; Chief session metered separately in Claude Code (/usage) Β· Marginal cost: $0 β€” both run on flat-rate subscriptions (ChatGPT plan / Claude plan). Updated 2026-07-11.

Needs Moe β€” the factory is idle until these are answered

Everything unblocked has shipped. The next milestone is strategy learning: an agent reads Babanuj's real campaign history and drafts the initial rule set β€” the actual north star β€” as status: proposed files for Moe's approval. Filing that work needs three business answers.

1 Β· What is the portfolio optimizing for? β€” βœ… ANSWERED (as a mechanism)

Moe (2026-07-11): a strategy.md file the agent reads, reasons about, and follows β€” plus a per-campaign file showing what strategy the agent is currently following. The objective itself gets written into strategy.md by the strategy-learning step: the agent drafts it from 12 months of account history, Moe edits and approves. Issues #45–#47 filed; #45 is building now.

2 Β· Which Google Ads accounts count? β€” βœ… ANSWERED

Moe (2026-07-11): account 160-437-6990. The 8-campaign account β€” the same one that ran the live pipeline clean end-to-end in the smoke matrix. Strategy learning will target it exclusively.

3 Β· What must the agent never touch? β€” βœ… ANSWERED

Moe (2026-07-11): nothing special for now. Standing "Never touch" section added below β€” constraints added there get encoded as guardrail rules the agents are mechanically bound by.

Also waiting (no rush): Meta access β€” no Meta Ads CLI/API connectivity exists on the machine (#30) Β· Amazon Ads refresh token still pending with Amazon, recheck advertising.amazon.com/developer (#31). Answer any of these in the Claude session and the factory resumes on its own.

Never touch

Hard constraints no agent proposal may violate β€” protected campaigns, budget floors, seasonal locks, off-limits products or regions. Each entry here is also encoded as a guardrail rule in strategy/rules/, so it binds the agents mechanically; this section is the human-readable mirror.

No constraints defined. Moe confirmed "nothing special" on 2026-07-11. To add one, tell Claude in the factory session (e.g. "never reduce the budget of campaign X" or "brand campaigns are off-limits") β€” it lands here and in the strategy rules in the same change.

Plan & Progress

Phase 1 is complete. The full loop runs in dry-run with zero spend risk: fable run --tick daily ingests signals, compiles strategy, proposes and dry-executes Google actions under the budget guard, and flags strategy drift; --tick weekly evaluates closed experiment windows, accumulates Beta-posterior confidence, and emits draft rules for human review. Every step lineage-logged; the whole loop is an e2e test inside make verify. Next: hygiene batch, then Phase 2 (live read-only against the Babanuj CLIs).

ChiefClaude Fable 5 Β· high

Architecture, issues, dispatch, evidence verification. Writes no product code.

CoderCodex gpt-5.6-sol Β· medium β†’ high on retry

All implementation, tests, verify runs, PRs. One disposable worker per issue.

ReviewerClaude subagent

Reviews each PR at its exact head SHA. Different model family than the Coder, by design.

Merge authorityChief, under Moe's standing authorization

Merges fire automatically once every gate is green: CI + DCO + APPROVE review, all on the exact head SHA. Any red gate blocks.

Phase 1 β€” Google Ads vertical slice (dry-run)
#1 Scaffold TypeScript CLI + wire make verify β€” PR #9 Merged Landed on main as f7dfaa3 Β· CI pass, verify exit 0 twice, Reviewer APPROVE Β· follow-up hygiene in #10
#2 Strategy rules: schema, parser, strategy compile Merged Landed on main as 5da10a7 after review β†’ drift-bug fix β†’ rebase β†’ byte-level re-audit Β· verify now fails on stale locks, proven twice
#3 Decision lineage store (append-only event log) Merged Landed on main as 90cc7d4 Β· Reviewer APPROVE after exercising the CLI against a real store Β· hardening notes β†’ issue #13
#4 External signal contract + file inbox Merged Landed on main as 2266cfa Β· feature + post-rebase APPROVE, byte-level audit clean Β· hardening notes β†’ #15
#5 Channel agent interface + Google Ads adapter (fixtures) Merged Landed on main as d9067f5 Β· Reviewer recomputed the decision arithmetic from raw fixtures; determinism + propose-only proven Β· follow-ups β†’ #17
#6 Bounded experiments: isolation + budget guard Merged Landed on main as 8934ea3 Β· Reviewer recomputed the 5% cap from raw fixtures and proved the guard unbypassable Β· built by gpt-5.6-sol Β· follow-ups β†’ #19
#7 Strategy-diff evaluator + confidence scoring Merged Landed on main as 8997816 Β· Reviewer hand-verified the Beta-posterior math (5 exact cases) and falsification-tested the human-approval gate
#8 Orchestrator loop: daily + weekly ticks (end-to-end) Merged Landed on main as 12a4e73 Β· Reviewer ran the full pipeline manually and mutation-tested drift detection (review caught it untested; fix proven by breaking the code and watching the test fail) Β· follow-ups β†’ #22
Phase 2 β€” real data, still zero spend risk
#28 Live read-only Google Ads behind --live-read Live on all accounts Full four-account matrix passes: main account (37 campaigns incl. SHOPPING) runs the complete pipeline on real data Β· smoke test found 3 real-world gaps, hardening merged same-day (#40 β†’ PR #41) Β· manager account fails with a clear, actionable message Β· read-only invariant falsification-tested twice
#29 Search Console bridge β†’ seo.signal events Merged Reviewer recomputed thresholds by hand; emitted events survive the real ingest with zero rejections Β· vanished-query follow-up β†’ #39
#30 Meta channel adapter (fixtures, propose-only) Merged Reviewer hand-recomputed the decision math (exact match) and verified propose-only + loud degradation empirically Β· fable plan --channel meta works Β· live read-only follows
#31 Amazon Ads adapter (fixtures, propose-only) Merged Reviewer hand-recomputed the decision math and byte-diffed Google/Meta outputs across the refactor (identical) Β· fixture shapes are schema-derived (live list endpoints 404/415ed) β€” validation deferred to live-read #54 Β· approved queue running: #53 live Meta β†’ #54 live Amazon β†’ #47 evidence β†’ #50 attribution
#60–64 πŸŽ‰ First real recommendation from real data Milestone fable plan --channel amazon --live-read proposed a genuine budget shift β€” low-ROAS campaign β†’ high-ROAS campaign, computed from 14 days of real spend/sales (5,697 report rows via the babanuj-ops daily sync) Β· dry-run, lineage-logged Β· reasoning still uses the placeholder rule: Moe's strategy.md gives it a real north star
#53–59 Live reads verified on ALL connected channels Milestone Meta: real account read end-to-end (9 paused campaigns, honest warnings; bare-digit id fix #57 found by live smoke) Β· Amazon: real profile with 3,890 campaigns / 13.5K entities read in 13s after the worker cracked the CLI's media-type puzzle Β· Google: verified earlier on all 4 accounts Β· every proposal remains dry-run Β· pre-Meta-reactivation guard fix queued (#56) Β· next: Amazon performance metrics via authorized report requests (#60, Coder running)
Phase 3 β€” the real strategy (Moe's Q&A, 2026-07-11)
#45 strategy.md β€” the north star agents read, reason about, follow Merged Rules must cite the strategy section they serve; strategy edits invalidate the lock β€” both proven empirically in review Β· skeleton awaits Moe's content (Moe is authoring it himself)
#46 Per-campaign strategy statement Merged strategy/state/google-160-437-6990.md: stance + rules + evidence per campaign, regenerated every tick, hash-logged to lineage Β· Reviewer cross-checked every stance against what fable plan actually proposes Β· follow-ups β†’ #50
#47 Initial strategy learning from 12 months of account …6990 history Queued Agent drafts strategy.md + rules from real history β†’ PR for Moe's approval Β· the moment the north star becomes real
β€” Later: product dashboard on top of the CLI (incl. never-touch editor) Β· adstock/MTA Β· cross-channel engine Β· incrementality Β· TikTok Not yet filed Dashboard v1 follows the strategy milestone β€” a window onto real substance, not a demo.

Existing plumbing (Babanuj)

Recon of ~/Babanuj and ~/babanuj-ops confirms the spec's claim: connectivity is already built. These CLIs (Go binaries in ~/go/bin) become the live data sources behind the ChannelDataSource port when we flip off dry-run.

ChannelCLIStatus
Google Adsgoogle-ads-pp-cliLIVE β€” OAuth2, Basic access, 4 accounts
Amazon Seller (SP-API)amazon-seller-pp-cliLIVE β€” store β€œBabanuj”, US/CA/MX/BR
Amazon Adsamazon-ads-pp-cliPending β€” API access submitted, refresh token outstanding
Search Consolegoogle-search-console-pp-cliLIVE β€” feeds the SEO-signal contract
Google Analyticsgoogle-analytics-pp-cliConfigured
Meta~/.config/meta-adsConfig present β€” CLI surface to be confirmed

Architecture

Canonical copy lives in the repo at docs/ARCHITECTURE.md; this is the same content, condensed. Three foundational decisions (Moe, Jul 6): TypeScript core, Google Ads first, dry-run on fixtures for v1.

1 Β· Strategy is Markdown rules, compiled

One rule per file under strategy/rules/ β€” YAML frontmatter (id, status, scope, channels, metric, confidence, provenance, approved_by) over a human-readable rationale. fable strategy compile validates everything against a JSON Schema and emits one canonical strategy.lock.json that channel agents consume.

Rules live in git: an agent-proposed change is a PR; human approval is the merge. The approve-loop and its audit trail come free, and an invalid strategy fails make verify.

2 Β· Experiments are ring-fenced by the framework, not the channels

An abstract experiment carries a hypothesis, a pre-registered metric and direction, a window, and an isolation request. Channel adapters declare which isolation modes their platform supports (budget-slice, geo-split, audience-split) and translate. A central budget guard rejects anything over the cap (default 5% of channel spend) β€” enforced above channel code so no adapter can bypass it.

3 Β· Confidence is a Beta-posterior over validation cycles

A validation cycle is one completed experiment window (default 7 days) scored against the strategy-diff baseline: did the portfolio move toward the strategy, relative to baseline. When P(effect > 0) β‰₯ 0.80 across β‰₯ 3 cycles, the hypothesis becomes a draft rule with provenance links β€” never an automatic change.

Deliberately simple and auditable; the model gets smarter only when lineage data proves it's miscalibrating.

4 Β· External agents speak versioned JSON events

SEO, creative, and website-change signals arrive as CloudEvents-style JSON validated against schemas in contracts/, through a file inbox the orchestrator polls. Transport can become a queue later without touching consumers. Every ingested signal gets a lineage entry so attribution can cite it.

5 Β· Attribution ships lineage-first

v1: tactics/strategy separation + decision lineage + strategy-diff evaluation, no causal claims. v2: adstock / multi-touch attribution from GA. v3: periodic geo-holdout incrementality tests.

The later layers are unauditable without lineage, so lineage ships first.

6 Β· One orchestrator, stateless channel agents

A single orchestrator owns budget guards, cross-channel gating, and lineage writes. Channel agents are stateless per tick: read strategy.lock.json + channel data, emit proposed actions. Cadence: daily tactical tick, weekly experiment-evaluation tick.

Product invariant β€” cross-channel gating. Cross-channel signals are hypothesis-only until they earn β‰₯ 0.80 confidence across β‰₯ 3 cycles. They never silently alter per-channel strategy; they enter it only as human-approved rule changes with provenance. This is a hard constraint, not a tuning default.

Learnings

Mirror of docs/LEARNINGS.md β€” the log that makes disposable agents cumulative. Every regression, failed review, or workflow failure becomes an entry; every agent reads the log in full before working; proven rules get promoted into AGENTS.md.

2026-07-07 Β· Three headless-Codex failure modes, found and fixed in sequence

Symptom: the first Coder sat ~18 hours with zero output, no branch, no PR. Two re-fires surfaced two more failures before the worker finally ran clean.

Root causes, peeled in order: (1) backgrounded codex exec inherits an open stdin pipe and waits forever for input β€” the primary hang; (2) approval_policy = "on-request" would deadlock any headless run at the first sandbox approval, since nobody exists to answer it; (3) the pinned model gpt-5.5-codex isn't available on this machine's ChatGPT-account Codex β€” the account runs gpt-5.5. Chief monitoring compounded #1 by piping worker output through tail, which buffers until exit β€” nothing to see mid-run.

New rules: headless workers launch with stdin closed (< /dev/null), approval_policy = "never", network enabled; logs stream unbuffered; a silent or non-growing log for 10–15 minutes means presumed-dead β€” kill, diagnose, re-fire; and smoke-test the exact dispatch configuration, not a simplified variant.

Outcome: fixes promoted into .codex/config.toml; Coder model is gpt-5.5 (high; xhigh on escalation) until the account gains codex-model access. Exact-config smoke test passes; worker re-fired with error + stall monitors.