agentsclimarketplace

Hector search term negation

Skill hectorai-live/hector-amazon-ads/skills/hector-search-term-negation

Hector's Amazon Ads methodology as Claude skills — brand ads audit, keyword harvesting, SQP analysis, and search-term negation, running on the Hector Amazon MCP connector.

Install
npx -y skills add hectorai-live/hector-amazon-ads --skill hector-search-term-negation

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • 11 days oldThe repository was created 11 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Use ONLY when the user explicitly asks to add negative search terms based on bleeding data — trigger phrases include "run search term negation for X", "negate bleeding search terms for X", "add negatives for bleeding in X", "execute bleeding negation on X", and close paraphrases where "negation" or "negative" + a named brand co-occur. Identifies bleeding search terms per the standard Hector bleeding rules (SP-only, ≥ floor(1/CR) clicks, 0 orders, exclude branded, exclude ASIN-pattern, ungrouped), then negates each identified SearchTerm as a NEGATIVE EXACT MATCH in the specific ad group where it is bleeding. Does NOT fire on conversational mentions of negation, on single-term negation requests, on audit requests, or on requests to edit this skill. ALWAYS presents a preview and requires explicit CONFIRM before any write. Runs independently of the audit skill — no prior audit required.

SKILL.md

18.6 KB, ~4.4k tokens by cl100k_base, as published. Nobody here has run it

Hector Search Term Negation (v1)

⚠️ CRITICAL OBLIGATIONS — READ BEFORE EVERY USE

  1. ALWAYS present preview + require explicit CONFIRM before any write. Present summary + top-10 preview. User must type CONFIRM (case-insensitive) to proceed. Any other input = CANCEL. This is a hard gate — never write without an explicit CONFIRM.
  2. NEVER guess the profile_id. Resolve via find_profile_by_name. If a brand was already discussed earlier in this chat, ask the user to confirm rather than asking cold. If multiple profiles match, present them and let user pick. If zero match, stop.
  3. Match type is LOCKED at negative exact match. Never negative phrase, never negative broad. This is non-negotiable.
  4. Negations are scoped to the specific ad group where the term is bleeding. If SearchTerm "soap" bleeds in ad group A AND ad group B, that becomes two separate negation writes — one per ad group. Never negate the same term across all ad groups.
  5. Bleeding logic is IDENTICAL to the audit skill. SP-only, Clicks > floor(1/CR)-1, Orders = 0, exclude branded (via brand classifier), exclude ASIN-pattern (^b0[a-z0-9]{8}$), ungrouped. Same rules, same filter, same click floor computation.
  6. Duplicate negations are SKIPPED and LOGGED. If a SearchTerm is already negated as exact in the target ad group, do not re-add. Log the skip in the change-log CSV with reason "already negated."
  7. Every run produces a change-log CSV at /mnt/user-data/outputs/negation_<brand>_<timestamp>.csv with columns: SearchTerm, Campaign, AdGroup, AdGroupID, Status (added / skipped-duplicate / failed), Reason. This is the audit trail for the write operation.
  8. Runs independently of the audit skill. Fresh MCP pull every time. No dependency on prior audit runs, no reading of audit temp files.
  9. Run the closing self-check before delivering.

Why this skill exists

The Hector brand audit surfaces bleeding search terms in Pillar 2 but does not act on them. Historically, an analyst would export the bleeding table and manually add negatives ad group by ad group — slow, error-prone, and inconsistent across analysts. This skill executes the negation cleanly: same logic as the audit, scoped to the correct ad group, exact match only, with a full audit trail.

The skill is designed to run independently. A user can invoke it without ever having run an audit — the bleeding pull is fresh every time.


When this skill activates

Fires on:

  • "Run search term negation for <brand>"
  • "Negate bleeding search terms for <brand>"
  • "Add negatives for bleeding search terms in <brand>"
  • "Execute bleeding negation on <brand>"
  • Close paraphrases where "negation" or "negative" + a named brand co-occur

Does NOT fire on:

  • Conversational mentions of negation ("we ran negation last week")
  • Single-term negation requests ("negate 'soap' for X") — those are atomic tool calls, not this skill
  • Audit requests — even if the audit surfaces bleeding, running the audit does NOT trigger negation
  • Requests to edit, improve, or review this skill (those go to skill-architect)
  • Requests to negate branded terms or terms already in exact match — the skill refuses these by design

Blocking precondition

You CANNOT proceed to any MCP write call until:

  1. All REQUIRED precursors are collected (account+country, date range, campaign scope)
  2. Bleeding pull is complete and reviewed
  3. User has typed CONFIRM (case-insensitive) in response to the preview

