Skip to content
Back to skills

07 Campaign Sheet

ASecurity

Turn a terminal records.jsonl into an owner-readable campaign sheet plus a HubSpot-import-shaped CSV - the chain's exit door. Use when a run is ready to hand to an owner: "build the campaign sheet", "export these for HubSpot", "who do I contact first", or as the final step of run-first-campaign. Reads whatever stage produced the records (qualified, signal-ranked, or fully resolved) and degrades gracefully on missing fields - no email column until 06 has run. Nothing sends and nothing downstre...

  • 26 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added August 31, 2026
ai-agentspythongobashapi

Works with

  • terminal
  • cli
  • api
  • mcp

Security analysis

A100/100

Pro scans all 3 files and shows the line behind each finding

Scanned August 31, 2026

npx -y skills add Zevenue/headless-gtm --skill 07-campaign-sheet --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 07 Campaign Sheet?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 07 Campaign Sheet
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/zevenue-07-campaign-sheet/badge)](https://www.skillsdirectory.com/skills/zevenue-07-campaign-sheet)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: 07-campaign-sheet
description: >-
  Turn a terminal records.jsonl into an owner-readable campaign sheet plus a
  HubSpot-import-shaped CSV - the chain's exit door. Use when a run is ready to
  hand to an owner: "build the campaign sheet", "export these for HubSpot", "who
  do I contact first", or as the final step of run-first-campaign. Reads
  whatever stage produced the records (qualified, signal-ranked, or fully
  resolved) and degrades gracefully on missing fields - no email column until 06
  has run. Nothing sends and nothing downstream reads its output: the sheet and
  CSV are the human deliverable, approved on screen. To add verified emails
  first, run 06-resolution-email-person; to rank, 05-signal-builder.
---

# Campaign sheet (07)

The last step in the chain. Everything upstream produced `records.jsonl`; this
turns those records into what an owner actually uses - a ranked "who to contact
first and why" sheet, plus a CSV shaped for a one-click HubSpot import.

It **adds no fields to the chain and nothing reads its output.** The CSV is a
derived, human-facing export (`headless-gtm-shared/CONVENTIONS.md`) - the
canonical record stays `records.jsonl`, and re-running any upstream skill never
depends on this sheet.

## What it reads

A terminal `records.jsonl` from any stage. The script tolerates every shape and
degrades instead of failing:

- **Company name** from `company` (or `name`), **site** from `website` (or
  `https://` + `domain`), **phone / city** from wherever the discovery step put
  them.
- **Ranking** from 05's `signals[]` - the highest-score signal per record
  decides call order; its `signal_type`, `signal_sentence`, and `source_url`
  become the "why now" line, and its `approach` (or `fallback_approach`) the
  recommended angle. Records with no signals stay in the sheet, ranked last.
- **Contacts** from 06's `person_name` / `matched_title` / `email` /
  `verification_status`. When 06 has not run, the contact columns are dropped
  entirely rather than shipped empty.
- Rows with no website ride through on their listing fields - the sheet does not
  drop them (a registry row with `domain` empty is still a real target).

## What it writes

`runs/<run-id>/` (via `common.runs_base()`, step prefix `07`):

- **`campaign-sheet.md`** - owner-readable. Ranked cards for the top targets
  (company, city, why now with source, approach, contact or "not resolved"),
  then a compact table for the rest, then a "before you send" note.
- **`campaign-sheet.csv`** - HubSpot default contact-import headers: `First
  Name, Last Name, Email, Company Name, Website URL, Phone Number, Lifecycle
  Stage, Notes`. Every row is set to **Lifecycle Stage = Lead**; `Notes` carries
  the top signal and the recommended approach. First/Last/Email appear only when
  at least one record is resolved, and a `Listing URL` column appears only when
  at least one record carries one (directory-sourced runs) - so a phone-only
  registry row still exports a working link. The headers are HubSpot's defaults
  because it is the most common import target; every field is a plain column, so
  any other CRM (Salesforce, Pipedrive, Attio) takes the same file after a
  one-time header remap on import.

## Run it

```bash
python3 scripts/campaign_sheet.py --records ./runs/<run-id>/records.jsonl --title "HVAC - Ontario"
```

Stdlib only - no API keys, no network. It runs on a synthetic fixture with zero
accounts, so it is safe to demo before any real data exists.

## The approval step (must hold)

Present both files on screen. **Nothing is send-ready until the owner approves
the sheet there.** Nothing in this repo sends email - if asked to "just send
it", say so plainly and point at the approved sheet and the drafted sequence.
The import, and any send, is the owner's step after approval.

## Optional: stage into HubSpot (only when a connector is present)

The default path is the CSV import - the owner uploads `campaign-sheet.csv` in
HubSpot and maps the columns (all default properties, so mapping is automatic).

If a HubSpot MCP or connector is available in the session, offer an alternative:
stage the approved rows directly as contacts with `lifecyclestage = lead`.
Before any write, confirm the batch size and get an explicit go-ahead, then
stage in batches and report what was created. Never create or modify HubSpot
records without that on-screen approval, and never stage rows the owner has not
approved on the sheet. If no connector is present, do not ask for one - the CSV
is the complete path.

## Output

End with a one-paragraph recap: rows written, how many carry a resolved contact,
the top 3 targets with their one-line reason, and the paths to the two files.

Files in this skill

  • README.md2.3 KB
  • SKILL.md4.6 KB
  • scripts/campaign_sheet.py12.7 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.