marketing-mindset 1.6.1 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -0
- package/bin/cli.js +106 -3
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -82,3 +82,15 @@ npx -y marketing-mindset plan --base 0.03 --lift 0.2 --daily 500 --weeks 4
|
|
|
82
82
|
```
|
|
83
83
|
|
|
84
84
|
The floor from `sample`/`budget` laid out on a calendar: contacts per week, cumulative volume against the floor, the first date the test can honestly be read, the mechanics-only first week, and an honest verdict when the volume cannot reach the floor inside the plan. `--json` for agents. Work with me: https://axelfreeman.com/marketing-engineer.html
|
|
85
|
+
|
|
86
|
+
## `brief` — the plan as markdown you can send
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
npx marketing-mindset brief --base 0.03 --lift 0.2 --cpl 4 --daily 500 --start 2026-09-21
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
One page: the floor in contacts per arm and in total, what reaching it costs at your price per contact,
|
|
93
|
+
the dated read, a week-by-week table with the percentage of the floor covered, the three gates, and the
|
|
94
|
+
kill rule. `--json` returns the same object for an agent or a script.
|
|
95
|
+
|
|
96
|
+
Method, packages and the paid version of this work: https://axelfreeman.com/marketing-engineer.html
|
package/bin/cli.js
CHANGED
|
@@ -370,7 +370,7 @@ function runPlan(opts) {
|
|
|
370
370
|
(p2 * 100).toFixed(2) + "% (lift " + lift + "), " + daily + " contacts/day, " + weeks + " week(s)");
|
|
371
371
|
console.log("Floor: " + perArm + " per arm, " + need + " contacts in total. Weekly volume: " + daily * 7 + ".");
|
|
372
372
|
weekRows.forEach((w) => {
|
|
373
|
-
console.log(" Week " + w + " (" + w.start + " .. " + w.end + "): " + w.planned_contacts +
|
|
373
|
+
console.log(" Week " + w.week + " (" + w.start + " .. " + w.end + "): " + w.planned_contacts +
|
|
374
374
|
" contacts, cumulative " + w.cumulative + " (" + w.against_floor_pct + "% of the floor)");
|
|
375
375
|
});
|
|
376
376
|
console.log("First honest read: " + out.read_date + " (day " + daysToRead + ").");
|
|
@@ -380,6 +380,107 @@ function runPlan(opts) {
|
|
|
380
380
|
return 0;
|
|
381
381
|
}
|
|
382
382
|
|
|
383
|
+
|
|
384
|
+
/* brief — the whole plan as one markdown page a client can keep: the floor, what reaching it costs,
|
|
385
|
+
* the dates, the gate for each week and the kill rule. --json returns the same object for an agent. */
|
|
386
|
+
function fmtNum(n) {
|
|
387
|
+
return String(n).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
388
|
+
}
|
|
389
|
+
function addDays(iso, n) {
|
|
390
|
+
const d = new Date(iso + "T00:00:00Z");
|
|
391
|
+
d.setUTCDate(d.getUTCDate() + n);
|
|
392
|
+
return d.toISOString().slice(0, 10);
|
|
393
|
+
}
|
|
394
|
+
function runBrief(opts) {
|
|
395
|
+
const base = Number(opts.base === undefined ? 0 : opts.base);
|
|
396
|
+
const lift = Number(opts.lift === undefined ? 0 : opts.lift);
|
|
397
|
+
if (!isFinite(base) || base <= 0 || base >= 1) {
|
|
398
|
+
console.error("brief: --base must be a rate between 0 and 1 (got: " + JSON.stringify(opts.base) + ")");
|
|
399
|
+
return 1;
|
|
400
|
+
}
|
|
401
|
+
if (!isFinite(lift) || lift <= 0) {
|
|
402
|
+
console.error("brief: --lift must be a positive relative lift, e.g. 0.2 for +20%");
|
|
403
|
+
return 1;
|
|
404
|
+
}
|
|
405
|
+
const cpl = Number(opts.cpl === undefined ? 0 : opts.cpl);
|
|
406
|
+
if (!isFinite(cpl) || cpl <= 0) {
|
|
407
|
+
console.error("brief: --cpl must be a positive cost per contact (got: " + JSON.stringify(opts.cpl) + ")");
|
|
408
|
+
return 1;
|
|
409
|
+
}
|
|
410
|
+
const daily = Number(opts.daily === undefined ? 0 : opts.daily);
|
|
411
|
+
if (opts.daily !== undefined && (!isFinite(daily) || daily <= 0)) {
|
|
412
|
+
console.error("brief: --daily must be a positive number of contacts per day");
|
|
413
|
+
return 1;
|
|
414
|
+
}
|
|
415
|
+
const weeks = opts.weeks === undefined ? 4 : Number(opts.weeks);
|
|
416
|
+
if (!isFinite(weeks) || weeks < 1 || weeks > 52 || Math.floor(weeks) !== weeks) {
|
|
417
|
+
console.error("brief: --weeks must be a whole number between 1 and 52");
|
|
418
|
+
return 1;
|
|
419
|
+
}
|
|
420
|
+
const power = opts.power === undefined ? 0.8 : opts.power;
|
|
421
|
+
const alpha = opts.alpha === undefined ? 0.05 : opts.alpha;
|
|
422
|
+
const start = typeof opts.start === "string" && /^\d{4}-\d{2}-\d{2}$/.test(opts.start)
|
|
423
|
+
? opts.start : new Date().toISOString().slice(0, 10);
|
|
424
|
+
|
|
425
|
+
const perArm = sampleSize(base, lift, power, alpha);
|
|
426
|
+
const need = perArm * 2;
|
|
427
|
+
const cost = Math.round(need * cpl * 100) / 100;
|
|
428
|
+
const days = daily > 0 ? Math.ceil(need / daily) : null;
|
|
429
|
+
const readDate = days ? addDays(start, days - 1) : null;
|
|
430
|
+
const rows = [];
|
|
431
|
+
for (let w = 1; w <= weeks; w++) {
|
|
432
|
+
const planned = daily > 0 ? daily * 7 : 0;
|
|
433
|
+
const cumulative = planned * w;
|
|
434
|
+
rows.push({
|
|
435
|
+
week: w, start: addDays(start, (w - 1) * 7), end: addDays(start, w * 7 - 1),
|
|
436
|
+
planned_contacts: planned, cumulative,
|
|
437
|
+
against_floor_pct: Math.round(Math.min(100, (cumulative / need) * 100) * 10) / 10
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
const gates = [
|
|
441
|
+
"gate 1 (week 1): the tracked event fires on a real lead - if it does not, stop and fix the event, the channel stays closed",
|
|
442
|
+
"gate 2 (50% of floor): counts per arm look like the plan; if one arm is 30% behind, the split is broken, not the offer",
|
|
443
|
+
"gate 3 (read date): read the result at the declared floor or later, never earlier - below the floor the difference is noise"
|
|
444
|
+
];
|
|
445
|
+
const killRule = "kill if conversions are at or under the floor on the read date; double only when the target rate is hit at or above the floor";
|
|
446
|
+
const result = {
|
|
447
|
+
base_rate: base, target_rate: Math.round(base * (1 + lift) * 10000) / 10000, relative_lift: lift,
|
|
448
|
+
power, alpha, cost_per_contact: cpl, per_arm: perArm, contacts_needed: need,
|
|
449
|
+
cost_to_read_the_test: cost, daily_contacts: daily > 0 ? daily : null,
|
|
450
|
+
days_to_read: days, first_honest_read: readDate, start_date: start, weeks: rows,
|
|
451
|
+
gates, kill_rule: killRule,
|
|
452
|
+
offer: "https://axelfreeman.com/marketing-engineer.html",
|
|
453
|
+
method: "two-proportion floor; same formula as `marketing-mindset sample`"
|
|
454
|
+
};
|
|
455
|
+
if (opts.json) {
|
|
456
|
+
console.log(JSON.stringify(result, null, 2));
|
|
457
|
+
return 0;
|
|
458
|
+
}
|
|
459
|
+
const pct = (x) => (x * 100).toFixed(2);
|
|
460
|
+
console.log("# Campaign brief - the honest test plan\n");
|
|
461
|
+
console.log("Base rate " + pct(base) + "% -> target " + pct(base * (1 + lift)) + "% (relative lift +"
|
|
462
|
+
+ (lift * 100).toFixed(0) + "%), power " + power + ", alpha " + alpha);
|
|
463
|
+
console.log("Floor: " + fmtNum(perArm) + " contacts per arm | " + fmtNum(need) + " in total");
|
|
464
|
+
console.log("At $" + cpl + " per contact: $" + fmtNum(cost) + " to read the test");
|
|
465
|
+
if (days) {
|
|
466
|
+
console.log("At " + fmtNum(daily) + " contacts/day: " + days + " days -> first honest read " + readDate);
|
|
467
|
+
} else {
|
|
468
|
+
console.log("Daily volume not given: add --daily to date the read");
|
|
469
|
+
}
|
|
470
|
+
console.log("\n## Weeks");
|
|
471
|
+
console.log("| Week | Dates | Contacts | Cumulative | % of floor |");
|
|
472
|
+
console.log("| --- | --- | --- | --- | --- |");
|
|
473
|
+
rows.forEach((r) => console.log("| " + r.week + " | " + r.start + " .. " + r.end + " | " + fmtNum(r.planned_contacts)
|
|
474
|
+
+ " | " + fmtNum(r.cumulative) + " | " + r.against_floor_pct.toFixed(1) + "% |"));
|
|
475
|
+
console.log("\n## Gates");
|
|
476
|
+
gates.forEach((g) => console.log("- " + g));
|
|
477
|
+
console.log("\n## Kill rule");
|
|
478
|
+
console.log("- " + killRule);
|
|
479
|
+
console.log("\nMethod and packages: " + result.offer);
|
|
480
|
+
console.log("Tools: https://axelfreeman.github.io/marketing-mindset/tools/email-test-planner.html");
|
|
481
|
+
return 0;
|
|
482
|
+
}
|
|
483
|
+
|
|
383
484
|
const cmd = (process.argv[2] || "").toLowerCase();
|
|
384
485
|
const rest = process.argv.slice(3);
|
|
385
486
|
|
|
@@ -414,6 +515,8 @@ if (cmd === "sample") {
|
|
|
414
515
|
}, null, 2));
|
|
415
516
|
} else if (cmd === "aeo") {
|
|
416
517
|
process.exit(runAeo(flags(rest)));
|
|
518
|
+
} else if (cmd === "brief") {
|
|
519
|
+
process.exit(runBrief(flags(rest)));
|
|
417
520
|
} else if (cmd === "plan") {
|
|
418
521
|
process.exit(runPlan(flags(rest)));
|
|
419
522
|
} else if (cmd === "budget") {
|
|
@@ -444,12 +547,12 @@ Usage:
|
|
|
444
547
|
--base 0.03 --lift 0.2 --power 0.8 --alpha 0.05
|
|
445
548
|
npx marketing-mindset kill kill rule for a running test
|
|
446
549
|
--base 0.03 --n 1500 --lift 0.2
|
|
550
|
+
npx marketing-mindset brief the whole plan as markdown you can send to a client
|
|
551
|
+
--base 0.03 --lift 0.2 --cpl 4 --daily 500 [--weeks 4] [--start 2026-09-21] [--json]
|
|
447
552
|
npx marketing-mindset budget what an honest test costs before you can read it
|
|
448
553
|
--base 0.03 --lift 0.2 --cpl 4 [--daily 500]
|
|
449
554
|
npx marketing-mindset plan dated plan: weekly volume, gates, first honest read
|
|
450
555
|
--base 0.03 --lift 0.2 --daily 500 [--weeks 4] [--start 2026-09-21]
|
|
451
|
-
npx marketing-mindset plan dated plan: weekly volume, gates, first honest read
|
|
452
|
-
--base 0.03 --lift 0.2 --daily 500 [--weeks 4] [--start 2026-09-21]
|
|
453
556
|
npx marketing-mindset warmup day-by-day sending ramp with stop rules
|
|
454
557
|
--start 2026-09-21 --target 200 --days 21 --mailboxes 4
|
|
455
558
|
npx marketing-mindset jd marketing engineer job description
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "marketing-mindset",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "A marketer's operating mindset as an installable agent skill and CLI: test-size floors, kill rules, agent-readiness checklist, marketing-engineer job description. npx marketing-mindset sample|kill|budget|warmup|aeo|jd|sections|read|install.",
|
|
3
|
+
"version": "1.7.0",
|
|
4
|
+
"description": "A marketer's operating mindset as an installable agent skill and CLI: test-size floors, kill rules, agent-readiness checklist, marketing-engineer job description. npx marketing-mindset sample|kill|budget|brief|plan|warmup|aeo|jd|sections|read|install.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent-skill",
|
|
7
7
|
"skill",
|