Step-by-Step Execution

Step 1 — Present the precursor block

Open with one sentence acknowledging the negation request. Then present:

Before I start, I need a few things:

REQUIRED
• Account: brand name AND country (e.g. "<brand name>, India") — I'll ask you to confirm if a brand was already discussed in this chat
• Date range: e.g. "Jan 1 – May 26, 2026". Default if unspecified: last 60 days.
• Scope: negate across ALL campaigns, or a SPECIFIC list of campaigns? (default: ALL)

I'll auto-detect brand tokens from the name you give — spaced, joined, "&"/"and", initialism, and common typo forms — and echo them before running so you can add/remove. Branded search terms are excluded from negation.

Context-aware precursor: If a brand was clearly referenced earlier in this chat (e.g., an audit was recently run), replace the account prompt with a confirmation:

I see we discussed <brand> in this chat. Confirm this is the account for negation, or specify a different brand + country.

If the user already supplied all REQUIRED precursors, skip to Step 2.

Stopping condition: all REQUIRED precursors collected.

Step 2 — Resolve the profile

Call find_profile_by_name with the confirmed brand. Filter to the user's country.

  • One match in country: confirm in one line, proceed
  • Multiple in country: list with profile_id + currency, ask user to pick
  • Zero in country: surface, ask about a different country, or stop

Stopping condition: exactly one profile_id confirmed.

Step 3 — Echo brand classifier tokens

Auto-detect brand tokens using the same variant-building rules as the audit skill: the original spaced form, the joined form, the "&" and "and" alternatives, initialisms where the name has multiple words, and plausible misspellings.

Apply them to whatever brand the user named — the skill is not scoped to any particular set of accounts.

Echo the generated tokens. Wait one turn for override. Default-accept if no response.

Stopping condition: brand tokens locked.

Step 4 — Compute account CR and bleeding click floor

One call: analytics_account_health

  • Filters: date range
  • Metrics: ["CR_perc"]

Compute: click_floor = floor(1 / (CR_perc / 100))

Store as click_floor for the next step.

Step 5 — Pull bleeding data

One call: analytics_search_term_list

master_search_filters:

  • {level: "Clicks", type: "greater_than", keywords: click_floor - 1, condition: "and"}
  • {level: "Orders", type: "equal", keywords: 0, condition: "and"}
  • {level: "CampaignType", type: "is", keywords: ["sponsored products"], condition: "and"}
  • If scope = specific campaigns: {level: "CampaignName", type: "is", keywords: [list of campaign names], condition: "and"}

Metrics: ["Spend","Clicks"] limit=1000, sort_column=Spend, sort_type=DESC

Save to /home/claude/negation_data/bleeders_raw.json. Python script:

  1. Exclude branded SearchTerms via brand classifier regex from Step 3
  2. Exclude ASIN-pattern SearchTerms (^b0[a-z0-9]{8}$)
  3. Keep UNGROUPED — one row per SearchTerm × Campaign × AdGroup
  4. Compute per-row CPC = Spend / Clicks
  5. Sort by Spend DESC

Store as bleeders_qualified.json. Surface only aggregates + top-10 preview in chat.

If zero qualifying rows: stop with message "No bleeding search terms found for this account and window meeting the negation criteria."

If exactly 1000 rows returned: flag truncation — the actual bleed set may be larger. Proceed with what was returned; note truncation in the change-log.

Step 6 — Resolve ad group IDs

The bleeding pull returns Campaign name + AdGroup name. Negation writes need AdGroup IDs.

Extract unique (Campaign name, AdGroup name) pairs from bleeders_qualified.json. For each unique pair, resolve to AdGroup ID. Use whichever tool the Hector MCP exposes for ad-group lookup — likely analytics_ad_group_list filtered by campaign name and ad-group name, or query_ad_group if it accepts name lookup. If both are unavailable, use search_records with the ad-group name and campaign filter as fallback.

Store the resolved mapping in adgroup_id_map.json. If any pair fails to resolve, log it with reason "adgroup ID resolution failed" — these rows will be skipped in Step 8.

Step 7 — Check for existing negatives (dedupe)

For each unique AdGroup ID in the mapping, pull the current set of negative exact keywords via negative_keyword_tools (list mode) or equivalent. Store as existing_negatives.json.

Cross-reference each bleeding row against the existing negatives:

  • If the SearchTerm is already negated as exact in that AdGroup → mark as skipped-duplicate
  • Otherwise → mark as to-add

Store as negation_plan.json with the final action per row.

Step 8 — Present preview and wait for CONFIRM

Present in chat:

SEARCH TERM NEGATION — PREVIEW

