adloop 0.26.0__tar.gz → 0.27.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {adloop-0.26.0 → adloop-0.27.0}/PKG-INFO +26 -3
- {adloop-0.26.0 → adloop-0.27.0}/README.md +25 -2
- {adloop-0.26.0 → adloop-0.27.0}/pyproject.toml +1 -1
- {adloop-0.26.0 → adloop-0.27.0}/pyproject.toml.orig +1 -1
- adloop-0.27.0/src/adloop/ads/pmax.py +721 -0
- adloop-0.27.0/src/adloop/ads/shopping.py +284 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/ads/write.py +95 -43
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/rules/adloop.md +26 -8
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/server.py +249 -11
- adloop-0.26.0/src/adloop/ads/pmax.py +0 -257
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/__init__.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/__main__.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/_mcp_patches.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/ads/__init__.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/ads/ai_max.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/ads/brands.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/ads/client.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/ads/conversion_actions.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/ads/currency.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/ads/custom_conversion_goals.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/ads/enums.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/ads/forecast.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/ads/gaql.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/ads/image_fetch.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/ads/read.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/ads/validate_only.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/auth.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/cli.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/config.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/crossref.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/diagnostics.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/ga4/__init__.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/ga4/client.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/ga4/reports.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/ga4/tracking.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/ga4/write.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/gsc/__init__.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/gsc/client.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/gsc/reports.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/gtm/__init__.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/gtm/client.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/gtm/entities.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/gtm/read.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/gtm/write.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/merchant/__init__.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/merchant/client.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/merchant/read.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/pagespeed.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/reddit/__init__.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/reddit/auth.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/reddit/client.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/reddit/read.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/reddit/schedule.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/reddit/write.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/rules/__init__.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/rules/commands/analyze-performance.md +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/rules/commands/budget-plan.md +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/rules/commands/create-ad.md +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/rules/commands/create-campaign.md +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/rules/commands/diagnose-tracking.md +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/rules/commands/optimize-campaign.md +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/rules_install.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/runtime.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/safety/__init__.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/safety/approval.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/safety/approval_card.html +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/safety/audit.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/safety/guards.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/safety/preview.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/tracking.py +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/upload_card.html +0 -0
- {adloop-0.26.0 → adloop-0.27.0}/src/adloop/uploads.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: adloop
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.27.0
|
|
4
4
|
Summary: The AI command center for Google Ads, Reddit Ads, GA4, and tracking code.
|
|
5
5
|
Keywords: mcp,google-ads,reddit-ads,google-analytics,ga4,cursor,marketing
|
|
6
6
|
Author: Daniel Klose
|
|
@@ -41,6 +41,7 @@ Description-Content-Type: text/markdown
|
|
|
41
41
|
[](https://developers.google.com/google-ads/api/docs/start)
|
|
42
42
|
[](https://developers.google.com/analytics/devguides/reporting/data/v1)
|
|
43
43
|
[](https://github.com/kLOsk/adloop)
|
|
44
|
+
[](https://smithery.ai/servers/adloop/adloop)
|
|
44
45
|
|
|
45
46
|
An MCP server that gives your AI assistant read + write access to Google Ads, Reddit Ads and GA4 — with safety guardrails that prevent accidental spend.
|
|
46
47
|
|
|
@@ -132,6 +133,7 @@ The best features come from real workflows. If you're using AdLoop and find your
|
|
|
132
133
|
| `get_recommendations` | Google's auto-generated recommendations with type, estimated impact, and campaign context |
|
|
133
134
|
| `get_pmax_performance` | Performance Max campaign metrics with network breakdown + asset group ad strength |
|
|
134
135
|
| `get_pmax_assets` | Per-asset details for PMax — field type, serving status, content |
|
|
136
|
+
| `get_asset_group_signals` | A PMax asset group's search themes and audience signal, plus the audiences available for it |
|
|
135
137
|
| `get_detailed_asset_performance` | Top-performing asset combinations — which headline+description+image combos Google selects most |
|
|
136
138
|
| `get_audience_performance` | Audience segment performance — remarketing, in-market, affinity, demographics |
|
|
137
139
|
| `get_change_history` | What changed before the drop: who changed what and when, through which client (UI, API, scripts, auto-applied recommendations), last 30 days |
|
|
@@ -262,6 +264,19 @@ A second ad platform, same safety model. Reddit is a separate connection: its ow
|
|
|
262
264
|
|
|
263
265
|
> **Setup for Reddit Ads tools** — In Reddit Ads Manager open **Business Manager → Developer Application → Create app** (business admins only; no approval wait). Register the redirect URL exactly as `http://localhost:8765/callback`, then run `adloop init` and complete the Reddit Ads step: it opens Reddit's consent page (scopes `adsread` + `adsedit`, permanent grant), stores the refresh token at `~/.adloop/reddit_token.json`, and lets you pick the default ad account. Reddit rate-limits per user (reporting: 60 requests/min) and requires a descriptive User-Agent, which AdLoop builds from your app id and Reddit username. Reddit has no validate-only mode, so `confirm_and_apply(dry_run=true)` re-reads the target and re-checks the safety caps instead.
|
|
264
266
|
|
|
267
|
+
### Image Uploads
|
|
268
|
+
|
|
269
|
+
An image on your computer, or one you attached in the chat, has no public URL, and an AI app cannot hand the file to a tool. `upload_images` gives it a way in.
|
|
270
|
+
|
|
271
|
+
<p align="center"><img src="https://raw.githubusercontent.com/kLOsk/adloop/main/assets/upload-card.gif" alt="An AdLoop upload card in an AI chat: the user drags a banner onto it, the card shows the upload id, posts it into the chat, and the AI drafts the image asset" width="760"></p>
|
|
272
|
+
|
|
273
|
+
| Tool | What It Does |
|
|
274
|
+
|------|-------------|
|
|
275
|
+
| `upload_images` | Shows an upload card in apps with MCP Apps (drop PNG, JPEG or GIF up to 5 MB); on AdLoop Cloud in other apps it returns a one-time upload link, which a coding agent can also use with `curl -T` |
|
|
276
|
+
| `list_uploads` | The uploads that have not expired yet (kept 24 hours), with id, dimensions and size |
|
|
277
|
+
|
|
278
|
+
The upload ids go into `draft_image_assets(upload_ids=[...])`, or as `upload:<id>` into the image fields of `draft_reddit_ad` on AdLoop Cloud.
|
|
279
|
+
|
|
265
280
|
### Planning Tools
|
|
266
281
|
|
|
267
282
|
| Tool | What It Does |
|
|
@@ -276,13 +291,17 @@ All write operations follow a **draft → preview → confirm** workflow. Nothin
|
|
|
276
291
|
| Tool | What It Does |
|
|
277
292
|
|------|-------------|
|
|
278
293
|
| `draft_campaign` | Create a full campaign structure — budget + campaign (PAUSED) + ad group + optional keywords. Supports Search partners, display expansion, and `max_cpc` for either MANUAL_CPC initial ad-group bids or TARGET_SPEND (Maximize Clicks) CPC caps. |
|
|
294
|
+
| `draft_shopping_campaign` | Create a Standard Shopping campaign for a linked Merchant Center feed — budget, campaign (PAUSED), product ad group, Shopping ad and an "All products" group in one atomic request. Manual CPC, Maximize clicks or target ROAS. |
|
|
295
|
+
| `draft_asset_group_assets` | Add and remove Performance Max assets (text, images incl. uploads, YouTube videos) in one change, so replacing an asset never drops a group below Google's minimums |
|
|
296
|
+
| `draft_asset_group_signals` | Add search themes or set the audience signal of a PMax asset group |
|
|
297
|
+
| `draft_pmax_product_exclusions` | Exclude products from a retail PMax asset group by item id, brand or custom label |
|
|
279
298
|
| `update_campaign` | Modify existing campaign settings — bidding, budget, geo/language targeting, Search partners, display expansion, and TARGET_SPEND (Maximize Clicks) `max_cpc` caps. |
|
|
280
299
|
| `draft_ad_group` | Create a paused SEARCH_STANDARD ad group inside an existing campaign, with optional MANUAL_CPC `max_cpc`. |
|
|
281
300
|
| `update_ad_group` | Update an ad group name and/or MANUAL_CPC `max_cpc`. Use `pause_entity` / `enable_entity` for ad-group status changes. |
|
|
282
301
|
| `draft_responsive_search_ad` | Create RSA preview (3-15 headlines ≤30 chars, 2-4 descriptions ≤90 chars). Warns if headline/description count is below best practice. |
|
|
283
302
|
| `draft_callouts` | Create campaign callout assets from 1-25 character text snippets. |
|
|
284
303
|
| `draft_structured_snippets` | Create campaign structured snippet assets using official header values and 3-10 snippet values. |
|
|
285
|
-
| `draft_image_assets` | Create campaign image assets from local files
|
|
304
|
+
| `draft_image_assets` | Create campaign image assets from local files, public image URLs or uploads (PNG, JPEG, or GIF). |
|
|
286
305
|
| `draft_keywords` | Propose keyword additions with match types. Proactively checks bidding strategy — flags BROAD match on campaigns without Smart Bidding as dangerous in the preview. |
|
|
287
306
|
| `add_negative_keywords` | Propose negative keywords directly on a campaign |
|
|
288
307
|
| `add_negative_locations` | Propose negative geo exclusions on a campaign — exclude cities/regions while keeping broader positive targets |
|
|
@@ -301,7 +320,7 @@ All write operations follow a **draft → preview → confirm** workflow. Nothin
|
|
|
301
320
|
| `draft_update_custom_conversion_goal` | Rename a custom conversion goal and/or replace its action list (list replace, not append) |
|
|
302
321
|
| `draft_assign_custom_conversion_goal` | Point a campaign at a custom conversion goal (`goal_config_level = CAMPAIGN`) |
|
|
303
322
|
| `draft_clear_custom_conversion_goal` | Put a campaign back on the account-level goals (rollback) |
|
|
304
|
-
| `pause_entity` | Pause a campaign, ad group, ad, or
|
|
323
|
+
| `pause_entity` | Pause a campaign, ad group, ad, keyword or PMax asset group |
|
|
305
324
|
| `enable_entity` | Re-enable a paused entity |
|
|
306
325
|
| `remove_entity` | Permanently remove an entity (irreversible — prefers pause). Supports keywords, negative keywords, ads, ad groups, campaigns. |
|
|
307
326
|
| `confirm_and_apply` | Execute a previously previewed change |
|
|
@@ -337,6 +356,10 @@ AdLoop includes pre-built slash commands in `.claude/commands/` for common workf
|
|
|
337
356
|
|
|
338
357
|
AdLoop manages real ad spend, so safety is not optional.
|
|
339
358
|
|
|
359
|
+
<p align="center"><img src="https://raw.githubusercontent.com/kLOsk/adloop/main/assets/approval-card.gif" alt="An AdLoop approval card in an AI chat: the user clicks Test run, Google validates the change, then Apply makes it live and the card reports back to the chat" width="760"></p>
|
|
360
|
+
|
|
361
|
+
- **Approval cards.** In apps that show MCP Apps (Claude, ChatGPT, VS Code and others), every change appears as a card with Test run and Apply. Only the click applies it: the AI's own `confirm_and_apply(dry_run=false)` is refused with `APPROVE_ON_CARD`, whatever it was told in the chat.
|
|
362
|
+
- **Confirmation dialogs.** Apps without cards that support elicitation (Claude Code, for example) get a dialog from AdLoop itself before every real change. The AI cannot answer it; declining changes nothing.
|
|
340
363
|
- **Two-step writes.** Every mutation returns a preview first. A separate `confirm_and_apply` call is required to execute.
|
|
341
364
|
- **Dry-run by default.** Even `confirm_and_apply` defaults to `dry_run=true`. Real changes require explicit `dry_run=false`.
|
|
342
365
|
- **Two-phase apply (optional).** With `safety.two_phase_apply: true`, `confirm_and_apply` refuses `dry_run=false` until the plan has completed one dry-run pass — preview-then-apply becomes server-enforced instead of a convention.
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
[](https://developers.google.com/google-ads/api/docs/start)
|
|
14
14
|
[](https://developers.google.com/analytics/devguides/reporting/data/v1)
|
|
15
15
|
[](https://github.com/kLOsk/adloop)
|
|
16
|
+
[](https://smithery.ai/servers/adloop/adloop)
|
|
16
17
|
|
|
17
18
|
An MCP server that gives your AI assistant read + write access to Google Ads, Reddit Ads and GA4 — with safety guardrails that prevent accidental spend.
|
|
18
19
|
|
|
@@ -104,6 +105,7 @@ The best features come from real workflows. If you're using AdLoop and find your
|
|
|
104
105
|
| `get_recommendations` | Google's auto-generated recommendations with type, estimated impact, and campaign context |
|
|
105
106
|
| `get_pmax_performance` | Performance Max campaign metrics with network breakdown + asset group ad strength |
|
|
106
107
|
| `get_pmax_assets` | Per-asset details for PMax — field type, serving status, content |
|
|
108
|
+
| `get_asset_group_signals` | A PMax asset group's search themes and audience signal, plus the audiences available for it |
|
|
107
109
|
| `get_detailed_asset_performance` | Top-performing asset combinations — which headline+description+image combos Google selects most |
|
|
108
110
|
| `get_audience_performance` | Audience segment performance — remarketing, in-market, affinity, demographics |
|
|
109
111
|
| `get_change_history` | What changed before the drop: who changed what and when, through which client (UI, API, scripts, auto-applied recommendations), last 30 days |
|
|
@@ -234,6 +236,19 @@ A second ad platform, same safety model. Reddit is a separate connection: its ow
|
|
|
234
236
|
|
|
235
237
|
> **Setup for Reddit Ads tools** — In Reddit Ads Manager open **Business Manager → Developer Application → Create app** (business admins only; no approval wait). Register the redirect URL exactly as `http://localhost:8765/callback`, then run `adloop init` and complete the Reddit Ads step: it opens Reddit's consent page (scopes `adsread` + `adsedit`, permanent grant), stores the refresh token at `~/.adloop/reddit_token.json`, and lets you pick the default ad account. Reddit rate-limits per user (reporting: 60 requests/min) and requires a descriptive User-Agent, which AdLoop builds from your app id and Reddit username. Reddit has no validate-only mode, so `confirm_and_apply(dry_run=true)` re-reads the target and re-checks the safety caps instead.
|
|
236
238
|
|
|
239
|
+
### Image Uploads
|
|
240
|
+
|
|
241
|
+
An image on your computer, or one you attached in the chat, has no public URL, and an AI app cannot hand the file to a tool. `upload_images` gives it a way in.
|
|
242
|
+
|
|
243
|
+
<p align="center"><img src="https://raw.githubusercontent.com/kLOsk/adloop/main/assets/upload-card.gif" alt="An AdLoop upload card in an AI chat: the user drags a banner onto it, the card shows the upload id, posts it into the chat, and the AI drafts the image asset" width="760"></p>
|
|
244
|
+
|
|
245
|
+
| Tool | What It Does |
|
|
246
|
+
|------|-------------|
|
|
247
|
+
| `upload_images` | Shows an upload card in apps with MCP Apps (drop PNG, JPEG or GIF up to 5 MB); on AdLoop Cloud in other apps it returns a one-time upload link, which a coding agent can also use with `curl -T` |
|
|
248
|
+
| `list_uploads` | The uploads that have not expired yet (kept 24 hours), with id, dimensions and size |
|
|
249
|
+
|
|
250
|
+
The upload ids go into `draft_image_assets(upload_ids=[...])`, or as `upload:<id>` into the image fields of `draft_reddit_ad` on AdLoop Cloud.
|
|
251
|
+
|
|
237
252
|
### Planning Tools
|
|
238
253
|
|
|
239
254
|
| Tool | What It Does |
|
|
@@ -248,13 +263,17 @@ All write operations follow a **draft → preview → confirm** workflow. Nothin
|
|
|
248
263
|
| Tool | What It Does |
|
|
249
264
|
|------|-------------|
|
|
250
265
|
| `draft_campaign` | Create a full campaign structure — budget + campaign (PAUSED) + ad group + optional keywords. Supports Search partners, display expansion, and `max_cpc` for either MANUAL_CPC initial ad-group bids or TARGET_SPEND (Maximize Clicks) CPC caps. |
|
|
266
|
+
| `draft_shopping_campaign` | Create a Standard Shopping campaign for a linked Merchant Center feed — budget, campaign (PAUSED), product ad group, Shopping ad and an "All products" group in one atomic request. Manual CPC, Maximize clicks or target ROAS. |
|
|
267
|
+
| `draft_asset_group_assets` | Add and remove Performance Max assets (text, images incl. uploads, YouTube videos) in one change, so replacing an asset never drops a group below Google's minimums |
|
|
268
|
+
| `draft_asset_group_signals` | Add search themes or set the audience signal of a PMax asset group |
|
|
269
|
+
| `draft_pmax_product_exclusions` | Exclude products from a retail PMax asset group by item id, brand or custom label |
|
|
251
270
|
| `update_campaign` | Modify existing campaign settings — bidding, budget, geo/language targeting, Search partners, display expansion, and TARGET_SPEND (Maximize Clicks) `max_cpc` caps. |
|
|
252
271
|
| `draft_ad_group` | Create a paused SEARCH_STANDARD ad group inside an existing campaign, with optional MANUAL_CPC `max_cpc`. |
|
|
253
272
|
| `update_ad_group` | Update an ad group name and/or MANUAL_CPC `max_cpc`. Use `pause_entity` / `enable_entity` for ad-group status changes. |
|
|
254
273
|
| `draft_responsive_search_ad` | Create RSA preview (3-15 headlines ≤30 chars, 2-4 descriptions ≤90 chars). Warns if headline/description count is below best practice. |
|
|
255
274
|
| `draft_callouts` | Create campaign callout assets from 1-25 character text snippets. |
|
|
256
275
|
| `draft_structured_snippets` | Create campaign structured snippet assets using official header values and 3-10 snippet values. |
|
|
257
|
-
| `draft_image_assets` | Create campaign image assets from local files
|
|
276
|
+
| `draft_image_assets` | Create campaign image assets from local files, public image URLs or uploads (PNG, JPEG, or GIF). |
|
|
258
277
|
| `draft_keywords` | Propose keyword additions with match types. Proactively checks bidding strategy — flags BROAD match on campaigns without Smart Bidding as dangerous in the preview. |
|
|
259
278
|
| `add_negative_keywords` | Propose negative keywords directly on a campaign |
|
|
260
279
|
| `add_negative_locations` | Propose negative geo exclusions on a campaign — exclude cities/regions while keeping broader positive targets |
|
|
@@ -273,7 +292,7 @@ All write operations follow a **draft → preview → confirm** workflow. Nothin
|
|
|
273
292
|
| `draft_update_custom_conversion_goal` | Rename a custom conversion goal and/or replace its action list (list replace, not append) |
|
|
274
293
|
| `draft_assign_custom_conversion_goal` | Point a campaign at a custom conversion goal (`goal_config_level = CAMPAIGN`) |
|
|
275
294
|
| `draft_clear_custom_conversion_goal` | Put a campaign back on the account-level goals (rollback) |
|
|
276
|
-
| `pause_entity` | Pause a campaign, ad group, ad, or
|
|
295
|
+
| `pause_entity` | Pause a campaign, ad group, ad, keyword or PMax asset group |
|
|
277
296
|
| `enable_entity` | Re-enable a paused entity |
|
|
278
297
|
| `remove_entity` | Permanently remove an entity (irreversible — prefers pause). Supports keywords, negative keywords, ads, ad groups, campaigns. |
|
|
279
298
|
| `confirm_and_apply` | Execute a previously previewed change |
|
|
@@ -309,6 +328,10 @@ AdLoop includes pre-built slash commands in `.claude/commands/` for common workf
|
|
|
309
328
|
|
|
310
329
|
AdLoop manages real ad spend, so safety is not optional.
|
|
311
330
|
|
|
331
|
+
<p align="center"><img src="https://raw.githubusercontent.com/kLOsk/adloop/main/assets/approval-card.gif" alt="An AdLoop approval card in an AI chat: the user clicks Test run, Google validates the change, then Apply makes it live and the card reports back to the chat" width="760"></p>
|
|
332
|
+
|
|
333
|
+
- **Approval cards.** In apps that show MCP Apps (Claude, ChatGPT, VS Code and others), every change appears as a card with Test run and Apply. Only the click applies it: the AI's own `confirm_and_apply(dry_run=false)` is refused with `APPROVE_ON_CARD`, whatever it was told in the chat.
|
|
334
|
+
- **Confirmation dialogs.** Apps without cards that support elicitation (Claude Code, for example) get a dialog from AdLoop itself before every real change. The AI cannot answer it; declining changes nothing.
|
|
312
335
|
- **Two-step writes.** Every mutation returns a preview first. A separate `confirm_and_apply` call is required to execute.
|
|
313
336
|
- **Dry-run by default.** Even `confirm_and_apply` defaults to `dry_run=true`. Real changes require explicit `dry_run=false`.
|
|
314
337
|
- **Two-phase apply (optional).** With `safety.two_phase_apply: true`, `confirm_and_apply` refuses `dry_run=false` until the plan has completed one dry-run pass — preview-then-apply becomes server-enforced instead of a convention.
|