The NoW of WorkTalk to our team
  1. Skills
  2. Outbound

AI Marketing Bench · Outbound

ICP

Builds and maintains the ideal customer profile and buyer personas from evidence (brand memory, a customer list or CRM export, win/loss and call notes) and writes a points-based scoring rubric another skill can apply to a prospect list.

Install this skill

Claude Code, the whole Outbound capability

/plugin marketplace add ashleahwilson/ai-marketing-bench
/plugin install outbound@ai-marketing-bench

Any agent that supports Agent Skills, this skill only

npx skills add ashleahwilson/ai-marketing-bench --skill icp

claude.ai

Download the skill folder from GitHub as a zip and upload it under Settings → Capabilities → Skills.

What it does

Builds and maintains the ideal customer profile and buyer personas from evidence (brand memory, a customer list or CRM export, win/loss and call notes) and writes a points-based scoring rubric another skill can apply to a prospect list. Computes which segments win, stay and pay from the data, says how many records every finding rests on, and labels small samples as hypotheses. Updates brand/audiences.md in the brand memory format and writes icp/scoring.md in a documented, parseable format (criteria, points, thresholds, disqualifiers). Never invents market size, TAM, benchmarks or persona quotes. With no customer data it writes a clearly provisional hypothesis and says what data would confirm it. Use when the user wants an ICP, target segments, buyer personas, a lead or account scoring rubric, "who should we target", "which customers are our best", or to update the ICP from a new export. Not for building the prospect list itself, writing outreach, or researching one company.

Note from the repo. Recommended for large models. Small models occasionally mislabel a segment count or paraphrase inside quote marks, and both sizes sometimes add a small unsourced aside, so check counts against the analysis. See evals/scorecard.json.

The skill, in full

SKILL.md as published in the repo. Reference files it links to open on GitHub.

Turns customer evidence into three things: who to go after (and who not to), the people who buy, and a rubric that scores a list the same way every time. The data decides what's true; the user decides what to do about it.

Ground rules

  1. Every finding carries its count. "10 of 12 won", "median deal $14,550 (n=10)". A percentage only when the denominator is 10 or more. Under 5 closed records behind a finding is an anecdote, 5–9 a hypothesis. Under 10 closed records in total, the whole ICP is a hypothesis: counts only, status provisional.
  2. Never invent market data. No TAM, SAM, SOM, market size, number of companies in a market, growth rate or "industry average". If asked, say once you don't have a source and won't estimate, name where each figure asked for could come from (one source per figure), and deliver the rest.
  3. Quotes are copied, never written. A persona's words come word for word from call notes, win/loss notes, replies, reviews or brand/proof.md. A role with no recorded words gets TBD, and its other details are tagged assumed.
  4. Missing stays missing. An unknown is TBD: <what would tell us>. A plausible guess is still an invention, and so is a persona backstory.
  5. The user decides the target. When they want a segment the data argues against, show the evidence in counts, write their version (status user-directed), and recommend once. Never refuse, never lecture.
  6. Brand memory's exclusions are disqualifiers. Anything offer.md or audiences.md says the business doesn't do or serve goes into the rubric as a disqualifier with its reason.
  7. Never overwrite the user's files. Before editing brand/audiences.md or icp/scoring.md, copy the current version to icp/history/. Other brand files are read only, except one new line in brand/changelog.md.

Pick the mode

The request… Mode
Has customer data (a CSV or export) and asks for an ICP, segments or a rubric Draft (default): analyze, write both files
Has no customer data Provisional: a hypothesis ICP from brand memory and the request, status provisional, plus the data that would confirm it
Has an existing icp/scoring.md and new data Update: rerun, report what moved, bump the version
Asks only for personas Personas: update the personas in brand/audiences.md; leave the rubric alone
Says "walk me through it", "decide together", "before anything gets written" Guided: findings with counts, then 2–4 decisions, each with a recommendation. No files until they answer

Workflow

- [ ] 1. Load: brand/, the data files, any notes, any existing icp/
- [ ] 2. Analyze the customer data (script)
- [ ] 3. Read the notes for triggers, objections and exact quotes
- [ ] 4. Decide segments, disqualifiers, triggers, personas (references/judgment.md)
- [ ] 5. Write brand/audiences.md and icp/scoring.md, after copying old versions to icp/history/
- [ ] 6. Back-test and self-check (scripts, then the questions in judgment.md)
- [ ] 7. Reply in the fixed shape

1. Load

List the project folder, including subfolders, even if the user named one file. Read brand/BRAND.md, audiences.md, offer.md, positioning.md, proof.md and rules.md where they exist. Find every CSV and every notes file (win/loss, calls, interviews, reviews).

No brand/ folder? Work from the data and the request. Say in the reply that there's no brand memory, mark anything not drawn from the data as provisional, create only brand/audiences.md, and offer to set up the rest.

2. Analyze

python3 scripts/analyze_customers.py <customers.csv> --out icp/analysis.json