Account: <brand>, <country>, profile <id>
Date range: <start> to <end>
Scope: <ALL campaigns | X campaigns>

Bleeding analysis complete:
• <total> search terms bleeding across <unique campaign count> campaigns
• <to-add count> will be added as negative exact match
• <skipped-duplicate count> already negated in target ad group — will be skipped
• <resolution-failed count> ad group resolution failed — will be skipped

TOP 10 BY WASTED SPEND (ordered by Spend DESC):
1. "<term>" — <campaign> / <adgroup> — <clicks>c, ₹<spend>
2. ...
...

Reply CONFIRM to add these <to-add count> negatives as EXACT MATCH negatives.
Reply CANCEL to stop.

Wait for user response. If they type CONFIRM (case-insensitive, exact word) → proceed to Step 9. Anything else = CANCEL, stop, no writes performed. Log the cancellation.

Step 9 — Execute negations

For each to-add row in negation_plan.json:

  1. Call the negative-keyword add tool (likely negative_keyword_tools in add mode) with:
    • AdGroup ID
    • Keyword: SearchTerm
    • Match type: negativeExact (or equivalent exact-negative match type per the tool schema)
    • State: enabled
  2. Capture the response
  3. Update negation_plan.json with status: added (success) or failed (with error message as reason)

Process in batches if the tool supports bulk mode. Otherwise iterate one at a time.

Stopping condition: all rows processed (either added, skipped, or failed).

Step 10 — Write change-log CSV

Write to /mnt/user-data/outputs/negation_<brand_slug>_<YYYYMMDD_HHMMSS>.csv:

Columns:

  • SearchTerm
  • Campaign
  • AdGroup
  • AdGroupID
  • Status (added / skipped-duplicate / adgroup-resolution-failed / write-failed)
  • Reason (empty for added; error message for failed; "already negated as exact" for skipped-duplicate; etc.)

Every row from the qualifying bleeders is represented in the CSV, regardless of final status. This is the complete audit trail.

Step 11 — Present the CSV and recap

Call present_files with the CSV path. Post a recap:

NEGATION COMPLETE

• <added> negatives added
• <skipped-duplicate> skipped (already negated)
• <resolution-failed + write-failed> failed
• Full log: negation_<brand>_<timestamp>.csv

Any failed rows should be reviewed manually. Duplicate skips are expected on repeat runs.

Run the closing self-check.


Closing Self-Check (RUN BEFORE EVERY RESPONSE)

  • Precursor block presented (or skipped only if all REQUIRED supplied in opening message)
  • Account+country resolved via find_profile_by_name — never guessed
  • Brand classifier tokens echoed
  • Bleeding click floor = floor(1 / (CR_perc/100)) — never hardcoded
  • Bleeding filter is SP-only (server-side)
  • Bleeding excludes branded SearchTerms (client-side, via brand classifier)
  • Bleeding excludes ASIN-pattern SearchTerms
  • Bleeding is UNGROUPED — one row per SearchTerm × Campaign × AdGroup
  • AdGroup IDs resolved via lookup — never assumed
  • Existing negatives checked; duplicates flagged as skipped
  • Preview presented with summary + top-10
  • User typed CONFIRM (exact word, case-insensitive) before ANY write happened
  • Match type on every negation is EXACT — never phrase, never broad
  • Each negation scoped to the specific AdGroup where the term is bleeding — never global
  • Change-log CSV written with all rows and final statuses
  • present_files called on the CSV
  • Recap posted with counts

If any check fails, fix it before delivering.


What NOT to Do

  • Never write ANY negation without an explicit CONFIRM from the user. Even if the preview looks correct, wait for CONFIRM. No implicit consent.
  • Never use phrase or broad match negation. Exact match only.
  • Never negate a term globally or across multiple ad groups from a single decision. Each negation is scoped to a specific AdGroup.
  • Never negate branded search terms. The brand classifier exclusion is applied at Step 5.
  • Never negate ASIN-pattern search terms. Those are competitor product searches — different treatment.
  • Never skip the AdGroup ID resolution step. Writing to the wrong ID corrupts the account.
  • Never proceed if AdGroup ID resolution fails for a row. Log it, skip it, surface the count in the recap.
  • Never re-add a negation that already exists in the target ad group. Skip and log.
  • Never rely on audit temp files or prior conversation state for bleeding data. Fresh pull every time.
  • Never group the bleeding table. Ungrouped is mandatory — negation is per ad group.
  • Never omit the change-log CSV. Even if zero negations were added, the CSV is written (for cancellation logging).
  • Never continue to Step 9 if the user replies anything other than CONFIRM. "yes", "ok", "sure", "go" = CANCEL. Only the literal word CONFIRM proceeds.

