@tank/google-search-ads
1.0.2Description
Closed-loop decision engine for Google Search Ads. Generates Google Ads Editor-importable CSVs from a business brief, analyzes weekly CSV exports against industry benchmarks, proposes ranked revisions. SMB-owner focused. Search Network only โ no Display, no Performance Max.
Triggered by
tank install -g @tank/google-search-adsVerified clean
No security issues detected in the latest scan.
Google Search Ads โ Closed-Loop Decision Engine
For SMB owners running their own Google Search Ads. The agent plans, the user imports, the agent analyzes, the agent revises โ every 7 days.
Core Philosophy
- Editor CSV is the contract. Skill output is what Google Ads Editor accepts. Never freeform suggestions; always import-ready files.
campaign.jsonis the single source of truth. CSVs are emitted from it; never edited directly. Roll-back is justcsv_emit.pyon an older version.- Search Network only at v1. No Display, no Smart Campaigns, no Performance Max. McDonald's Gotchas #3 and #4 are non-negotiable.
- Validate before users see it. Two-pass validator (schema + emitted CSV) catches every known Editor failure mode before the user opens Editor.
- The Search Terms Report drives everything. Weekly review = harvest negatives (burns) + promote winners (missed opportunities). That's where the money is.
- Phase out Marshall, lean on McDonald where they disagree on AI-era tactics. McDonald is 2023 vs Marshall's 2020 โ closer to current ground truth.
The Three Commands
plan Brief โ campaign.json + 8 importable CSVs + IMPORT_GUIDE.md
analyze User's CSV exports โ ranked findings vs benchmarks
revise Findings + previous campaign.json โ campaign_v{N+1}.json + DIFF.md + new CSVs
schedule ASK user, only if host has cron primitive โ fall back to .ics + crontab line
Quick-Start: Common Problems
"Help me set up Google Ads for my business"
- Run prompt
prompts/plan-brief.mdโ 11 questions. - Save user answers as
brief.json(template inassets/brief-template.json). scripts/plan.py --brief brief.json --out campaign.jsonโ producescampaign.json.scripts/csv_emit.py --in campaign.json --out-dir out/โ 8 CSV files.scripts/validate.py --in campaign.json --csv-dir out/โ must exit 0 before handoff.- Hand
out/directory +assets/IMPORT_GUIDE.mdto user. - Run
scripts/cron_detect.pyto see if host has a scheduler. - ASK the user (don't assume): "Want me to schedule a weekly check-in?"
"My Google Ads are wasting money"
- Ask the user to export the 5 CSVs listed in
prompts/weekly-checkin.md(Campaign, Ad group, Search terms, Keyword with QS columns, Ad). scripts/normalize_report.py --in-dir reports/ --out report.json.scripts/diagnose.py --report report.json --campaign campaign.json --benchmarks assets/benchmarks.json --out findings.json --report-md diagnose-report.md.- Show user the diagnose report (sorted by severity ร confidence score).
- Ask: "Apply the auto-fixable items?" โ never auto-apply without confirmation.
scripts/revise.py --campaign campaign.json --findings findings.json --apply allโ producescampaign_v{N+1}.json+DIFF.md.- Re-emit CSVs from the new version; re-validate.
- Hand new bundle to user for re-import.
"I imported the CSVs but Editor says 'Ambiguous row type'"
Don't combine entity files. Each CSV must hold one entity type only (Campaigns, AdGroups, Keywords, etc.). Re-emit via csv_emit.py โ it always emits one file per entity. If the error persists, run validate.py with --csv-dir and read the validation report.
"I want to revert a revision"
Every revise step keeps campaign_v{N}.json files. To revert:
python3 scripts/csv_emit.py --in campaign_v{N-1}.json --out-dir rollback/
# Import rollback/ in Editor โ it overrides the current state
Decision Trees
When to use which command
| User asks | Run |
|---|---|
| "Set up ads for [business]" | plan + csv_emit + validate (handoff) |
| "Audit / improve / fix my ads" | normalize_report + diagnose (show findings) โ ask before revise |
| "Apply the fixes" / "Yes, go ahead" | revise + csv_emit + validate (handoff) |
| "Roll back" | csv_emit on campaign_v{N-1}.json |
| "Schedule weekly review" | cron_detect โ if found, call its _tool_call with payload; else emit .ics |
Bid-strategy ramp (from references/01-plan-workflow.md)
| Account state | Strategy |
|---|---|
| Brand new, 0 conversions | Manual CPC |
| 1โ49 conversions / month / campaign | Manual CPC |
| 50โ99 conv / mo / camp | Enhanced CPC |
| 100+ conv with lead gen | Target CPA |
| 100+ conv with ecom + wide price range | Target ROAS |
"Should I emit a competitor campaign?"
| Signal | Decision |
|---|---|
User named competitors AND opted in via run_competitor_campaign: true | Yes โ 10% of budget |
| User named competitors but didn't opt in | No (default) โ list them as account negatives in non-brand instead |
| User has no listed competitors | No |
Hard Rules (Validator-Enforced)
| Rule | Source |
|---|---|
No naked broad-match keywords without explicit broad_confirmed: true | McDonald Gotcha #2 |
No Modified Broad (+keyword) โ discontinued since 2021 | Google deprecation |
No Display Network in Networks column | McDonald Gotcha #4 |
| RSA has 3โ15 headlines (โค30 chars each) and 2โ4 descriptions (โค90 chars each) | Google ad spec |
| Path 1, Path 2 โค15 chars, alphanumeric + hyphen | Google ad spec |
Match-type wrapping matches Criterion Type ([...] for Exact, "..." for Phrase) | Editor strict parse |
| Each emitted CSV holds one entity type only | Editor "Ambiguous row type" prevention |
Geo cells in Locations.csv are numeric IDs only | Editor "Unknown location" prevention |
| Headers in English, case-insensitive | Editor multilingual rejection |
Multi-value cells use ; (semicolon) not , | Editor strict parse |
scripts/validate.py enforces all of these. ALWAYS run it before handing CSVs to the user.
Reference Files
| File | Contents |
|---|---|
references/01-plan-workflow.md | 11-question brief, prerequisites, USP six elements, HOT/WARM/COLD keyword tagging, RSA generation rules, campaign-separation matrix |
references/02-csv-schema.md | campaign.json schema, full per-entity CSV column layouts, validator Pass 1 + Pass 2 rule tables with severities |
references/03-diagnose-playbook.md | Industry benchmarks, diagnostic decision tree (search term burn / missed opportunity / lost IS / QS sub-components / etc), worked plumber example |
references/04-cron-integration.md | Host capability detection, OpenClaw/Hermes/Agentic OS/generic payload shapes, .ics + crontab fallback |
Bundled scripts
| Script | Purpose |
|---|---|
scripts/plan.py | brief.json โ campaign.json |
scripts/csv_emit.py | campaign.json โ 8 Editor-compatible CSVs |
scripts/validate.py | Two-pass validator: schema + emitted CSVs. Exit 0 only on zero ERRORs. |
scripts/normalize_report.py | User's UI CSV exports โ unified report.json |
scripts/diagnose.py | report.json + campaign.json + benchmarks โ ranked findings |
scripts/revise.py | Findings โ campaign_v{N+1}.json + DIFF.md |
scripts/cron_detect.py | Detect host scheduler; emit payload or fallback |
Bundled assets
| Asset | Purpose |
|---|---|
assets/brief-template.json | Skeleton for the 11-question interrogation |
assets/benchmarks.json | Industry CTR/CPC/CVR/CPA medians (default + 9 verticals) |
assets/geo-targets-seed.csv | 86 Geo Target IDs (top countries + US states + major cities). Fallback to https://developers.google.com/google-ads/api/data/geotargets for anything missing. |
assets/IMPORT_GUIDE.md | Step-by-step Editor import instructions for the user |
Prompts
| Prompt | When |
|---|---|
prompts/plan-brief.md | First-time setup. Use verbatim โ it lists the prerequisites the user MUST satisfy. |
prompts/weekly-checkin.md | Triggered by cron OR by user request. Lists the 5 reports + UI paths. |
What this skill does NOT do (anti-scope)
- Display Network, Performance Max, Smart Campaigns, Shopping, YouTube, App campaigns โ out of scope.
- Direct Google Ads API write access (developer token gate). Editor CSV bulk import is the supported path.
- Auto-scraping the user's actual account performance โ user uploads CSVs explicitly.
- Auto-applying fixes without user confirmation. Always show DIFF.md first.
- Replacing human judgment on USP, brand voice, or unique offer crafting โ the skill mechanizes the boring parts.