It matches columns by common names, drops open deals, duplicates and rows with no outcome, and reports win rate, churn, deal size and cycle by segment, with the sample-size labels applied. Read its header first: which column it read as what, how many rows it excluded and why, which fields are missing, any date warning. If a mapping is wrong, rerun with --map outcome="Deal Stage",deal="ARR".

If any segment field is blank on some rows (they show as "unknown"), say how many and which field under "Before you use it".

Use only figures it printed, each with the exact label of the row it came from. "General dentistry / 1" (one industry at one size) is not "1" (every single-location clinic), and the two have different counts. Never count or add rows by hand: if you need a figure it didn't print (a combined segment, a different cut), rerun with --by or --cross, or leave it out.

No CSV at all: skip to step 3 and use Provisional mode.

3. Read the notes

Pull out what happened before each purchase (triggers), why deals were lost and customers left, what each role is measured on, and their objections. Copy quotes exactly, with who said it and when. Count how many notes support each trigger.

4. Decide

Follow references/judgment.md: check the analysis, rank segments on retention, then win rate, then deal size; pick triggers; build one persona per role the evidence shows. Two rules hold with or without brand memory:

  • Disqualifiers: every brand-memory exclusion, plus any segment with 0 wins in 4 or more closed records whose loss reasons point the same way (procurement, security reviews, an enterprise suite). A zero-win segment must never be able to outscore a segment that wins.
  • Sample labels: 10+ closed records is evidence; say it plainly and don't call it "too few". Under 10 is "too few to be sure", every time it's mentioned. It also covers the hard cases: no data, a tiny sample, a user who insists on a segment, requests for market size, and quotes that don't exist.

5. Write the files

  • brand/audiences.md, in the brand memory format: segments in priority order, triggers, Not for, personas, history. Layout and source tags in references/audiences-format.md.
  • icp/scoring.md, the rubric the list builder reads: a short header (version, date, status, basis, max points, tiers), then | Criterion | Points | Evidence | tables for criteria and disqualifiers. Each criterion is written in the list builder's grammar (Industry: a, b, Locations 5–19, Locations 20+, Signal new location: yes) and disqualifiers score DQ. Format in references/scoring-format.md. Keep any Notes the user wrote.
  • brand/changelog.md: one new dated line.

6. Back-test and self-check

