Embed realize-toolkit, align with Apr 2026 brand guardrails#2
Conversation
- Embed toolkit knowledge layer: os/guardrails.md (consolidated system-prompt), knowledge/ (10 topic MDs + manifest.json), scripts/brand-check.sh. - Apply PMM brand guardrails: feature renames (Realize Pixel → Taboola Pixel; Marketplace Audiences → Taboola First Party Audiences; first-party segments → Taboola First Party Audiences), UI naming (Realize console → Realize UI), brand naming (Taboola Realize → Realize). - Align operational thresholds with toolkit: 100+ clicks per item (was 500–1000), daily spend >= 8x CPA goal (was \$50/day flat), 7–10 day learning phase, 4–6 ads per campaign (was 3–10), 3 titles + 3 images per campaign (was 5–10 variations), Fixed Bid per client requirements. - Enforce attribution + timeframe rule globally via os/guardrails.md (single source of truth) — every CPA/CVR/Leads/ROAS figure must specify both attribution basis (CT/VT/Total) and timeframe. - Consolidate os/ from 4 files (guardrails, tone, orchestration, routing) to 1 (guardrails) — Claude Code skill-routing handles intent matching natively. - Adapt brand-check.sh: allow item_id as public MCP parameter; tighten console/dashboard regex; drop bare \bhip\b alternative. - Remove redundant backlog.md — content now lives in docs/realize-best-practices-gap.md Part 3 as single source. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… to private layer
- Remove competitor comparison bullet ("No bias towards owned and operated
inventory (Taboola does not own inventory like Meta and Google)") — names
competitors, can't appear publicly.
- Move four sections from os/guardrails.md (public) to guardrails-private.md
(internal layer), out of the plugin repo:
- Preferred messaging direction (full section)
- Framing rules (Tone subsection)
- Emotional tone matching (Tone subsection)
- What the assistant is not (Tone subsection)
These are internal directional rules — the assistant should follow them
silently, but they must not be visible in the public guardrails file shipped
with the plugin (Maayan flagged them as marketing-playbook content that
shouldn't be exposed externally).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three renames in upstream realize-mcp (../realize-mcp): - get_all_campaigns → list_campaigns - get_campaign_items → list_items - get_campaign_item → get_item Pure token swaps across 8 files. No new tools added, no skill files created, no other content touched. Scope intentionally minimal — follow-up needed for stale "11 tools" claim in docs/realize-best-practices-gap.md and the write-tool framing in agents/realize-analyst.md Tool Reference. Verified: zero old tool-name hits via grep; JSON + YAML frontmatter parse cleanly; scripts/brand-check.sh passes (0 FAIL, 1 pre-existing WARN); 13/16 manual test scenarios PASS against live MCP, 3 require a Claude Code session. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add new skills/discovery/SKILL.md wrapping the 9 read-only "look it up"
tools the MCP exposes (search_geos, search_techno, search_audiences,
search_lookalike_audiences, search_contextual_segments,
search_publishers, search_conversion_rules, list_time_zones,
list_cta_types). Read-only - designed for inventory queries
("what audiences are configured?") and forward name -> opaque-code
resolution before campaign work in the Realize UI.
Agent Tool Reference grew from 9 to 18 read tools. Grouped:
Accounts / Campaigns / Items / Discovery / Reports / Auth.
Added discovery routing example + Core Responsibility #2 line.
Tool-existence-boundary updated to acknowledge upstream's 4 write tools
exist but are intentionally not wired in this revision.
Updated CLAUDE.md architecture diagram (added discovery row, 18 reads,
4 upstream writes noted), docs/realize-best-practices-gap.md capability
baseline (folded Discovery), README skills table (new discovery row),
tests/test-scenarios.md (scenarios 12-16 verified live against MCP).
Version 0.1.0 -> 0.2.0. CHANGELOG 0.2.0 section consolidates prior
[Unreleased] entries (toolkit embed, brand alignment, threshold
updates, optimize-campaign skill) with this Phase 1 wiring.
Content for the discovery skill + scenarios 12-16 reused verbatim from
upstream c8e4a5b ("Align skills, agent, and tests with latest
realize-mcp tool set") since no toolkit/brand conflicts.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add new skills/discovery/SKILL.md wrapping the 9 read-only "look it up"
tools the MCP exposes (search_geos, search_techno, search_audiences,
search_lookalike_audiences, search_contextual_segments,
search_publishers, search_conversion_rules, list_time_zones,
list_cta_types). Read-only - designed for inventory queries
("what audiences are configured?") and forward name -> opaque-code
resolution before campaign work in the Realize UI.
Agent Tool Reference grew from 9 to 18 read tools. Grouped:
Accounts / Campaigns / Items / Discovery / Reports / Auth.
Added discovery routing example + Core Responsibility #2 line.
Tool-existence-boundary updated to acknowledge upstream's 4 write tools
exist but are intentionally not wired in this revision.
Updated CLAUDE.md architecture diagram (added discovery row, 18 reads,
4 upstream writes noted), docs/realize-best-practices-gap.md capability
baseline (folded Discovery), README skills table (new discovery row),
tests/test-scenarios.md (scenarios 12-16 verified live against MCP).
Version 0.1.0 -> 0.2.0. CHANGELOG 0.2.0 section consolidates prior
[Unreleased] entries (toolkit embed, brand alignment, threshold
updates, optimize-campaign skill) with this Phase 1 wiring.
Content for the discovery skill + scenarios 12-16 reused verbatim from
upstream c8e4a5b ("Align skills, agent, and tests with latest
realize-mcp tool set") since no toolkit/brand conflicts.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…nage-campaigns restructure Replays the realize-buyer-agent port on top of fork's 3 prior commits (MCP-tool-ref rename + discovery/campaigns/manage-campaigns skill split). The original single-commit port (preserved on backup/port-2026-06-08 and as inputs/0001-Port-realize-buyer-agent-Steps-1-7-...patch) targeted the pre-restructure layout; this commit re-applies it cleanly on the new architecture without losing fork's read/write split. Knowledge layer: add 2 new topics (reach-estimation, reporting-aggregation), section-merge 6 grown topics (bidding/creative/targeting/campaign-structure/ budget/site-management). Fix stale "MCP creates Native only" claim in campaign-structure.md with the correct two-path description (pricing_model =VCPM locks Display at create; pricing_model=CPC sets type by first item). Standardize learning phase at 7-14 days. Refresh manifest. Skills: - optimize-campaign: rewrite as lean SKILL.md (5 mandatory pre-checks P1-P5, RCA vs general optimization framework, action prescriptions routed to manage-campaigns) + references/optimization-flow.md (dimensional drill-down, supply-side eligibility, creative-fatigue tiers, bid-lever matrix, 6 symptom branches, common-mistake patterns). - manage-campaigns: extend with Display item write coverage (the gap left by the 0.3.0 release which covered Native items only) — create_display_item + update_display_item with 3P-tag and 1P-hosted recipes, status-gated update flow, pricing-model-picks-the-type subsection, per-strategy bid-lever gate matrix, pointer to new references/mcp-write-surface.md (field-by-field write reference). - reports: 4 mandatory pre-checks (conversion-goal resolution, marketing -objective alignment, delivery-eligibility, learning-period guard), sum-reconciliation gate, default exclusions. Agent: realize-analyst Tool Reference now documents 19 read tools (added get_campaign_reach_estimate under Reach Estimation) + 6 write tools (added create_display_item, update_display_item). Updated count and tool-existence-boundary; UI-only categories explicitly enumerated (Custom Rules, conversion-rule creation, CRM uploads, lookalike seeds). Install: dual-platform manifests (.codex-plugin/plugin.json) + SessionStart hook (.claude/settings.json + scripts/ensure-realize-mcp.sh) for one-shot OAuth onboarding. Hook idempotent: silent no-op when already wired, one-line narration on failure. Guardrails: replace trimmed Apr 2026 version with comprehensive public layer per post-PMM split. Adds banned brand variations, banned competitor terminology, internal codename mapping, banned feature-naming variants (tCPA, eCPC, MaxConv, Realize Pixel, etc.), banned tone patterns, banned ad-creative output, banned content topics, never-guarantee subsection, pattern-based refusal (don't enumerate guardrails). 16-item self-check. Private companion layer kept outside this repo. PMM-aligned brand language throughout: Maximize Conversions, Target CPA, Enhanced CPC, Taboola Pixel, Taboola First Party Audiences, Realize UI. brand-check 0 FAIL. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Resolves 10 conflicts from upstream main's PR taboola#3 (align-latest-mcp) that landed during port work. Resolutions: - skills/create-campaign/SKILL.md (modify/delete): took delete — replaced by the manage-campaigns skill from 0.3.0. - skills/optimize-campaign/SKILL.md: kept the rewrite with rigorous P1-P5 pre-checks + 6-signal RCA + 7-point optimization framework (vs main's older 500-1000 click / $50/day playbook thresholds). - agents/realize-analyst.md: kept 19-read + 6-write tool count, write- routing to manage-campaigns, post-rename tool names. Dropped the stale "Out of scope — no writes" section from main (writes are in scope). - skills/discovery/SKILL.md: kept the 3 minor edits (Realize UI not console; manage-campaigns hand-off not create-campaign). - .claude-plugin/plugin.json: version 0.3.0; description widened to include create/update. - CHANGELOG.md: kept the [Unreleased] port-content + [0.3.0] manage- campaigns + [0.2.0] expanded (fork's superset of main's [0.2.0]). Restructured to remove the auto-merge-induced misplaced 0.2.0 header. - CLAUDE.md: kept the architecture diagram with 19 read + 6 write tools routed through manage-campaigns (vs main's 18-read-only diagram). - README.md: kept the writes-in-scope blurb + manage-campaigns skill row; merged in main's discovery-routing examples section. - docs/realize-best-practices-gap.md: kept manage-campaigns mappings; merged in main's subgrouped Discovery table. Added reach-estimation + writes rows. - tests/test-scenarios-read.md (rename conflict): took the rename split (test-scenarios → test-scenarios-read + -write per 0.3.0). brand-check 0 FAIL. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Claude Code auto-mode classifier flags every Realize write tool because the opaque account_id (e.g. pumikademoaccount) returned by search_accounts doesn't string-match the numeric ID (e.g. 1065940) the user typed — even though both are equivalent representations of the same account, and resolving via search_accounts is the plugin's contracted ID-routing pattern. Object-typed targeting params (country_targeting and siblings) compound the issue, rendering as [object Object] in the classifier's inspection view. Add the 6 Realize write tools to .claude/settings.json's permissions.allow. The manage-campaigns skill's WRITE TARGET preview-then-confirm gate remains the structural safety — the classifier was redundant for the writes routed through that gate. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…-brand-guardrails # Conflicts: # CHANGELOG.md # agents/realize-analyst.md # docs/realize-best-practices-gap.md
Eval feedback uncovered two HG-5 (write-gate bypass) patterns: - Q79: user pre-authorized 'no need to ask before each one' -> plugin applied 5 writes without per-write confirmation. - Q95: user asked for '3 ad variations' -> plugin expanded scope to 30 items across 10 campaigns without confirming the fan-out. Changes: - skills/manage-campaigns/SKILL.md: new 'Scope confirmation' section refusing skip-confirm framings + requiring scope confirmation for ambiguous-target requests. Added 2 gotchas reinforcing these rules. - agents/realize-analyst.md: clarified that the per-write gate is non-bypassable even when the user pre-authorizes. - tests/test-scenarios-write.md: added W8 (skip-confirm refusal) and W9 (ambiguous-target scope confirmation) anchored to eval Q79, Q95. Refs: realize-plugin-fix-list.md FIX-S1. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Eval feedback found pervasive leakage of internal implementation details
into user-facing answers:
- Raw enums / payload syntax: EMPTY_DISPLAY, CVR_LEARNING_LIMITED,
MAX_CONVERSIONS, conversion_rules: [], country_targeting: {...},
INCLUDE [PHON], PENDING_APPROVAL (Q1, Q11, Q13, Q14, Q16, Q34, Q41,
Q65, Q70, Q86 in the eval).
- Internal Taboola employee emails surfaced from change logs:
gal.l@taboola.com (Q34), nandishwar.y@taboola.com (Q70),
mai-ly.n@taboola.com (Q100).
- Vertica SQL queries shown to end users (Q35, Q83).
- MCP tool / skill name leakage: 'manage-campaigns skill',
search_accounts, mcp__plugin_realize-ads-api__* (Q24, Q53).
- Lecturing-tone slips ('the wrong frame', 'silent failure mode',
'silent diagnostic-quality killer' — Q41) and unexpanded RCA
acronym + internal Signal 1/2 framework labels (Q41).
Changes:
- os/guardrails.md:
- New 'Internal field names and enum values' subsection with
payload-to-plain-English translation table.
- New 'Internal tools, skills, and infrastructure' subsection
banning MCP/skill names, other-MCP references, repo paths,
data-warehouse references, and employee emails / names.
- Expanded 'Banned tone patterns' with lecturing/wrong-frame,
internal-process callouts, unexpanded acronyms, signal-framework
labels, and 'what NOT to do'-led answers.
- Self-check expanded with 4 new items covering all of the above.
- scripts/brand-check.sh:
- FAIL: Vertica references; trc.* schema; first.last@taboola.com
employee emails (support@ / billing@ aliases not flagged).
- WARN: lecturing-tone phrasing; mandatory-pre-checks / silent-*;
unexpanded RCA; Signal N framework; raw enum values in
user-facing text.
- All new patterns scoped to PUBLIC files (skip /os).
Refs: realize-plugin-fix-list.md FIX-T1, T2, T5, T6, B6, B9.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…nt-default)
Eval feedback found substance errors and mischaracterizations in the
plugin's knowledge layer:
- Q65: plugin recommended switching to Target CPA at $16 when actual
campaign CPA was $26 — too harsh, scale would collapse. User flagged
starting closer to actual then dropping gradually as best practice.
- Q13, Q16: plugin misunderstood predictive audience campaigns. Q16
also confused Native (with STATIC_IMAGE/PERFORMANCE_VIDEO items)
with Display (banner ads), claiming the campaign had "no Display
creatives" when it was a Native campaign in the first place.
- Q41, Q13: plugin described account-default conversion goal as a
'silent failure mode' / 'silent diagnostic-quality killer'. User
flagged: account-default routing is a valid configuration when the
include-in-total events are sensible — not a failure mode.
- Q41 broader: plugin surfaced internal framework labels ('mandatory
pre-checks', 'RCA' unexpanded, 'Signal 1/2 chain', 'silent failure
mode') in user-facing answers. Per B2 guardrails these belong in
the model's internal scaffolding, not the user output.
Changes:
- skills/optimize-campaign/SKILL.md:
- Added 'Internal vs user-facing terminology' callout at the top
with a translation table. The framework labels (P1-P5, RCA,
Signal 1-6, residual signal, restructure shock) stay for model
reasoning; the callout instructs the model not to surface them
to users.
- Reworded P2 (campaign-level conversion goal check) to describe
account-default routing as a valid configuration, not a 'silent
failure mode'. Only flag if include-in-total events don't match
user intent.
- knowledge/bidding.md:
- New 'Target CPA calibration' subsection: set Target CPA at or
above actual current CPA, then drop gradually in ~10-15% steps
after 5-7 day stabilization. Explicit anti-pattern: don't start
Target CPA at the user's aspirational goal when actual is far
above.
- knowledge/targeting.md:
- New 'Predictive audience campaigns — signal dependencies beyond
the seed event' section: parallel campaigns on the same account
feed the predictive model; pausing them starves it. Diagnostic
table for stalled-predictive scenarios.
- New 'Native vs Display creative type' section: campaigns are
either Native or Display, locked at creation. Native with
STATIC_IMAGE/PERFORMANCE_VIDEO items is NOT 'Display with no
Display ads'. EMPTY_DISPLAY learning state on a Native-locked
campaign is expected, not a problem. For Display reach, launch
a separate Display campaign.
Refs: realize-plugin-fix-list.md FIX-B1, B2, B3, T4.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…emature commit)
Eval feedback found behavioral patterns the plugin needs upstream rules
for, before any skill is invoked:
- Q18, Q97: plugin over-engaged on questions that should have been
one-sentence refusals. Q97 (creative copywriting OOS) produced 5
angles of rewrites + critique. Q18 (pixel-firing OOS) ran a 5-minute
deep-dive on 180 conversion rules.
- Q40, Q76, Q50: plugin attempted MCP calls in UI-only domains
(EVEN traffic toggle, block-list edit, claimed no MCP campaign-
creation tool exists), then surfaced 404s rather than refusing
upfront with the UI redirect.
- Q62: plugin offered "platform-agnostic principles" for an Outbrain
optimization request, when the right answer was to refuse the
cross-platform ask entirely.
- Q69: plugin claimed item had no spend when it actually had spent —
failed to validate the user's premise before reasoning from it.
- Q61, Q9, Q45: plugin used premature commitment language ("I'll
create this campaign...") before the action had completed.
- Q41 (broader): plugin shipped a wall-of-text answer with sources
footer enumerating MCP tool calls; multiple repeated config tables;
no length discipline.
Changes:
- os/guardrails.md:
- New 'Length target — default ≤ 250 words for routine answers'
subsection with exemptions for write previews, multi-part
diagnostics, structured tables; explicit 'stop and offer to
continue' pattern if exceeding the budget legitimately.
- New 'Refusals are short' subsection: one sentence + redirect;
no enumeration of related capabilities, no internal-architecture
walk-through, no hedging.
- New 'Don't list sources / tool calls at the end of the answer'
rule: scope footer (date/account/filters/attribution) is the
only sourcing; never enumerate MCP tool names.
- Self-check expanded with 3 new items.
- agents/realize-analyst.md:
- New 'Upfront triage — capability check before any tool calls'
section with classification table (UI-only / OOS outside Realize
/ cross-platform / malicious / in-scope-but-ambiguous-scope).
Names Q18 + Q97 as the two over-engagement traps.
- New 'Validate user claims before reasoning from them' section
anchored to Q69.
- New 'Don't pre-commit to a future action's success' section
anchored to Q61; contrasts intent-announcing language (good)
vs result-claiming language (premature).
Refs: realize-plugin-fix-list.md FIX-T3, B4, B5, B8, R1 (carried),
R2, R3, R5.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Eval feedback found three friction points and one alias-invention:
- Q30 user feedback: "Could also be helpful for the plugin to provide
the user with a direct URL to go to in the UI." Today the plugin
surfaces menu paths only ("Realize UI -> Campaigns -> overflow ->
Delete"). A one-click deeplink reduces friction.
- Q73: plugin invented 'billing@taboola.com' alias when directing the
user for a refund. That alias may not exist for all users. User
feedback: "Better to say AM or support@taboola.com, better not to
use other alias such as 'billing@taboola.com' or any other thing."
- Q65: plugin recommended "look at this again in a week to let delayed
conversions catch up" — but the event in question was months in the
past. The plugin reasoned from the user-stated date without checking
against today's actual date.
Changes:
- os/guardrails.md:
- New 'Support / contact aliases — only use approved destinations'
subsection. Only the user's AM, support@taboola.com, and the
in-platform UI are approved. Function-specific aliases
(billing@, finance@, crt@, policy@) are explicitly banned.
- New 'Date awareness — anchor recommendations to today's date'
subsection. Computes days_elapsed = today - event_date and gates
'wait and re-evaluate' language: > 14 days = data has settled,
> 30 days = data is final.
- knowledge/realize-ui-deeplinks.md (new file):
- Deeplink templates for Realize-UI-only actions (campaign edit,
block list, Conversions, Pixel status, Audiences, Custom Rules,
GenAI Ad Maker, Billing). Each with menu-path fallback.
- Rules for when to surface a deeplink vs. fall back to menu-path
only (route-protected pages, filter state, beta features).
- knowledge/manifest.json:
- Registered the new realize-ui-deeplinks topic with tags so the
agent picks it up when needed.
- skills/manage-campaigns/SKILL.md:
- UI-fallback section preamble updated to instruct the skill to
emit a deeplink alongside the menu path, citing
realize-ui-deeplinks.md.
Refs: realize-plugin-fix-list.md FIX-B7, B10, R4.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Fix/eval feedback 2026 06
The realize-ui-deeplinks.md file shipped in B5 used a base URL of ads.taboola.com with path-based account scoping (/accounts/<account_id>/...). The real Realize UI lives at ads.realizeperformance.com and uses query-string scoping (?accountId=<numeric>). Example of a real Custom Rules URL: https://ads.realizeperformance.com/performance-rules ?locale=en &accountId=1009840 &reportId=performance-rules ... None of the deeplink templates I shipped would have resolved. Worse, the whole 'click-once deeplink' scheme may not generalize across the Realize UI — the path / query structure varies by page (performance- rules vs other report views) and some flows likely don't have stable deeplinks at all. This commit: - Deletes knowledge/realize-ui-deeplinks.md. - Removes the manifest.json entry that registered the topic. - Reverts the manage-campaigns/SKILL.md UI-fallback preamble to plain menu-path-only redirects, with an explicit instruction NOT to fabricate deeplinks. If the team wants verified deeplinks later, capture the real URL for each UI-only flow first (open the page in the Realize UI, copy the URL, document the param schema), then re-introduce the file with only verified entries. Refs: realize-plugin-fix-list.md FIX-B10 (reverted; needs UI walk). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Revert B5 deeplinks: URLs were fabricated, structure unverified
|
mcp-write-surface.md:195-198 — nonexistent readback tools. Table lists get_all_campaigns, get_campaign_items, get_campaign_item — none exist in the MCP. Correct names: list_campaigns, list_items, get_item. |
|
mcp-write-surface.md:210 — invalid spending_limit_model="DAILY". Enum is NONE|MONTHLY|ENTIRE (API + MCP). For a daily budget use spending_limit_model="NONE" + daily_cap= + daily_ad_delivery_model="STRICT". |
|
mcp-write-surface.md:214,240 — wrong conversion_rules shape. Sends [{"rule_id":""}]; API/MCP expect {"rules":[{"id":}]} (key id, nested under rules, integer not string). |
|
mcp-write-surface.md:239 (block 232-243) — target_roas at create is impossible. Field name is wrong (API = roasGoal) and ROAS can't be set on create_campaign for any account; it's update-only, DCO-accounts-only, and MCP doesn't wire it at all. Remove the field/example. (Plugin fix now; separate upstream MCP issue if ROAS support is ever wanted.) |
|
mcp-write-surface.md:252-254 — wrong publisher_bid_modifier shape. Sends [{"publisher_id":,"modifier_pct":+20}]; API/MCP expect {"values":[{"target":"<publisher_name>","cpc_modification":1.25}]} (publisher name not id; multiplier not percent). |
|
CONTRIBUTING.md:37 — checklist - [ ] No write paths added to MCP tools contradicts the now-enabled writes. Reword to the real policy. |
|
Codex build (.codex-plugin/plugin.json) ships the full .mcp.json — including the 6 write tools — but none of the skills, so its claim that writes are "not available on Codex" is false and writes run without the manage-campaigns preview-confirm gate. Either port the write-gate into os/guardrails.md (or scope Codex to read-only) and document/test it, or drop the manifest until Codex is a real target. Note the realize-mcp runs on different port for codex - so mcp install instructions should change if codex is supported. Also conflicts with name of repo., |
|
Fix contradictions between skill and knowledgebase:
|
|
Committed permissions.allow pre-approves all 6 raw write tools → no permission prompt. The preview-then-confirm gate is otherwise just SKILL.md prose; this allowlist
|
|
knowledge/manifest.json creative entry — phantom content ✓ confirmed Manifest advertises tags + description for creative.md that don't exist in the file. Verified grep counts in creative.md: Wilson=0, validity tier=0, 3P=0, 1P=0,
See creative.md for the full Display recipe." No Display recipe in creative.md (no 3P/1P/ad_tag/asset_url). The real Display item shape lives in targeting.md:206-209.
|
|
knowledge/campaign-structure.md:64 vs 66 — inconsistent bundling thresholds. CONFIRMED (low). Both lines answer the same question — "when is budget too small to split platforms, so bundle instead?" — but with different, unreconciled units:
The problem: one is a total figure, the other per-day + strategy-specific, with no relationship stated. They can disagree — e.g., a $3k/day campaign over a 1-day flight is
|
|
skills/manage-campaigns/SKILL.md:52 says cpc_cap "valid on all strategies (… MAX_CONVERSIONS / TARGET_CPA / MAX_VALUE)." API + MCP both say MAX_CONVERSIONS only (CpcCapTransformer.java:39; registry.py:500). Sending cpc_cap on TARGET_CPA/MAX_VALUE → API 400. Note: knowledge/bidding.md is silent on this, so the SKILL is the lone offender. Fix: "valid only on MAX_CONVERSIONS. |
|
Campaign Groups are heavily mentioned in plugin - but does not yet have MCP support. Maybe remove it until we have MCP support? |
MCP write-surface API fixes (skills/manage-campaigns/references/mcp-write-surface.md):
- Readback tool names: get_all_campaigns/get_campaign_items/get_campaign_item
-> list_campaigns/list_items/get_item
- spending_limit_model="DAILY" (invalid enum) -> "NONE" + daily_cap +
daily_ad_delivery_model="STRICT"
- conversion_rules shape: [{"rule_id":"..."}] -> {"rules":[{"id":<int>}]}
- target_roas at create removed; roasGoal documented as update-only,
DCO-only, not MCP-wired
- publisher_bid_modifier: [{publisher_id,modifier_pct}] ->
{"values":[{"target":<name>,"cpc_modification":<multiplier>}]}
- cpc_cap narrowed to MAX_CONVERSIONS only across scalar table, bid-lever
matrix, refuse-and-reframe rules, failure-mode table
SKILL <-> knowledge consistency (skills/manage-campaigns/SKILL.md +
knowledge/bidding.md + knowledge/campaign-structure.md +
skills/optimize-campaign/references/optimization-flow.md):
- TARGET_CPA minimum 5x/150x -> 10x CPA/day (matches bidding.md)
- SMART (Enhanced CPC) split out with 5x/150x minimum
- cpc bid-lever gate: FIXED-only -> SMART + FIXED
- Canonical bid-lever matrix in bidding.md: dropped Target ROAS row,
fixed cpc_cap row (MAX_CONVERSIONS only), Target CPA MAX_VALUE cell
cleaned, editing-note guard added for downstream copies
- Bundling threshold: dropped "~$5K total"; kept per-day strategy rule
- optimization-flow.md target_roas reference updated
Codex + permissions safety:
- Ported write-tool gate from manage-campaigns SKILL to os/guardrails.md
so it covers Codex (which doesn't load skills): 6 write tools listed,
WRITE TARGET header mandatory, explicit Yes/No/Edit confirm flow,
refuse confirmation-skip framings, scope-fan-out confirmation, UI
fallback for non-MCP actions
- Removed write-tool allowlist from committed .claude/settings.json;
added .claude/settings.local.json.example template for per-user opt-in;
.gitignore'd settings.local.json
- INSTALL.md: optional opt-in section + experimental Codex install
section with manifest-name + MCP URL/port caveats
- .codex-plugin/plugin.json description updated
- CONTRIBUTING.md PR checklist rewritten: stale "No write paths added"
-> three new lines covering skill routing, write-gate inheritance,
per-user opt-in pattern
Manifest + Campaign Groups + closed-gap restructure:
- knowledge/manifest.json: trimmed creative entry (removed phantom
Wilson / validity-tier / 3P-JS-tag / 1P-hosted / create_display_item
tags that don't exist in creative.md)
- knowledge/creative.md: added breadcrumb pointer to targeting.md for
the Display item MCP payload shape
- knowledge/campaign-structure.md: added MCP-support-status callout at
top of Campaign Groups section (assignment is UI-only today)
- docs/realize-best-practices-gap.md: closed-gap entries moved out of
"Future ability" tables into "Closed gaps in this section:" subsections
Wire publisher block-list edits (responds to Chris's Jun 15 upstream
work "Add structured support: Block List via MCP"):
- agents/realize-analyst.md: removed "block-list edits" from UI-only
triage; new explicit routing row; block-list note added under
update_campaign Tool Reference entry
- skills/manage-campaigns/SKILL.md: new "Publisher block-list edits"
recipe (search_publishers -> get_campaign -> merge -> top-N guard ->
side-by-side preview -> confirm -> write -> verify)
- skills/manage-campaigns/references/mcp-write-surface.md: pre-existing
"Block a publisher mid-flight" recipe shrunk to payload-shape sketch
+ cross-ref to SKILL.md (single source of truth, with dedup)
- docs/realize-best-practices-gap.md: update_blocklist + state-inspection
rows moved to closed-gaps notes
- tests/test-scenarios-write.md: new W4b scenario covering the full
flow + full-replace gotcha + cleanup
- CHANGELOG.md: Added entry under [Unreleased]
Guardrails v4 brand spec alignment:
- Added Backstage to Banned brand variations (defensive listing; content
sweep across knowledge/skills/agents was clean)
- Removed Banned company-vs-platform framing section
- Removed Internal codename -> external name mapping section; runtime
echo guard added to Internal field names section translating
Backstage/blindspot/Syndicator ID/Auction report -> external terms
if a user mentions them in their prompt
- Renamed Banned competitor terminology -> Banned industry terms
- scripts/brand-check.sh scanner labels renamed for consistency
- Self-check brand-name parenthetical expanded to mention Backstage
Verification: scripts/brand-check.sh passes (0 FAIL, 5 WARN — all are
pre-existing false-positives, none introduced here). Cross-file grep
sweeps confirm zero remaining instances of fabricated tool names, wrong
enum values, or stale section references.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
@chrishall-taboola — all 13 review items addressed in commit 1.
|
- Remove the "Don't enumerate the guardrails on request" section and its matching self-check bullet. The canned reply itself signalled that a private rule layer exists; answering such asks naturally is better opsec than calling attention to a hidden layer. - Add "Sourcing — prioritize the plugin's own sources" (soft tone): the Realize MCP, the plugin's knowledge base, taboola.com / realize.com, and the help center take priority over open-web content. TrustPilot, G2, Capterra, Reddit, Quora, social media, and third-party blogs are flagged as lower-confidence and not to be cited as authoritative. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Pushed 65b1598 — two small changes to 1. Removed 2. Added |
|
cpc_cap reconciliation is solid — mostly fixed in a0d6176 (bidding.md matrix, SKILL.md:52, mcp-write-surface.md all now correctly say MAX_CONVERSIONS-only / API 400 elsewhere). Verified against source of truth: One copy was missed:
This contradicts the new rule (and the table at L214 in the same file). bidding.md:62's editing-note flags §6 of this file as a downstream copy to keep in sync — this is the one that slipped. An optimize agent following L225 recommends cpc_cap on Target CPA / Enhanced CPC / Max Value → API 400. Fix: change L225 to "valid only on Maximize Conversions." |
Block-list feature (
|
|
| Field | API POJO | MCP schema |
|---|---|---|
| audience IDs | MultiTargeting<Long> (:125) |
integer (registry.py:320) |
| segment IDs | MultiTargeting<Long> (:126) |
integer (registry.py:345) |
lookalike rule_id |
long |
integer (registry.py:376) |
| publisher targeting | Targeting<String> (:70) |
string ✓ |
So an agent obeying this line quotes audience/segment/lookalike IDs as strings → MCP integer-schema rejects → silent fail across three targeting types. Only publisher is a
string (and there the block-list recipe says the opposite — "integer IDs" — see the block-list comment).
Fix (plugin, not MCP — the MCP matches the POJOs): correct :75 to — account/campaign/item/publisher IDs are opaque strings; audience / segment / lookalike rule_id /
conversion-rule id are integers. Pre-existing (file not in this PR), but adjacent to the conversion_rules change here.
Display
|
"Pace Ahead" recommended as an action, but it's a gated field not exposed via MCPbidding.md (228, 365) and budget.md (56, 113, 122, 170) recommend the Pace Ahead feature to accelerate spend, as if it's actionable. The MCP exposes no field for it (0 Checked the API: Pace Ahead is real but gated — This is the same posture as Fix: add a "Pace Ahead is UI-only — gated field, not exposed via the MCP; set it in the Realize UI" callout next to these recs, matching the |
…rce-of-truth
HIGH:
- publisher_targeting payload: convert "integer IDs" + [10,12,14] examples
to string IDs across manage-campaigns/SKILL.md, mcp-write-surface.md,
and the matching W4b test scenario. The MCP validator schema is
items: {type: string}; integer values hard-fail.
- Hoist merge-before-write rule into os/guardrails.md Confirmation flow
step 2. Codex doesn't load skills, so the gate is the only contract
that prevents "block ESPN" from silently wiping pre-existing blocks
on list-replace fields (publisher_targeting, country_targeting,
platform_targeting, audience_targeting, audience_targeting_excluded,
contextual_segments).
Documentation-coherence:
- optimize-campaign/references/optimization-flow.md:225: cpc_cap is
Maximize-Conversions-only — sending it on Enhanced CPC / Fixed Bid /
Target CPA / Maximize Value returns API 400. Aligns with the L214
matrix in the same file and with knowledge/bidding.md.
- discovery/SKILL.md:75: re-categorize ID types. Opaque strings are
account / campaign / item / publisher; integers are audience_id,
segment_id, lookalike rule_id, and conversion-rule id. Matches the
API POJOs (Targeting<String> for publisher, MultiTargeting<Long>
for the rest) and MCP schemas.
- Display ad_tag: drop the dangling "see knowledge/creative.md for the
validator allowlist" pointers (creative.md never contained an
allowlist; the validator is a per-vendor server-side ordered list).
Refs cleaned in agents/realize-analyst.md, skills/manage-campaigns/
SKILL.md, and references/mcp-write-surface.md. Inline wrapper rules
retained.
- Display ad_tag error-recovery: split the single "400 Unsupported tag,
strip the wrapper" advice into two distinct cases that match the
validator's UNSUPPORTED_TAG (vendor not configured — route to AM,
do not retry) and INVALID_STRUCTURE (wrapped markup — strip and
retry) error paths.
Pace Ahead UI-only callout added at all six refs (knowledge/bidding.md
L228, L365 and knowledge/budget.md L56, L113, L122, L170), mirroring
the existing roasGoal pattern: not exposed via the MCP, set in the
Realize UI.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Self-review found the Codex merge rule named three fields that don't exist in the upstream MCP — exactly the silent-failure category the rule was meant to close. Corrections: - Replace invented names (`audience_targeting`, `audience_targeting_excluded`, `contextual_segments`) with the real field names from `skills/manage-campaigns/references/mcp-write-surface.md`: `audiences_targeting`, `contextual_segments_targeting`, `lookalike_audience_targeting`. - Extend the list to cover every full-replace targeting block the plugin documents: `region_country_targeting`, `dma_country_targeting`, `city_targeting`, `postal_code_targeting`, `os_targeting`. Codex now has the complete inventory. - Add the item-update array fields `verification_pixel` and `viewability_tag` (on `update_native_item` / `update_display_item`) — also full-replace per SKILL.md, also missed by the original rule. - Switch terminology from "list-replace" to "full-replace" to match the language already used throughout `skills/manage-campaigns/`. Two synonyms for the same concept invited confusion. - Restructure step 2 from one dense inline paragraph into three sub- bullets so the rule scans cleanly on Codex's read of the gate. Also gitignore the local PR / review / reply draft .txt files at repo root so they stop showing as untracked. Patterns are narrow (`/pr-description-*.txt`, `/pr*-comment-*.txt`, `/reply-to-*.txt`) — no risk of accidentally swallowing real content. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Thanks Chris — all 5 addressed across
Also: Pace Ahead UI-only callout added at all 6 refs across |
Two related runtime tone rules added to os/guardrails.md and propagated
through the knowledge layer. Anchor for both: brand-voice review feeding
into product, June 2026.
1. Publisher and site framing — measurable performance, not name
- New section in os/guardrails.md establishing that publisher / site
recommendations describe measurable performance ("0 conversions over
14 days", "CPA exceeds 3x campaign average") + action, not the
publisher's character or reputation in the abstract. Ties back to
existing frozen brand phrases (Embedded publisher integrations,
Code on page integrations) so the rule reads as brand-voice
extension rather than a banned-word list.
- knowledge/site-management.md opener softened: "blocking bad sites"
-> "excluding sites that underperform on the campaign's KPI".
- scripts/brand-check.sh: defense-in-depth FAIL regexes for
publisher-character framing and rescue / salvage framing.
2. Reader framing — the operator, not a relay through them
- New section in os/guardrails.md establishing that the reader is the
campaign operator (self-serve advertiser, agency running on behalf
of a brand, or in-house media buyer) — never a Taboola Account
Manager relaying instructions to "the client". Possessive
"your client" / "my client" stay in voice for the agency case.
- Knowledge-layer reader-voice sweep: brand-safety.md (13 phrasings
+ section retitle "When an Advertiser Complains" -> "Responding to
a Brand-Safety Complaint"), tracking.md (14 phrasings + 2 retitles
including "How to communicate this to clients" -> "What to plan
for"), environments.md (Sponsored Content <-> Display section
retitle from "Upsell" to "Expansion" + 4 table-row rewrites + Apple
News "What to plan for" block), bidding.md (Overview, attribution
notes, FIXED-use trigger, Enhanced CPC framing, budget-restriction
guidance), targeting.md (Tier-1 caveat, MRT bundles, Marketplace
row, pixel and CRM retargeting bullets), creative.md (Display
add-format pro tip), budget.md (short-burst definition),
site-management.md (approved-list dynamics), and
skills/manage-campaigns/SKILL.md (Fixed Bid / MAX_VALUE budget
minimums + 1P-hosted display asset-hosting note). All rewrites stay
in advertiser-direct second person or neutral instructional voice —
no net-new content.
- scripts/brand-check.sh: AM-relay FAIL regexes
(verbs-at-advertiser, modal-at-advertiser, set-expectations,
discuss-with, communicate-to-clients). Tight enough that
"your Account Manager", "client-side merge", and possessive
"your client" stay valid.
- Silent self-check bullets added for both rules.
Brand-check passes 0 FAIL, 5 WARN (WARN count unchanged from prior
baseline).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
amitl-levi
left a comment
There was a problem hiding this comment.
Two related runtime tone rules added to os/guardrails.md
and propagated through the knowledge layer. Anchor for both:
brand-voice review feeding into product, June 2026.
- Publisher and site framing — measurable performance, not
name. Publisher / site recommendations describe measurable
performance ("0 conversions over 14 days", "CPA exceeds 3×
campaign average") + action — never the publisher's character
or reputation in the abstract. Ties back to existing frozen
brand phrases (Embedded publisher integrations, Code on
page integrations) so the rule reads as brand-voice
extension rather than a banned-word list. Removes the one
upstream priming anchor inknowledge/site-management.md
("blocking bad sites" → "excluding sites that underperform
on the campaign's KPI"). Adds defense-in-depth FAIL regexes
toscripts/brand-check.sh. - Reader framing — the operator, not a relay through
them. The reader is the campaign operator (self-serve
advertiser, agency running on behalf of a brand, or in-house
media buyer) — never a Taboola Account Manager relaying
instructions to "the client". Possessive "your client" /
"my client" stay in voice for the agency case.
Knowledge-layer reader-voice sweep across 9 files (~30
phrasings + 3 section retitles, all rewrites stay in
advertiser-direct second person or neutral instructional
voice — no net-new content). Adds AM-relay FAIL regexes to
scripts/brand-check.sh, tight enough that "your Account
Manager", "client-side merge", and possessive "your
client" stay valid.
Section retitles:
knowledge/brand-safety.md"When an Advertiser
Complains" → "Responding to a Brand-Safety Complaint"knowledge/tracking.md"When the Advertiser Refuses Pixel
or S2S" → "When Pixel or S2S Isn't an Option"; inline
"How to communicate this to clients" → "What to plan for"knowledge/environments.md"Sponsored Content ↔ Display
Upsell" → "Sponsored Content ↔ Display Expansion" (4
table-row rewrites)
Silent self-check bullets added to os/guardrails.md for
both rules.
Replaces the single descriptive sentence about the realize-analyst agent with a directive that (a) leads with the rule in bold, (b) names what the skills carry that raw MCP calls bypass — account resolution, CSV conventions, optimization playbook, write-preview gate — and (c) pins the most common miss observed at install time: "performance review" or "insights" asks being answered as ad-hoc analysis on report output instead of being routed to optimize-campaign. One line removed, one line added. No other files touched. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Pushed one more fix— surgical README edit (one line in, one line out, no other files touched). Replaces the single descriptive sentence about the Context: caught from a real install transcript where Claude went straight to the MCP tools and only invoked the skill after being explicitly asked "did you use the skill set?" |
Summary
os/guardrails.md(consolidated system-prompt),knowledge/(10 topic MDs +manifest.json),
scripts/brand-check.sh(linter).authoritative source).
orchestration, routing) into 1 (guardrails) — Claude Code skill-routing
handles intent matching natively.
guardrails layer, and
backlog.mdremoved (content lives indocs/realize-best-practices-gap.mdPart 3).Why
feature renames and tightened banned positioning. Plugin now follows it.
help articles that contradicted the internal realize-toolkit best practices.
The toolkit is now the authoritative source.
separate
routing.mdwas redundant. Single source of truth =os/guardrails.md.Key changes
Test plan
bash scripts/brand-check.shpasses (0 FAIL, 1 known false-positiveWARN)
realize-analystagent readsos/guardrails.mdat session startknowledge/bidding.mdoptimize-campaignskill withthe new toolkit-aligned thresholds
Taboola Realize,Realize console,Marketplace Audiencesnolonger appear in any output
Notes for review
backlog.mddeleted — content (with more detail, including UI paths) is indocs/realize-best-practices-gap.mdPart 3.TODO:markers remain inCLAUDE.md,CONTRIBUTING.md,SECURITY.md— not introduced by this PR.scripts/brand-check.shallowsitem_idas a public MCP parameter (itremains banned as a schema column in the realize-toolkit's separate linter
copy).
Amit comment:
Update (Jun 16 2026 — commit a0d6176)
Addresses all 13 review threads from @chrishall-taboola + bonus work for block-list wiring and guardrails v4 alignment.
MCP write-surface API fixes
skills/manage-campaigns/references/mcp-write-surface.mdlist_campaigns/list_items/get_itemspending_limit_model="DAILY"→"NONE"+daily_cap+daily_ad_delivery_model="STRICT"conversion_rulesshape →{"rules":[{"id":<int>}]}target_roasremoved;roasGoaldocumented as update-only / DCO-only / not MCP-wiredpublisher_bid_modifiershape →{"values":[{"target":<name>,"cpc_modification":<multiplier>}]}cpc_capnarrowed to MAX_CONVERSIONS onlySKILL ↔ knowledge contradictions
cpcbid-lever: SMART + FIXED (was FIXED only)bidding.md: dropped Target ROAS row, fixedcpc_caprow, added editing-note guardCodex + permissions safety
os/guardrails.md(covers Codex without skills).claude/settings.jsonwrite-tool allowlist removed; per-user opt-in template at.claude/settings.local.json.exampleINSTALL.mdadds Codex install section + opt-in permissions docCONTRIBUTING.mdchecklist rewritten to match enabled writesManifest + Campaign Groups + closed-gap restructure
manifest.jsoncreative entry trimmed (phantom Wilson / 1P/3P tags removed)creative.mdtotargeting.mdfor the Display item shapedocs/realize-best-practices-gap.md: closed-gap rows moved out of "Future ability" tablesBlock-list wiring (from Chris's Jun 15 upstream work)
Publisher block-list edits routed through
update_campaign(publisher_targeting=...):manage-campaignsrecipe: search_publishers → get_campaign → merge → top-N guard → preview → write → verifyW4btest scenario with full-replace gotcha + cleanupGuardrails v4 brand spec alignment
Verification:
scripts/brand-check.shpasses (0 FAIL, 5 WARN — all pre-existing false-positives). 19 files changed, 342 insertions, 108 deletions.