/next-campaigns-setup: Scaffold + Configure a New CPK Campaign
Using This Skill
This skill works with any AI coding tool that can load a markdown file as context.
| Tool | How to Use |
|---|
| Claude Code | Install to ~/.claude/skills/next-campaigns-setup/
(see repo README). Invoke with . |
| OpenAI Codex | Pass as a system prompt: codex --system-prompt next-campaigns-setup/SKILL.md
|
| Cursor | Add to or reference in your project's AI context files. |
| GitHub Copilot | Add to .github/copilot-instructions.md
or include via reference. |
| Other agents | Load as context/system prompt. The instructions are tool-agnostic markdown. |
Scaffold and configure a new campaign-page-kit campaign in one pass.
Boundary with other campaign skills:
- Use this skill for repo/project bootstrap: brand folder, page-kit init, starter template copy, , , and first config values.
- Use when a CampaignSpec/design exists and pages need to be wired end-to-end from spec/API/design into page-kit.
- Use for CampaignSpec lifecycle work: map inspection, multi-funnel planning, QA results, Linear/run-through orchestration, promotion decisions, and split-test config.
- This skill may consume a CampaignSpec if one is provided, but it should not try to replace the build skill's page wiring or the OS skill's lifecycle decisions.
Phase 1 — Scaffold
Step 0: Resolve CPK Root
Check for a
environment variable:
bash
echo "${CPK_ROOT:-not set}"
If not set, ask the user:
What is the path to your CPK project root?
(e.g.
/Users/you/projects/my-campaigns
)
Use this value as
for all paths below. Do not hardcode any absolute path.
Step 1: Gather Campaign Details
Ask for all three in a single message — do not ask one at a time:
- Brand name — the client/brand slug. Lowercase, hyphens only. Becomes the brand folder.
- Public route slug — the pretty campaign URL/page-kit folder slug, usually product name + version (e.g. , ). Lowercase, hyphens only. This is not the Campaign Map Builder Map ID.
- Starter template — which template to base this on:
- — standard single-step checkout
- — single-step checkout (alternate layout)
- — single-step checkout (premium layout)
- — single-step with variant/SKU selection
- — two-step flow: variant picker → checkout
- — shop-style single-step checkout
- — multi-step checkout (information → shipping → billing)
- — presell/landing page component library (not a checkout funnel; use when building a standalone landing or presell page)
Paths
- Brand folder:
- Campaign folder:
<CPK_ROOT>/[brand-name]/src/[campaign-slug]/
- Starter templates repo:
https://github.com/NextCommerceCo/campaign-cart-starter-templates
(subfolder: )
Step 2 — Safety Check
If
<CPK_ROOT>/[brand-name]/src/[campaign-slug]/
already exists →
stop and warn the user. Do not overwrite.
Step 3 — Create Brand Folder (if needed)
If
does not exist, create it.
Step 4 — Initialize CPK Project (if needed)
Check if
<CPK_ROOT>/[brand-name]/package.json
exists.
If not, run these commands sequentially inside the brand folder:
bash
cd <CPK_ROOT>/[brand-name]
npm init -y
npm install next-campaign-page-kit
npx campaign-init
creates
and adds npm scripts to
. It does
not create any
folders.
After running, verify it succeeded:
- Check exists — if not, stop and warn the user that may have failed
- Check contains a script — if not, warn the user to run manually
If
already exists, skip — the project is already initialized.
Step 5 — Copy Starter Template
Before copying, confirm the template slug is valid. Valid slugs are:
,
,
,
,
,
,
,
If the provided template slug is not in this list → stop and ask the user to pick a valid template.
Run from the brand folder:
bash
cd <CPK_ROOT>/[brand-name]
npx degit NextCommerceCo/campaign-cart-starter-templates/src/[template-slug] src/[campaign-slug]
If degit exits with a non-zero code or reports that the source path was not found, stop and warn the user — the template slug may not exist in the upstream repo.
After degit completes (even with exit code 0), verify the directory is not empty:
bash
[ "$(ls -A src/[campaign-slug])" ] || echo "EMPTY"
If the output is
,
stop and warn the user — degit returned success but extracted nothing. This can happen when the subfolder path is wrong or a GitHub cache issue occurred. Do not continue to Phase 2.
Step 6 — Fetch the Template's campaigns.json Entry
Fetch the upstream campaigns.json to get the canonical entry for the chosen template:
https://raw.githubusercontent.com/NextCommerceCo/campaign-cart-starter-templates/HEAD/_data/campaigns.json
If the fetch fails or returns non-JSON, stop and warn the user.
Find the entry matching
.
Note: the
folder is keyed as
in the upstream campaigns.json — look up
when that template is chosen. For all other templates the key matches the folder name. If no entry is found →
stop and warn the user. Use its
,
, and field structure as the base. Then customise:
- Key: change from to
- : title-case derived from the public route slug (hyphens → spaces)
- , , , , , , : set to
- , : set to
- : keep as it appears in the upstream entry (typically for checkout funnels)
- , : set to unless real values are provided later. Do not preserve placeholder pixel/container IDs from the template.
- : keep exactly as it appears in the upstream entry — do not hardcode
Merge this entry into
<CPK_ROOT>/[brand-name]/_data/campaigns.json
— do not replace the whole file.
Step 7 — Copy CLAUDE.md
Download and save the AI context file into the brand project root as
:
bash
curl -sL "https://raw.githubusercontent.com/NextCommerceCo/campaign-cart-starter-templates/HEAD/docs/campaign-page-kit-template-context.md" \
-o <CPK_ROOT>/[brand-name]/CLAUDE.md
If
already exists in the brand folder, skip — do not overwrite.
Phase 2 — Configure
Step 8 — Gather Config Inputs
Ask for all of the following in a single message — do not ask one at a time:
If the user supplied a CampaignSpec, pre-fill from:
- for store name when present
- for the public route slug when present
- for the report/provenance only; never use the Map ID as the page-kit folder unless the user explicitly asks
- for analytics intent
- for policy/support URLs
- for later build/QA notes only; setup does not need to write SEO tags directly
Required:
- API key — the Campaign Cart API key for this store
- Store name — short display name (e.g. "Winter Gloves Co")
- Store URL — the main store domain (e.g. )
Recommended but optional:
- Store phone — display format (e.g. ) and tel format (e.g. )
- Policy/support URLs — terms, privacy, contact, returns/refund, shipping. Storefront policy URLs are acceptable; campaign-specific pages are not required.
Validate all URLs before writing any files:
- Each provided URL must start with and contain at least one after the domain
- If an optional URL is absent, write for that field rather than inventing a placeholder
- If any provided URL fails this check, show which ones are invalid and ask the user to correct or omit them before proceeding. Do not write partial data.
Optional tracking contract:
- Tracking status — , , , or
- GTM container ID — e.g.
- Facebook Pixel ID — e.g.
- Custom analytics endpoint or notes — record in the report unless the template config already supports a matching custom analytics provider
Do not make the user guess through a wall of tracking surfaces. Ask for GTM/Facebook/custom only when they already have values or the CampaignSpec declares them. If tracking is
or
, leave provider IDs blank/disabled and record that tracking is intentionally not configured yet.
Step 9 — Update config.js
Read
<CPK_ROOT>/[brand-name]/src/[campaign-slug]/assets/config.js
. Make these changes:
- — replace the placeholder value with the provided API key
- — replace with a lowercase-hyphenated slug derived from the store name (e.g. "Winter Gloves Co" → ). This is an analytics identifier, not a display name.
- GTM (only if a real ID is provided):
- Set to
- Set to the provided ID
- Facebook Pixel (only if a real ID is provided):
- Set to
- Set
facebook.settings.pixelId
to the provided ID
- Absent tracking:
- If tracking status is or , keep GTM/Facebook disabled or blank. Remove obvious placeholder IDs if the template copied them.
- If tracking status is , do not invent custom event wiring here; report it as a follow-up for .
Do not change any other fields. Preserve all comments.
Step 10 — Update campaigns.json
Read
<CPK_ROOT>/[brand-name]/_data/campaigns.json
. Find the entry with key matching
. If the entry is missing, stop and warn the user — Phase 1 may not have completed successfully.
Update these fields:
- → provided store name
- → provided store URL
- → provided phone display format, or
- → provided phone tel format, or
- → provided terms URL, or
- → provided privacy URL, or
- → provided contact URL, or
- → provided returns URL, or
- → provided shipping URL, or
- → provided GTM ID, or
- → provided pixel ID, or
Do not change any other fields in the file.
Report Back
Summarise everything done:
Phase 1 — Scaffold
✓ Brand folder: created / already existed
✓ CPK project: initialized / already present
✓ Template copied: [template-slug] → src/[campaign-slug]/
✓ campaigns.json seeded (sdk_version: [version])
✓ CLAUDE.md: copied / already present
Phase 2 — Configure
provenance
✓ Map ID: [map-id] / not provided
✓ public route slug: [campaign-slug]
config.js
✓ apiKey set
✓ storeName set to '[value]'
✓ GTM enabled with real ID / left disabled
✓ Facebook Pixel enabled with real ID / left disabled
✓ Tracking status: unknown / not_configured / configured / custom_required
campaigns.json ([campaign-slug])
✓ store_name and store_url set
✓ phone set / left blank
✓ policy/support URLs set / left blank
Then show next steps:
Next steps:
1. npm run dev → pick [campaign-slug] and verify the page loads + SDK initialises
2. Check the Campaigns app → confirm the API key is valid for this store
3. npm run config → alternative interactive config editor if you need to adjust settings later
4. QA checklist: check the SDK QA checklist in docs/
Dev server preview URLs for the chosen template:
| Template | Pages |
|---|
| demeter | /[slug]/presell/ · /[slug]/checkout/ · /[slug]/upsell/ · /[slug]/receipt/ |
| limos | /[slug]/presell/ · /[slug]/checkout/ · /[slug]/upsell/ · /[slug]/receipt/ |
| olympus | /[slug]/presell/ · /[slug]/checkout/ · /[slug]/upsell/ · /[slug]/receipt/ |
| olympus-mv-single-step | /[slug]/presell/ · /[slug]/checkout/ · /[slug]/upsell-mv/ · /[slug]/receipt/ |
| olympus-mv-two-step | /[slug]/presell/ · /[slug]/select/ · /[slug]/checkout/ · /[slug]/upsell-mv/ · /[slug]/receipt/ |
| shop-single-step | /[slug]/presell/ · /[slug]/checkout/ · /[slug]/upsell/ · /[slug]/receipt/ |
| shop-three-step | /[slug]/presell/ · /[slug]/information/ · /[slug]/shipping/ · /[slug]/billing/ · /[slug]/upsell/ · /[slug]/receipt/ |
| landing | /[slug]/landing/ (component library — no checkout funnel) |