python3 scripts/scoring.py check icp/scoring.md
python3 scripts/scoring.py backtest icp/scoring.md <customers.csv>
python3 scripts/check_icp.py --scoring icp/scoring.md --audiences brand/audiences.md --analysis icp/analysis.json --sources <notes files> brand/proof.md icp/history/* --reply response.md

check validates the rubric in the list builder's grammar, the points and the tiers. backtest scores the customer file with the rubric: retained customers should sit higher than churned and lost ones; if not, adjust the weights. check_icp.py fails on untraced or small-sample percentages, market figures, quotes not found in a source, untagged audience bullets, evidence without counts, and internals in the reply. Fix every FAIL and rerun. For every CHECK line, trace the figure to the analysis row or note it came from, or delete it. Then answer the self-check questions in judgment.md. Skip --analysis and backtest when there's no CSV.

7. Reply

**ICP:** <written | updated to version N | provisional hypothesis | your version, with a recommendation | not written yet> (brand/audiences.md, icp/scoring.md)

**Recommendation:** one line: who to go after first, and the count behind it.

**What the data shows:** 3–5 bullets, each with its count. First bullet is the basis ("46 closed records; 3 open deals and 1 duplicate left out").

**Before you use it:** numbered: small samples, gaps, decisions for the user, data that would confirm it.

**Kept out:** one line on what was deliberately left out and why (market size without a source, quotes no one said). Omit if nothing.
  • Guided: the "ICP" line says not written yet; then the findings (mark each segment under 10 records "too few to be sure"), then the numbered decisions, each with your recommendation. Nothing else.
  • User-directed: acknowledge what's true in their view, give the counter-evidence in two or three lines with counts, say the rubric follows their call, recommend once.
  • Keep the reply under 300 words. The detail is in the files.
  • Say small samples in plain words: "only 6 records, too few to be sure", not just "hypothesis".
  • Don't explain how the rubric is built (point caps, labels, thresholds for evidence). Give the finding and what it means for who to call.
  • "Kept out" names only what the user asked for, or what the evidence held, that you left out. If nothing, drop the line.
  • Never mention the scripts, the analysis file, source-tag statuses, these references or any skill by name. Say "the rubric your list builder reads", not a tool's name. Talk to the user in the second person.

Keep tools out of the deliverable

Never name this skill, other skills, or their scripts and checks in a reply, report, draft or file the user may pass on: these often go to clients or the public. Describe what was checked, not the tool that checked it. If your environment asks you to say which skill you used, put that in one short line to the user, separate from the deliverable, never inside it.

What good looks like

A salesperson can read brand/audiences.md in two minutes and know who to call, who to skip and what that buyer cares about. Every number traces to a count in the data, every quote to a note, and every gap is a visible TBD. The rubric scores a list the same way twice, and scores the company's own best customers highest.

A worked example (Pipewise, a pipeline-review tool, from 28 deals) is in assets/examples/pipewise/.

How it was tested

Partly meets the Bench Standard bar. It beats no skill and the comparison skill on total on both models (Haiku 64/66 and Opus 65-66/66 vs 41/66 and 48/66 without and 35/66 for the comparison skill), is never worse on traps (with skill 35/35 trap expectations on both models in rounds 1 and 3; 34/35 for Haiku in round 2), and passes lint. The 'no invented facts' item is not fully met: final-round outputs still had small unsourced details (Haiku paraphrased a version 1 line inside quote marks and mislabelled two segment counts; Opus added three small unsupported asides). No invented market sizes, benchmarks, persona quotes from a customer, customer names or statistics were found in any with-skill output in any round.

9 evals (5 traps), expectations written before any run. Round 1 ran the skill, no skill, and the comparison skill (sales-icp from the 'sales' suite) on Haiku, and the skill and no skill on Opus, each in a fresh headless agent, graded blind by a separate headless Opus grader that read only evals.json and the fixtures and recomputed every count from the CSVs. Rounds 2 and 3 re-ran the skill as revised on Haiku and Opus and were graded blind the same way. The eval 7 fixture rubric was converted to the new hand-off format before round 3 (same criteria and points).

Expectations met per run
RunExpectations met
with skill, Opus (v1.2.0, round 3)66 / 66
with skill, Opus (v1.1.0, round 2)66 / 66
with skill, Opus (v1.0.0, round 1)65 / 66
no skill, Opus48 / 66
with skill, Haiku (v1.2.0, round 3)64 / 66
with skill, Haiku (v1.1.0, round 2)61 / 66
with skill, Haiku (v1.0.0, round 1)64 / 66
no skill, Haiku41 / 66
comparison skill (sales-icp), Haiku35 / 66

Traps

with skill, Haiku (rounds 1, 2, 3)
35/35, 34/35, 35/35 expectations across evals 2-6
with skill, Opus (rounds 1, 2, 3)
35/35, 35/35, 35/35
no skill, Haiku
26/35
no skill, Opus
25/35
comparison skill, Haiku
22/35

Where it fell short

  • Round 3, Haiku, eval 7: never stated the old single-location churn (4 of 11) next to the new 6 of 11, and its history line paraphrased the version 1 segment line inside quote marks ('with a moderate churn rate'), which the grader counted as an invented quote
  • Round 3, Haiku, eval 8: created brand/audiences.md without saying there was no brand memory or offering to set it up
  • Round 3, Haiku: mislabelled counts: '11 of 17 won' tagged as single-location general dentistry (11 of 17 is all single-location clinics; general dentistry alone is 11 of 14) in eval 4; specialty segments described as '2 to 5' and '1 or 2' records each (2 each) in evals 1 and 5; a churn reason cited to the win/loss notes when it is only in the CSV (eval 5)
  • Round 3, Opus: small unsupported asides: 'payroll requests usually surface on a call or in a job post' (eval 1); 'find this from the checkout or a Stripe badge' and suggestions to review 'your last 20 paying customers' when the user had no customer list (eval 2); a persona line attributing two PMS-calendar losses to single-location clinics when one was a 4-location group (eval 8)
  • Round 3, Haiku, eval 3: says 4 records are too few to pick a segment, but its provisional rubric still scores single restaurants twice (as type and as 1 location), leaning toward a winner
  • Round 2, Haiku (v1.1.0): left a 0-of-4 segment (20+ locations) able to outscore single-location clinics when there was no brand memory, didn't flag 2 blank verticals (eval 8); named no source for the churn benchmark (eval 5); didn't label small segments in Guided mode (eval 9). Fixed in 1.2.0; round 3 passed all four
  • Round 1 (v1.0.0), both models, eval 8: gave 20+ location groups negative points with no Disqualifiers section; Haiku eval 9 labelled small segments only as 'hypothesis'; mislabelled figures (a cross-tab row quoted as a whole band) and a few hand counts (Opus: 'spreadsheets 11 of 13', 'ChairTime 4 losses'). Fixed in 1.1.0
  • Every run leaves icp/analysis.json (the analysis dump, with absolute paths) in the user's project. No reply mentions it and it has no small-sample percentages, but it is clutter
  • Part of the comparison gap comes from the hand-off convention: six expectations require the rubric at icp/scoring.md, a path the prompts don't name. No-skill and comparison runs lose those even when their content is right; the grader flagged this as partly unfair to them
  • Comparisons, round 1: no-skill and comparison runs gave percentages on samples under 10 in evals 3, 4, 5, 7 and 8, overrode the user's tier choice (no-skill Opus, eval 4), overwrote the version 1 rubric (eval 7) and edited brand files they shouldn't have. The comparison skill invented persona quotes, cycle lengths, growth rates, competitors, events and dental-office counts 'from memory', and leaked its own name in every reply

From evals/scorecard.json for version 1.2.0, graded 2026-10-23. The evals and scorecard on GitHub →

This skill lives in ashleahwilson/ai-marketing-bench on GitHub, MIT licence.

All skills