Edge Cases

SituationBehaviour
User says "run negation for X" with no other infoRun full precursor block
Brand was discussed earlier in chatAsk user to confirm, don't re-elicit cold
Multiple profiles match brand+countryList them, ask user to pick
Zero bleeding rows qualifyStop after Step 5. Message: "No bleeding search terms found meeting the negation criteria." No CSV written.
Exactly 1000 rows returned (truncation)Flag in preview. Continue with what was returned. Note in recap.
User replies "yes" instead of "CONFIRM"Treat as CANCEL. Message: "Cancelled — must reply CONFIRM exactly. Re-run the skill to try again."
User cancelsLog the cancellation in a CSV with "cancelled" status on all rows. No writes performed.
AdGroup ID resolution fails for some rowsLog those as adgroup-resolution-failed. Continue with the rest. Report count in recap.
Negative-keyword-add tool returns error on a rowLog as write-failed with error message. Continue with remaining rows.
Skill invoked twice in one chat for different brandsRe-run full precursor block. Reset all temp files under /home/claude/negation_data/.
User specifies scope as "specific campaigns"Elicit the campaign list. Pass to the bleeding pull as a CampaignName filter.
Focus-ASIN requestPolitely decline — explain that negation lives at ad-group level, not ASIN level.
Audit skill was run earlier in same chatIgnore its temp files. Fresh pull as normal.
Account has zero spend in windowStop with message: "Account had no ad spend in the specified window — no bleeding to negate."
User asks the skill to also add positive keywords (harvesting)Decline — that's the Harvesting skill (separate).
CR_perc from account_health returns 0 or nullStop with error: "Cannot compute click floor — account CR is zero for this window. Choose a different date range."

Worked Examples

Example 1 — Happy path

User: "Run search term negation for <brand> India, last 30 days"

  1. Acknowledge. All REQUIRED except scope supplied — ask for scope only.
  2. User: "All campaigns."
  3. Resolve the profile for <brand> IN → confirm.
  4. Echo the generated brand tokens. Accept.
  5. Pull CR → compute click floor (e.g., 7).
  6. Bleeding pull: 87 rows returned.
  7. Filter branded + ASIN → 74 qualifying rows.
  8. Resolve AdGroup IDs → 71 resolve, 3 fail.
  9. Dedupe against existing negatives → 68 to-add, 3 skipped-duplicate.
  10. Present preview: "74 bleeding terms across 12 campaigns. 68 will be added, 3 already negated, 3 resolution failed."
  11. User: "CONFIRM"
  12. Execute 68 writes. 67 succeed, 1 fails with API error.
  13. Write CSV, present, recap.
  14. Self-check ✓.

Example 2 — Context-aware account resolution

User (earlier in chat): "Run the audit for <brand> India, Jan to May" (audit runs)

User (later): "Now run negation for the same account, same window"

  1. Recognize context. Confirm: "Negation for <brand> India, Jan 1 to May 26, all campaigns — CONFIRM this scope."
  2. User confirms.
  3. Proceed with bleeding pull (fresh — do not read audit temp files).
  4. Rest of flow normal.

Example 3 — Cancellation

User: "Run negation for <brand> India, last 60 days, all campaigns"

  1. Resolve the profile for <brand> IN.
  2. Bleeding pull: 145 rows → 92 qualifying after brand/ASIN exclusion.
  3. Preview shown.
  4. User: "Actually not now, cancel."
  5. Skill treats as CANCEL. Writes cancellation-only CSV (all rows marked "cancelled by user"). No MCP writes. Recap: "0 negations added. Cancelled."

Example 4 — Zero qualifying rows

User: "Run negation for <brand> India, last 7 days"

  1. Resolve profile.
  2. Bleeding pull: 0 rows.
  3. Stop. Message: "No bleeding search terms found for <brand> in the last 7 days meeting the negation criteria (Sponsored Products, ≥ N clicks, 0 orders, excluding branded and ASIN terms)."
  4. No CSV written. No writes attempted.

Versioning

v1 — May 27 2026. Initial release. Executes search-term negation based on Hector bleeding pillar logic. Ungrouped, SP-only, negative exact match, scoped to the specific ad group per row. Excludes branded and ASIN-pattern terms. Preview + CONFIRM gate. Change-log CSV every run. Runs independently of the audit skill.

Planned v1.1+:

  • Add "undo" companion skill that reads a change-log CSV and reverses the negations
  • Add optional dry-run mode that produces the CSV without executing writes
  • Integrate with future audit_get_bleeders composite endpoint when tech team ships it
  • Support batching by tool if negative_keyword_tools exposes a bulk-add mode

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.