All skills
01Prospecting
clay-alt-campaign-init
Scaffold a framework-anchored outbound campaign in one command.
Creates the campaign folder (config.yml, seed-leads.csv, routine-prompt.md) and registers the campaign in Supabase. Collects the required outbound fields upfront (offer outcome, timeframe, risk reversal, proof point, cold-read angle, goal) so the downstream copy generator has clean inputs on every lead.
- Batched intake captures every framework field at launch
- Generates the routine-ready config.yml + Supabase row in one step
- Validates outcome is a single number, not a range
Install
$ mkdir -p ~/.claude/skills/clay-alt-campaign-init && curl -sSL https://trueadvertize.com/skill-files/clay-alt-campaign-init/SKILL.md -o ~/.claude/skills/clay-alt-campaign-init/SKILL.md
Drops SKILL.md into ~/.claude/skills/clay-alt-campaign-init/. Reload Claude Code and the skill auto-activates on its triggers.
Source
SKILL.md
---
name: clay-alt-campaign-init
description: Scaffold a new Clay Alt Platform campaign by creating campaigns/<name>/ with config.yml, seed-leads.csv, and routine-prompt.md, then inserting a row into the Supabase campaigns table. Collects the required cold-outbound fields (offer_outcome, offer_timeframe, offer_risk_reversal, proof_point, cold_read_angle, sender_first_name, goal) up front so the downstream clay-alt-generate-copy skill has everything it needs to apply the 4-step framework on every lead. Use when launching a new outbound campaign.
allowed-tools: Read Write Bash AskUserQuestion
---
# clay-alt-campaign-init
One-step campaign scaffolder. Creates the file layout, registers the campaign in Supabase, and ensures the config carries every field the framework-anchored `clay-alt-generate-copy` skill expects when the routine runs.
Sibling skills: `email-copywriter` (interactive use of the framework), `clay-alt-generate-copy` (per-lead automation of the framework).
---
## When to use
- User says "create a new campaign", "scaffold campaign X", "start outbound for Y"
- You need a working `campaigns/<name>/` folder populated with the framework-shaped config
- You want the campaign registered in Supabase so the routine can find it
## When NOT to use
- Campaign folder already exists (this skill does not overwrite — caller should `rm -rf campaigns/<name>/` first or pick a new name)
- The platform schema is not applied yet (no `campaigns` table to insert into)
- The user can't yet articulate the framework intake answers (offer outcome, proof point, etc.) — go run the offer-design conversation first and come back
---
## Step 1: Intake interview (ALWAYS — never skip)
Ask all questions in ONE batched message using `AskUserQuestion` (or freeform text if more natural). Don't write a single file until every field below is locked. These map 1-to-1 onto what `clay-alt-generate-copy` needs to produce framework-compliant copy for every lead.
**Campaign identity:**
- `name` — slug, e.g. `energy-connector`, `saas-proc-leaders`. Validate `^[a-z0-9][a-z0-9-]*$`.
- `audience` — 1-sentence ICP description. E.g. "B2B SaaS founders 50 to 300 customers."
- `offer_summary` — 1-sentence description of what the campaign is selling. (Plain-English, separate from the structured offer fields below.)
**Framework required (locks the methodology):**
- `cold_read_angle` — the general pain or topic the cold-read opener references. Must apply to ~70% of the audience. E.g. "scaling outbound past founder-led sales", "SDRs not sticking", "agency retainer fatigue".
- `proof_point` — ONE specific named result with a specific number. Odd numbers feel real. E.g. "11.2% reply rate and 18 meetings in the first 60 days for a B2B SaaS founder, around $412k in pipeline." Avoid round numbers and aggregate vagueness.
- `offer_outcome` — single quantified outcome. NOT a range. E.g. "20 booked meetings", "$100k in pipeline", "10 paying customers". Rule: no ranges.
- `offer_timeframe` — specific time window. E.g. "60 days", "4 to 8 weeks".
- `offer_risk_reversal` — what protects the prospect. E.g. "or you don't pay a cent", "or I work for free until I deliver", "no charge until you see results".
- `sender_first_name` — first name only. Casual sign-off. Never "Best regards, Full Name, Title".
- `goal` — one of `reply` | `link_click` | `booked_call`. Drives CTA style.
**Framework optional (CTA shape, deliverability):**
- `cta_slots` — array of 2 specific time slots when `goal = booked_call`. E.g. `["3:30 p.m. today", "11 a.m. tomorrow"]`. If omitted, the per-lead skill picks reasonable defaults.
- `cta_phone` — phone number for the "I can give you a ring" variant.
- `meet_link_alternative` — `true` to offer "one-click Google Meet" as the friction-minimizer.
- `allow_emojis` — defaults `false`. The framework does not use emojis.
- `lowercase_subject` — defaults `true` (signals real person).
**Send-layer:**
- `route_to_instantly` — defaults `false`. Gate for the send step.
- `instantly_campaign_id` — required if `route_to_instantly=true`.
If the user cannot answer the framework required fields cleanly, STOP and run a quick offer-design conversation. Bad inputs here propagate to every lead in the campaign.
---
## Step 2: Validate
- Check `campaigns/<name>/` does NOT exist. If it does, exit 1 with a clear error.
- Validate `name` regex.
- Confirm `offer_outcome` is a single number/phrase, not a range. Reject `$10–20k`, accept `$20k`.
- Confirm `offer_timeframe` has a unit. Reject `soon`, accept `60 days`.
- Confirm `offer_risk_reversal` is concrete. Reject `satisfaction guaranteed`, accept `or you don't pay a cent`.
- Confirm `proof_point` has at least one specific number.
---
## Step 3: Create the files
Write under `campaigns/<name>/`:
### `config.yml` — framework-shaped schema
```yaml
name: <name>
audience: <audience>
offer_summary: <offer_summary>
# Framework (required)
cold_read_angle: <cold_read_angle>
proof_point: <proof_point>
offer_outcome: <offer_outcome>
offer_timeframe: <offer_timeframe>
offer_risk_reversal: <offer_risk_reversal>
sender_first_name: <sender_first_name>
goal: <goal> # reply | link_click | booked_call
# Framework (optional, defaults shown)
cta_slots: [] # ["3:30 p.m. today", "11 a.m. tomorrow"] when goal=booked_call
cta_phone: null
meet_link_alternative: false
allow_emojis: false
lowercase_subject: true
# Send-layer gate
route_to_instantly: false
instantly_campaign_id: null
# Copy template (framework-shaped slot names; legacy hook_line/value_prop still work)
template:
subject: "{{ subject_line }}"
body: |
Hey {{ first_name }},
{{ personalization }}
{{ who_am_i }}
{{ offer }}
{{ cta }}
Thanks,
{{ sender_first_name }}
```
### `seed-leads.csv`
Header row only:
```csv
domain,company,first_name,last_name,title,email_hint
```
### `routine-prompt.md`
Copy from `campaigns/reference/routine-prompt.md`, substitute `{{ campaign_name }}` tokens with the new name. The reference prompt already knows to load `config.yml` and pass the framework fields into the `clay-alt-generate-copy` invocation, so no extra wiring needed.
---
## Step 4: Insert into Supabase
Source `platform/lib/supabase.sh`. Call:
```bash
sb_insert campaigns "$(jq -n \
--arg name "$NAME" \
--argjson cfg "$CONFIG_JSON" \
'{name:$name, config:$cfg, active:true}')"
```
where `CONFIG_JSON` is the parsed YAML-to-JSON of the newly-written `config.yml` (so all framework fields land in the `config` JSONB column).
---
## Step 5: Emit the result
```json
{"campaign_id":"<uuid>","path":"campaigns/<name>","framework_ready":true}
```
The `framework_ready` boolean confirms all required fields were captured. If `false`, the routine will fall back to legacy `hook_line`/`value_prop` slots and produce less-effective copy.
---
## Outputs
- Files written under `campaigns/<name>/`:
- `config.yml` — framework-shaped campaign parameters
- `seed-leads.csv` — empty template with header row
- `routine-prompt.md` — the Claude Routine prompt customized for this campaign
- One row inserted into Supabase `campaigns` table
- Final stdout: `{"campaign_id":"uuid","path":"campaigns/<name>","framework_ready":true|false}`
---
## Example intake → output
User says: "scaffold a new campaign called `saas-founders-q3` targeting B2B SaaS founders, we're pitching the 4-week GTM build."
After intake:
```yaml
name: saas-founders-q3
audience: B2B SaaS founders, 50 to 300 customers
offer_summary: Custom 4-week GTM system build with 30-day money-back guarantee
cold_read_angle: scaling outbound past founder-led sales
proof_point: 11.2% reply rate and 18 meetings in the first 60 days for a B2B SaaS founder, around $412k in pipeline
offer_outcome: a full GTM system build (Clay enrichment, ICP sequences, SOPs, dashboard)
offer_timeframe: 4 to 8 weeks
offer_risk_reversal: 30-day money-back, you keep what's been built
sender_first_name: Sam
goal: booked_call
cta_slots:
- "3:30 p.m. today"
- "11 a.m. tomorrow"
meet_link_alternative: true
```
---
## Gotchas
- **YAML → JSON conversion** for the `config` column: use `yq -o json` if installed, else a one-off Python call (`python -c "import yaml,json,sys; print(json.dumps(yaml.safe_load(sys.stdin)))" < config.yml`).
- **Supabase `name` is UNIQUE** — a duplicate name will 409. Catch and report as "campaign already registered" with an ID lookup.
- **Don't generate the framework fields yourself** if the user can't answer them. Bad guesses propagate to every lead. Stop and have the conversation first.
- **Numbers in `proof_point` must be defensible.** If the user says "tons of pipeline", refuse and ask for a specific number. Vague proof = dead copy at the per-lead step.
- **`offer_outcome` ranges silently sabotage the campaign.** `clay-alt-generate-copy` will reject "10 to 20 meetings" but accept "20 meetings". Catch the range here at intake, not 500 leads later.
---
## Anti-patterns
- **Don't skip the intake.** A campaign scaffolded without the framework fields produces generic AI-shaped copy that gets 1-2% reply rates instead of the 8-12% the framework targets.
- **Don't write a "TBD" placeholder for a framework required field.** Stop and get the real answer.
- **Don't seed-lead the CSV here.** This skill writes the empty header only. Lead sourcing happens via `build-tam` / `portfolio-prospecting` / `linkedin-url-lookup` after scaffolding.
- **Don't enable `route_to_instantly` on the first run.** v1 should be a dry-run: scaffold, enrich, generate copy, inspect 20 leads manually, THEN flip the send gate.
---
## Source
Same cold-outbound framework the sibling `email-copywriter` and `clay-alt-generate-copy` skills are built against. Campaign initialization is the upstream step that ensures the framework has clean inputs to compose with on every lead.
Trigger phrases
Claude Code auto-activates this skill when prompts contain phrases like:
create a new campaignscaffold campaign [name]start outbound for [niche]new outbound campaign