skills/plan-campaign/SKILL.md
Plan an outreach campaign. Groups OK_TO_SEND demos (no campaign yet) into a named campaign with an offer text and deadline, creates the campaign in CRM, and links the selected opportunities to it. Run after /review-demos and before /setup-email-drafts. Optional parameter: track ('inbox' plans only Demo-Postfach/INBOX opportunities, 'chatbot' only chatbot ones).
npx skillsauth add psquared-development/psquared-skills plan-campaignInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
/plan-campaign [track] — optional. inbox → only opportunities with demoType: INBOX; chatbot → only demoType: CHATBOT or null (legacy). Omitted → both groups, planned as separate campaigns (see STEP 1).
Announce:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Campaign Planner started. Checking environment... ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Read .env using the Read tool (do NOT source it — values may contain semicolons or special characters that break shell parsing). Extract token values by reading the file content directly.
Required:
PSQUARED_CRM_TOKEN — for querying and updating CRM opportunities and creating campaignsIf the .env file is missing or the token is absent, stop immediately and ask the user to provide it.
Once verified, announce:
Environment OK. Finding unassigned demos...
Query CRM for InboxMate opportunities at SCREENING stage with demoStatus = OK_TO_SEND and no campaignId yet. Rules:
outreachType: { eq: INBOXMATE } — campaigns here are InboxMate-only. Services opportunities use their own flow (/find-services-leads handles the drafts directly). Museum opportunities (INBOX_MATE_MUSEUM) are excluded automatically by this filter and have their own future flow.noOutreach: { eq: false } — never touch opportunities flagged do-not-contact (e.g. Austrian companies, unsubscribed).company { outreachFor } and drop any opportunity whose company contains PERSONAL_ONLY. PERSONAL_ONLY companies are Martin's private contacts and must never be put into a campaign, even if someone manually created an opportunity on them.curl -s -X POST https://crm.psquared.dev/graphql \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $PSQUARED_CRM_TOKEN" \
-d "{\"query\":\"{ opportunities(first: 200, filter: { stage: { eq: SCREENING }, demoStatus: { eq: OK_TO_SEND }, campaignId: { is: NULL }, noOutreach: { eq: false }, outreachType: { eq: INBOXMATE } }) { edges { node { id outreachType demoType company { id name outreachFor } } } totalCount } }\"}"
After the response lands, filter out any edge where node.company.outreachFor contains PERSONAL_ONLY. Announce how many were dropped for that reason.
Campaigns are single-type. Group the remaining opportunities by demoType (null counts as CHATBOT). If both CHATBOT and INBOX demos are waiting, plan SEPARATE campaigns — never mix types in one campaign, because /setup-email-drafts routes the email template per campaign batch and the offer copy differs (chatbot deal vs "Inbox-Test starten"). Present both groups to the user and run STEP 2–4 once per group.
Announce:
Found [totalCount] demos ready for campaign assignment: 1. [Company A] 2. [Company B] ...
If none found, announce "No demos ready — run /review-demos first." and stop.
Present the list and ask the user to confirm:
Which opportunities to include — default is all of them. The user may exclude specific companies by name.
Campaign name — suggest the format Week [N] — [Month YYYY] based on today's date (e.g. "Week 14 — April 2026").
Offer text (offerText) — the value proposition shown on demo pages. Must be in German and time-limited in nature. Examples:
Offer deadline (offerExpiresAt) — suggest 14 days from today as ISO date (e.g. 2026-04-09T23:59:59.000Z).
Wait for the user's response before proceeding.
Once the user has confirmed all details, create the campaign:
curl -s -X POST https://crm.psquared.dev/graphql \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $PSQUARED_CRM_TOKEN" \
-d "{\"query\":\"mutation { createCampaign(data: { name: \\\"[name]\\\", offerText: \\\"[offerText]\\\", offerExpiresAt: \\\"[ISO date]\\\" }) { id name } }\"}"
Save the returned campaignId — you need it for the next step and the final report.
Announce:
Campaign "[name]" created (ID: [campaignId])
For each selected opportunity, update its campaignId. Do this sequentially — Twenty CRM does not support batch mutations reliably.
curl -s -X POST https://crm.psquared.dev/graphql \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $PSQUARED_CRM_TOKEN" \
-d "{\"query\":\"mutation { updateOpportunity(id: \\\"[oppId]\\\", data: { campaignId: \\\"[campaignId]\\\" }) { id } }\"}"
Announce after each:
Linked: [Company Name]
Announce:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Campaign planned. Campaign: [name] Deadline: [offerExpiresAt, human-readable] Offer: [offerText] Linked opportunities ([N]): - [Company A] - [Company B] ... Next step: /setup-email-drafts → Campaign ID: [campaignId] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
tools
Set up a personalized InboxMate INBOX demo (Demo-Postfach) for a sales prospect: a public, read-only seeded inbox showing 5-7 pre-triaged emails in their industry's language, with categories, routing and ready AI drafts. Use for email-automation outreach (the €49-349 product), NOT for chatbot outreach. No agent is created.
development
Build InboxMate demos AND write personalised outreach drafts in a single pass per company — eliminating the double-research that happens when /inboxmate-batch-demo and /setup-email-drafts run separately. Use when kicking off a new campaign where the campaign already exists (plan via /plan-campaign first). For each target company, dispatches ONE subagent that researches the site, builds the demo, creates the CRM opportunity, and drafts the outreach email — reusing the same research across all three. After all subagents return, runs a single batch call to auto-generate follow-ups.
testing
Autonomous pilot for the InboxMate EMAIL outreach (Demo-Postfach/INBOX track). Assesses where the inbox pipeline stands (leads → demos → review → campaign → drafts) and executes the next sensible step end-to-end, always finishing with the inbox sanity check and a summary of what the user should do next (ideally: just schedule the mails). Runs in save mode by default: orchestration + all quality gates on the top model, data collection on haiku subagents, content generation on sonnet subagents (pass 'full' to disable). Use when asked to 'advance the email outreach', 'run the inbox pipeline', or 'what's next for the Demo-Postfach motion'.
tools
Generate a polished psquared client offer as a multi-page PDF (title, project description, screenshots, Angebot/pricing, AGB). Walks the user through gathering inputs (or accepts a JSON config), renders branded HTML templates with Playwright in two passes (title page edge-to-edge + body pages with margins and pagination), then merges with pdf-lib.