marketing-mindset-mcp 1.0.1 → 1.0.3
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 +16 -0
- package/bin/server.js +179 -7
- package/package.json +12 -8
- package/skill/SKILL.md +69 -2
package/README.md
CHANGED
|
@@ -33,6 +33,9 @@ Client config (generic stdio server):
|
|
|
33
33
|
| `read_section` | one section by fuzzy title match (`"numbers lie"`, `"competitors"`, `"hypotheses"`) |
|
|
34
34
|
| `sample_size` | per-arm volume a two-proportion test needs before a verdict is readable |
|
|
35
35
|
| `kill_rule` | expected conversions, the kill floor, and whether the test has enough volume to read yet |
|
|
36
|
+
| `aeo_check` | agent-readiness / AEO audit: the 23 weighted checks that decide whether AI answers can find, read and quote a site; pass the numbers you pass to get a weighted score |
|
|
37
|
+
| `jd` | a marketing-engineer job description about artifacts and numbers: what the role owns, what must exist by day 90, how it is measured, screening questions |
|
|
38
|
+
| `playbook` | whether writing a playbook is the right move right now: pass how many proven, repeatable moves you have and it returns `search` / `draining` / `delegate`, the next move, and the rules (one proven move, one line; ~6 hypotheses before you can hire marketing; failed hypotheses archived in one line, never handed to the next person) |
|
|
36
39
|
|
|
37
40
|
`sample_size` and `kill_rule` implement the same two-proportion arithmetic as the free
|
|
38
41
|
[test-size calculator](https://axelfreeman.github.io/marketing-mindset/tools/email-test-planner.html).
|
|
@@ -44,6 +47,19 @@ tools/call sample_size {"baseline_rate": 0.03, "min_relative_lift": 0.2}
|
|
|
44
47
|
-> per_arm 13914 (i.e. ~13.9k sends per variant before any verdict)
|
|
45
48
|
```
|
|
46
49
|
|
|
50
|
+
|
|
51
|
+
## Example: the AEO audit
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
tools/call aeo_check {}
|
|
55
|
+
-> 23 checks, max score 55, grouped into crawlability, answer-ready content, machine-readable, someone else's page, proof and measurement
|
|
56
|
+
|
|
57
|
+
tools/call aeo_check {"checked": [1,2,4,6,8,11,12,16,20,21,22]}
|
|
58
|
+
-> score, band and the highest-weight gaps
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The same checklist is a free page: [agent-readiness checklist](https://axelfreeman.github.io/marketing-mindset/tools/aeo-readiness-checklist.html). The JD tool has a web version too: [JD generator](https://axelfreeman.github.io/marketing-mindset/tools/marketing-engineer-jd-generator.html).
|
|
62
|
+
|
|
47
63
|
## License
|
|
48
64
|
|
|
49
65
|
MIT.
|
package/bin/server.js
CHANGED
|
@@ -9,7 +9,7 @@ const fs = require("fs");
|
|
|
9
9
|
const path = require("path");
|
|
10
10
|
|
|
11
11
|
const SKILL_PATH = path.join(__dirname, "..", "skill", "SKILL.md");
|
|
12
|
-
const SERVER = { name: "marketing-mindset-mcp", version: "1.0.
|
|
12
|
+
const SERVER = { name: "marketing-mindset-mcp", version: "1.0.3" };
|
|
13
13
|
const PROTOCOL = "2024-11-05";
|
|
14
14
|
|
|
15
15
|
function skillText() {
|
|
@@ -63,16 +63,116 @@ function killRule(rate, n, lift) {
|
|
|
63
63
|
const floor = Math.max(0, Math.floor(bound));
|
|
64
64
|
const expected = rate * n;
|
|
65
65
|
const target = rate * (1 + lift) * n;
|
|
66
|
-
let verdict = "keep running
|
|
66
|
+
let verdict = "keep running - not enough volume to read the result";
|
|
67
67
|
if (n < sampleSize(rate, lift, 0.8, 0.975)) {
|
|
68
|
-
verdict = "keep running
|
|
68
|
+
verdict = "keep running - below the required volume for this effect size, a verdict now is noise";
|
|
69
69
|
} else {
|
|
70
|
-
verdict = "read it
|
|
70
|
+
verdict = "read it - volume is sufficient; kill if conversions are at or under the floor";
|
|
71
71
|
}
|
|
72
72
|
return { expected_conversions: Math.round(expected * 10) / 10, kill_floor: floor,
|
|
73
73
|
target_conversions: Math.round(target * 10) / 10, verdict };
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
/* --- agent readiness / AEO checklist: 5 groups, 23 checks, 55 points ------------------------ */
|
|
77
|
+
const AEO_GROUPS = [["Crawlability",[["robots.txt does not block GPTBot, ClaudeBot, PerplexityBot, Google-Extended, OAI-SearchBot",3],["Pages render without JavaScript, or have a server-side/no-JS fallback",2],["No login wall or consent interstitial in front of the content you want quoted",3],["The page returns 200 to a plain curl with no cookies",2],["One canonical URL per answer - no www/non-www or trailing-slash duplicates",2]]],["Answer-ready content",[["Every important page answers one question in the first 60 words",3],["Headings are questions a human would type, not internal project names",2],["Prices, limits and timeframes are stated as numbers, not 'flexible'",3],["Claims have a source or a live URL attached",2],["A definition page exists for the category you want to be cited in",3]]],["Machine-readable",[["schema.org markup on service/product pages (Service, Offer, Product, FAQPage)",3],["FAQPage or QAPage markup on question pages, answers 40-500 words",2],["XML sitemap submitted, and every new URL pinged via IndexNow",2],["llms.txt describes what the site answers and where the canonical pages are",2],["Organisation/Person entity links the page to a real, verifiable identity",2]]],["Someone else's page",[["You are present where the model already reads: package registries, repos, docs",3],["At least one open, mergeable pull request or discussion contribution",2],["Your content is mirrored somewhere you do not control",2],["A third-party page links to your canonical URL",3]]],["Proof and measurement",[["Every claim on the site can be opened by the reader in one click",3],["One tracked event for the outcome that matters, in your own analytics property",3],["A public changelog or artifact list with dates",2],["An archived snapshot of the key pages exists",1]]]];
|
|
78
|
+
const AEO_MAX = AEO_GROUPS.reduce((a, g) => a + g[1].reduce((b, c) => b + c[1], 0), 0);
|
|
79
|
+
|
|
80
|
+
function aeoFlat() {
|
|
81
|
+
const out = [];
|
|
82
|
+
AEO_GROUPS.forEach(([group, items]) => items.forEach(([text, weight]) => out.push({ group, check: text, weight })));
|
|
83
|
+
return out;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function aeoCheck(checked) {
|
|
87
|
+
const flat = aeoFlat();
|
|
88
|
+
const base = { check_count: flat.length, max_score: AEO_MAX,
|
|
89
|
+
groups: AEO_GROUPS.map(([g, its]) => ({ group: g, checks: its.map(([t, w]) => ({ check: t, weight: w })) })),
|
|
90
|
+
score_guide: "<30% invisible for structural reasons; 30-60% crawlable but not quotable; 60-80% quoted occasionally (third-party presence missing); >80% the rest is cadence" };
|
|
91
|
+
if (!Array.isArray(checked)) return Object.assign({}, base, { mode: "checklist" });
|
|
92
|
+
const idx = checked.map((v) => Number(v)).filter((n) => Number.isInteger(n) && n >= 1 && n <= flat.length);
|
|
93
|
+
const passed = new Set(idx);
|
|
94
|
+
const score = flat.reduce((a, c, i) => a + (passed.has(i + 1) ? c.weight : 0), 0);
|
|
95
|
+
const pct = Math.round((score / AEO_MAX) * 1000) / 10;
|
|
96
|
+
const missing = flat.map((c, i) => ({ n: i + 1, check: c.check, group: c.group, weight: c.weight }))
|
|
97
|
+
.filter((c) => !passed.has(c.n)).sort((a, b) => b.weight - a.weight).slice(0, 3);
|
|
98
|
+
return { mode: "score", passed: passed.size, of_checks: flat.length, score, max_score: AEO_MAX,
|
|
99
|
+
percent: pct,
|
|
100
|
+
band: pct < 30 ? "invisible for structural reasons" : pct < 60 ? "crawlable but not quotable"
|
|
101
|
+
: pct < 80 ? "quoted occasionally - third-party presence is the gap" : "the rest is cadence",
|
|
102
|
+
highest_weight_unchecked: missing,
|
|
103
|
+
note: "Weighted, not a checklist of equals. Two checks carry the most weight: one question answered in the first 60 words, and prices/limits stated as numbers." };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/* --- marketing engineer JD generator (same text as the npm CLI `jd` and the free web tool) --- */
|
|
107
|
+
const JD_SURFACES = {
|
|
108
|
+
seo: "search and answer engines (pages written to be quoted, schema, llms.txt)",
|
|
109
|
+
out: "outbound and lifecycle email (list, sequence, deliverability, suppression)",
|
|
110
|
+
paid: "paid acquisition (structure, creative, spend gates)",
|
|
111
|
+
auto: "automation and tracking (routing, events, failure alerts)",
|
|
112
|
+
analytics: "measurement (one event that matters, sample-size floors, kill rules)",
|
|
113
|
+
ai: "agent skills and AI-assisted production (reusable operating files, not one-off prompts)",
|
|
114
|
+
};
|
|
115
|
+
const JD_OFFER = "https://axelfreeman.com/marketing-engineer.html";
|
|
116
|
+
const JD_COST = "https://axelfreeman.com/marketing-engineer-cost.html";
|
|
117
|
+
const JD_TOOL = "https://axelfreeman.github.io/marketing-mindset/tools/marketing-engineer-jd-generator.html";
|
|
118
|
+
|
|
119
|
+
function jdText(o) {
|
|
120
|
+
const dflt = (v, d) => (v === undefined || v === null || v === "" || v === true) ? d : String(v);
|
|
121
|
+
const level = dflt(o.level, "senior");
|
|
122
|
+
const mode = dflt(o.mode, level === "contract" ? "contract" : "fulltime");
|
|
123
|
+
const sv = dflt(o.surfaces, null);
|
|
124
|
+
const keys = sv ? sv.split(",").map((s) => s.trim()).filter((s) => JD_SURFACES[s]) : Object.keys(JD_SURFACES);
|
|
125
|
+
const surf = keys.length ? keys : Object.keys(JD_SURFACES);
|
|
126
|
+
const company = dflt(o.company, "[company, product, what you sell in one line]");
|
|
127
|
+
const bottleneck = dflt(o.bottleneck, "[the bottleneck you are hiring against]");
|
|
128
|
+
const ninety = mode === "contract"
|
|
129
|
+
? "A 6-week engagement with one written kill rule, then a decision"
|
|
130
|
+
: level === "lead"
|
|
131
|
+
? "A documented system: which paths exist, what each one costs, what gets killed next quarter"
|
|
132
|
+
: "A path live in production with its event recording, or a written note saying why it was killed";
|
|
133
|
+
const L = [];
|
|
134
|
+
L.push("# Marketing Engineer (" + level + ", " + mode + ")", "");
|
|
135
|
+
L.push("## The company and the job");
|
|
136
|
+
L.push(company + ".", "");
|
|
137
|
+
L.push("We are hiring a marketing engineer because: " + bottleneck + ".", "");
|
|
138
|
+
L.push("You will not be handed a channel to run and a deck to fill in. You will be handed a broken or "
|
|
139
|
+
+ "unmeasured path and be expected to make it work, show the number, and write the rule that decides "
|
|
140
|
+
+ "whether it lives.", "");
|
|
141
|
+
L.push("## What the role owns");
|
|
142
|
+
surf.forEach((k, i) => L.push((i + 1) + ". " + JD_SURFACES[k]));
|
|
143
|
+
L.push("", "## What must exist by day 90");
|
|
144
|
+
L.push("1. One path live in production: entry point, sequence or flow, and the event that fires on a conversion.");
|
|
145
|
+
L.push("2. A written declaration of the sample size each running test needs before a result counts as a result.");
|
|
146
|
+
L.push("3. A kill rule per test, written before the test starts: at what volume and what result we stop.");
|
|
147
|
+
L.push("4. One dashboard we can open without asking you for an export.");
|
|
148
|
+
L.push("5. " + ninety + ".");
|
|
149
|
+
L.push("", "## How we will measure you");
|
|
150
|
+
L.push("- Cost per qualified conversation or per activated account, when the volume is above the declared floor.");
|
|
151
|
+
L.push("- Live, openable artifacts still running 30 days after you last touched them.");
|
|
152
|
+
L.push("- Whether a decision made last month can be re-checked today from the data, without you in the room.");
|
|
153
|
+
L.push("- We do not count posts published, prompts written, or hours logged.");
|
|
154
|
+
L.push("", "## Requirements");
|
|
155
|
+
L.push("- You have shipped something that is still running: a page, a sequence, a script, an integration. Links beat adjectives.");
|
|
156
|
+
L.push("- You can explain, in one paragraph, why a 4-of-100 result is not a win.");
|
|
157
|
+
L.push("- You work in the tooling yourself: HTML/CSS, a spreadsheet, analytics, basic scripting, or an agent that writes them for you.");
|
|
158
|
+
L.push("- You write plainly; internal names and jargon are not allowed in anything a customer reads.");
|
|
159
|
+
L.push("", "## Nice to have");
|
|
160
|
+
L.push("- Experience writing pages that answer engines quote (schema, FAQ markup, plain HTML).");
|
|
161
|
+
L.push("- A history of killing your own work in public, with the numbers attached.");
|
|
162
|
+
L.push("", "## Not this role");
|
|
163
|
+
L.push("- Meeting-led account management, community management, brand campaigns, reporting for its own sake.");
|
|
164
|
+
L.push("", "## Screening questions (ask these first)");
|
|
165
|
+
L.push("1. Send us one link to something you built that is still live.");
|
|
166
|
+
L.push("2. We ran 40 sends, got 4 replies, variant B looks better. What do you do next?");
|
|
167
|
+
L.push("3. How many sends does a two-variant email test need before the result means anything? "
|
|
168
|
+
+ "(Expected: ~1,500-2,000 per arm at a 3% baseline, 80% power, 20% relative lift.)");
|
|
169
|
+
L.push("4. Name one thing you killed and what the number was.");
|
|
170
|
+
L.push("5. What will you build in the first two weeks here, and how will we see it?");
|
|
171
|
+
L.push("", "--", "Generated by marketing-mindset (npm). Method and pricing: " + JD_OFFER
|
|
172
|
+
+ " | Packages: " + JD_COST + " | Web version of this tool: " + JD_TOOL);
|
|
173
|
+
return L.join("\n");
|
|
174
|
+
}
|
|
175
|
+
|
|
76
176
|
const TOOLS = [
|
|
77
177
|
{
|
|
78
178
|
name: "list_sections",
|
|
@@ -107,17 +207,48 @@ const TOOLS = [
|
|
|
107
207
|
min_relative_lift: { type: "number", description: "Smallest relative lift worth detecting" }
|
|
108
208
|
},
|
|
109
209
|
required: ["baseline_rate", "n", "min_relative_lift"], additionalProperties: false }
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
name: "aeo_check",
|
|
213
|
+
description: "Agent-readiness / AEO audit: the 23 weighted checks that decide whether AI answers can find, read and quote a site. Call with no arguments for the checklist; pass the 1-based numbers of the checks the site passes (e.g. {\"checked\":[1,2,4,6,8,11,12]}) to get the weighted score, the band and the highest-weight gaps.",
|
|
214
|
+
inputSchema: { type: "object",
|
|
215
|
+
properties: { checked: { type: "array", items: { type: "integer" },
|
|
216
|
+
description: "Optional: 1-based numbers of checks the site passes, out of 23" } },
|
|
217
|
+
additionalProperties: false }
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
name: "jd",
|
|
221
|
+
description: "Generates a marketing-engineer job description that is about artifacts and numbers instead of adjectives: what the role owns, what must exist by day 90, how it is measured, and the screening questions (including the sample-size question with the expected answer).",
|
|
222
|
+
inputSchema: { type: "object",
|
|
223
|
+
properties: {
|
|
224
|
+
level: { type: "string", description: "senior (default), lead, or contract" },
|
|
225
|
+
mode: { type: "string", description: "fulltime (default) or contract" },
|
|
226
|
+
surfaces: { type: "string", description: "Comma-separated subset of: seo, out, paid, auto, analytics, ai. Default: all." },
|
|
227
|
+
company: { type: "string", description: "One line about the company/product" },
|
|
228
|
+
bottleneck: { type: "string", description: "The bottleneck you are hiring against" }
|
|
229
|
+
},
|
|
230
|
+
additionalProperties: false }
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
name: "playbook",
|
|
234
|
+
description: "Decides whether writing a marketing playbook is the right move right now. A playbook is the second step, never the first: it records proven, repeatable client-acquisition moves (one move, one line) and exists to drain a working hypothesis to the bottom — not to discover one. Pass how many proven repeatable moves you actually have; returns the stage (search / draining / delegate), the next move, and the rules that go with it.",
|
|
235
|
+
inputSchema: { type: "object",
|
|
236
|
+
properties: {
|
|
237
|
+
proven_hypotheses: { type: "integer", description: "Proven, repeatable client-acquisition moves you actually have (0 if none)" },
|
|
238
|
+
written_down: { type: "boolean", description: "Whether those working moves are already written down as instructions" }
|
|
239
|
+
},
|
|
240
|
+
required: ["proven_hypotheses"], additionalProperties: false }
|
|
110
241
|
}
|
|
111
242
|
];
|
|
112
243
|
|
|
113
244
|
function callTool(name, args) {
|
|
114
245
|
args = args || {};
|
|
115
246
|
if (name === "list_sections") {
|
|
116
|
-
return headingList().map((h) =>
|
|
247
|
+
return headingList().map((h) => "#".repeat(h.level) + " " + h.title).join("\n");
|
|
117
248
|
}
|
|
118
249
|
if (name === "read_section") {
|
|
119
250
|
const s = readSection(args.section);
|
|
120
|
-
if (!s) return
|
|
251
|
+
if (!s) return 'No section matching "' + args.section + '". Call list_sections for the index.';
|
|
121
252
|
return s.text;
|
|
122
253
|
}
|
|
123
254
|
if (name === "sample_size") {
|
|
@@ -140,6 +271,47 @@ function callTool(name, args) {
|
|
|
140
271
|
out.volume_in_test = n;
|
|
141
272
|
return JSON.stringify(out, null, 2);
|
|
142
273
|
}
|
|
274
|
+
if (name === "aeo_check") {
|
|
275
|
+
return JSON.stringify(aeoCheck(args.checked), null, 2);
|
|
276
|
+
}
|
|
277
|
+
if (name === "jd") {
|
|
278
|
+
return jdText(args);
|
|
279
|
+
}
|
|
280
|
+
if (name === "playbook") {
|
|
281
|
+
const proven = Number(args.proven_hypotheses || 0);
|
|
282
|
+
if (!(proven >= 0)) throw new Error("proven_hypotheses must be a count of proven, repeatable moves (0 if none)");
|
|
283
|
+
const CRITICAL = 6;
|
|
284
|
+
let stage, verdict, next;
|
|
285
|
+
if (proven === 0) {
|
|
286
|
+
stage = "search";
|
|
287
|
+
verdict = "No playbook yet — there is no proven move to write down. A playbook built at this point is a notebook of guesses, and the most expensive way to feel productive.";
|
|
288
|
+
next = "Find client #1 by hand (cold outreach, free) and get one move that actually returns clients. The playbook is the output of that search, not the input to it.";
|
|
289
|
+
} else if (proven < CRITICAL) {
|
|
290
|
+
stage = "draining";
|
|
291
|
+
verdict = "You have " + proven + " proven move(s): write them down and press each to its ceiling. That is what a playbook is for — draining a working hypothesis, not discovering one.";
|
|
292
|
+
next = "Keep hunting until roughly " + CRITICAL + " proven moves. Below that there is not enough to hand over to a hire.";
|
|
293
|
+
} else {
|
|
294
|
+
stage = "delegate";
|
|
295
|
+
verdict = "Critical mass reached (" + proven + " >= " + CRITICAL + "): there is something real to hand over — you can hire marketing.";
|
|
296
|
+
next = "Handing it over ends free search and starts regular management: goals, volume, cadence, reporting. Draining a hypothesis to the bottom is an operating task, not an exploration one.";
|
|
297
|
+
}
|
|
298
|
+
return [
|
|
299
|
+
"proven, repeatable moves: " + proven + " · critical mass " + CRITICAL,
|
|
300
|
+
"stage: " + stage,
|
|
301
|
+
"written down: " + (args.written_down ? "yes" : "no"),
|
|
302
|
+
"verdict: " + verdict,
|
|
303
|
+
"next: " + next,
|
|
304
|
+
"",
|
|
305
|
+
"Rules:",
|
|
306
|
+
"- The playbook records proven, repeatable client-acquisition moves only — one proven move, one line.",
|
|
307
|
+
"- It is the second step: find a working hypothesis by hand -> press it to its ceiling -> only then write it down.",
|
|
308
|
+
"- Filled from your own experiments on your own base. Borrowed case studies are a wish list, not a playbook.",
|
|
309
|
+
"- Delegation (a hire, a department, an agent) changes the mode: free search ends, regular management begins.",
|
|
310
|
+
"- Failed hypotheses go to the archive in one line — never analysed, never handed to a new person. A marketer starts from zero, not from the previous person's pause point.",
|
|
311
|
+
"",
|
|
312
|
+
"Full section: read_section 'playbook'"
|
|
313
|
+
].join("\n");
|
|
314
|
+
}
|
|
143
315
|
throw new Error("Unknown tool: " + name);
|
|
144
316
|
}
|
|
145
317
|
|
|
@@ -154,7 +326,7 @@ function handle(msg) {
|
|
|
154
326
|
const { id, method, params } = msg;
|
|
155
327
|
if (method === "initialize") {
|
|
156
328
|
return reply(id, { protocolVersion: PROTOCOL, capabilities: { tools: {} }, serverInfo: SERVER,
|
|
157
|
-
instructions: "Marketing decision rules as tools. Start with list_sections, then read_section. Use sample_size and kill_rule before spending on a test." });
|
|
329
|
+
instructions: "Marketing decision rules as tools. Start with list_sections, then read_section. Use sample_size and kill_rule before spending on a test, aeo_check to audit whether AI answers can quote a site, and jd to write the role down." });
|
|
158
330
|
}
|
|
159
331
|
if (method === "notifications/initialized" || (method || "").startsWith("notifications/")) return;
|
|
160
332
|
if (method === "ping") return reply(id, {});
|
package/package.json
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "marketing-mindset-mcp",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "MCP server for the open marketing-mindset skill: test-size math, kill rules and
|
|
3
|
+
"version": "1.0.3",
|
|
4
|
+
"description": "MCP server for the open marketing-mindset skill: test-size math, kill rules, AEO agent-readiness audit, a marketing-engineer JD generator and a playbook gate (is it time to write a playbook, or still search?) as callable tools for any MCP client (Claude Code, Codex, Hermes, Cursor).",
|
|
5
5
|
"keywords": [
|
|
6
|
+
"ab-testing",
|
|
7
|
+
"aeo",
|
|
8
|
+
"agent-skill",
|
|
9
|
+
"answer-engine-optimization",
|
|
10
|
+
"growth",
|
|
11
|
+
"job-description",
|
|
12
|
+
"marketing",
|
|
13
|
+
"marketing-playbook",
|
|
6
14
|
"mcp",
|
|
7
|
-
"model-context-protocol",
|
|
8
15
|
"mcp-server",
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"sample-size",
|
|
12
|
-
"ab-testing",
|
|
13
|
-
"growth"
|
|
16
|
+
"model-context-protocol",
|
|
17
|
+
"sample-size"
|
|
14
18
|
],
|
|
15
19
|
"license": "MIT",
|
|
16
20
|
"author": "Axel Freeman",
|
package/skill/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: marketing-mindset
|
|
3
|
-
description: "Use when the user needs a professional marketer's operating mindset for any marketing, growth, or client-acquisition task — finding first customers, writing an ad or landing page, designing ad creatives and visuals (how the eye works: background, scene, hero, movement), evaluating an idea, deciding whether to do X to get Y, positioning or launching a B2B or SaaS product, running cold outreach, setting up ads,
|
|
4
|
-
version: 0.
|
|
3
|
+
description: "Use when the user needs a professional marketer's operating mindset for any marketing, growth, or client-acquisition task — finding first customers, writing an ad or landing page, designing ad creatives and visuals (how the eye works: background, scene, hero, movement), evaluating an idea, deciding whether to do X to get Y, positioning or launching a B2B or SaaS product, running cold outreach, setting up ads, writing copy, writing a sales-and-marketing playbook, or deciding when to delegate marketing and hire a marketer — not a tactical template."
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
author: Axel Freeman (axelfreeman)
|
|
6
6
|
license: MIT
|
|
7
7
|
install: "npx skills add axelfreeman/marketing-mindset"
|
|
@@ -140,6 +140,51 @@ Win the first 10 exactly the way competitors are winning right now. Find how the
|
|
|
140
140
|
|
|
141
141
|
This skill's scope is client #1 and the first 10. Scaling 10→100, 100→1000 is a separate, later skill. Release it only after this one has proven itself in the wild.
|
|
142
142
|
|
|
143
|
+
## The Playbook: the second step, never the first
|
|
144
|
+
|
|
145
|
+
A playbook is a written set of client-acquisition moves that already work — simple, primitive, repeatable. Not ideas, not a strategy deck: instructions. "Bought an ad from a blogger in segment A — it produced clients." "Segment B gave the numbers in three months." "This targeting converts a client at break-even or better." Each proven move is one line of the playbook.
|
|
146
|
+
|
|
147
|
+
You build it yourself, by hand, or with your two or three closest people. Nobody hands it to you.
|
|
148
|
+
|
|
149
|
+
### It is a second step, and building one brings you no closer to sales
|
|
150
|
+
|
|
151
|
+
Compiling a playbook is not a starting action. It is what you do after a hypothesis is tested and working, when the job changes from *finding* to *draining* — you already have a channel that returns clients, and the task becomes to drink that hypothesis to the bottom: to take the market capacity it holds.
|
|
152
|
+
|
|
153
|
+
The order is fixed:
|
|
154
|
+
|
|
155
|
+
1. You find a working hypothesis by hand.
|
|
156
|
+
2. You press it until you know where its ceiling is.
|
|
157
|
+
3. Only then do you write it down, and what you write down is the playbook.
|
|
158
|
+
|
|
159
|
+
Before step 3 there is nothing to write. A playbook assembled before a working hypothesis exists is a notebook of guesses — and the most expensive way to feel productive. Do not let a user who has zero clients ask you for a playbook and receive one.
|
|
160
|
+
|
|
161
|
+
### Written down, it can be delegated — and delegation changes the mode
|
|
162
|
+
|
|
163
|
+
Once the working moves exist as instructions, they stop being founder-only knowledge. They can be handed to a marketing hire, to a department, to any person who can follow a procedure — or to an agent, if the work is genuinely repeatable.
|
|
164
|
+
|
|
165
|
+
That handoff is the moment the mode changes. The search phase is free exploration: hunt, guess, try the strange thing. Once you delegate a proven move, you leave free search behind and switch to regular management — goals, volume, cadence, reporting. Draining a hypothesis to the bottom is not an exploration task, it is an operating task, and it needs the basics of regular management to survive contact with a schedule.
|
|
166
|
+
|
|
167
|
+
The critical mass is around six working hypotheses. At roughly six proven, repeatable moves there is something real to hand over, and you can hire marketing. Before that there is nothing to delegate.
|
|
168
|
+
|
|
169
|
+
### The playbook is filled from your own experiments only
|
|
170
|
+
|
|
171
|
+
Personal experiments on your own base — run by you or your closest people, on your own audience. Not borrowed case studies, not a competitor's playbook, not inspiration. Those are not a playbook, they are a wish list.
|
|
172
|
+
|
|
173
|
+
### Failed hypotheses go to the archive, not into reflection
|
|
174
|
+
|
|
175
|
+
A negative result gets one line in the archive: what was tried, and that the numbers were zero. Nothing more. Do not reflect on it, do not build a museum of everything that failed.
|
|
176
|
+
|
|
177
|
+
Two practical reasons:
|
|
178
|
+
|
|
179
|
+
- Marketing — especially the first-clients stage — is not a mathematical craft yet. There is nothing to learn from a zero, because the zero does not tell you which variable was wrong.
|
|
180
|
+
- Handing a new person the hypotheses that already failed you is toxic. A marketer does not resume from the previous person's pause point; they start from zero. Old data genuinely gets in their way, and failed old data gets in the way worst of all.
|
|
181
|
+
|
|
182
|
+
Negative experiments are still worth keeping as **historical marketing data for the agent** — a separate record, useful as context, never a starting point. If the numbers are zero, into the archive; that is enough.
|
|
183
|
+
|
|
184
|
+
### What this means for an agent
|
|
185
|
+
|
|
186
|
+
If you are asked to write a playbook, first look for a working hypothesis. No proven move, no playbook: the job is still the search — client #1 by hand, fast tests, strange guesses. Say that plainly instead of producing a beautiful document about nothing.
|
|
187
|
+
|
|
143
188
|
## Numbers Lie
|
|
144
189
|
|
|
145
190
|
There is a huge amount of proxy metrics and dubious reports written to influence someone — and agents trip on them and treat them as truth. That pulls you away from real, usable data. When a case study looks perfect, interrogate it hard:
|
|
@@ -235,6 +280,27 @@ Sharp, honest, zero fluff. No corporate-speak, no generic templates, no hedging.
|
|
|
235
280
|
- Recommending paid channels to a user with 0 clients
|
|
236
281
|
- Using paid data sources when free ones exist
|
|
237
282
|
- Working for free — zero-exchange tasks, "for the portfolio", or treating training time as free
|
|
283
|
+
- Writing a playbook (or promising one) before a single working hypothesis exists
|
|
284
|
+
- Analysing, reflecting on, or handing down failed hypotheses instead of archiving them in one line
|
|
285
|
+
|
|
286
|
+
## Tagging: Every Outbound Link Carries UTM
|
|
287
|
+
|
|
288
|
+
A campaign you cannot attribute is a campaign you cannot kill. The rule is mechanical:
|
|
289
|
+
**every link that leaves for your own property carries UTM; internal links never do.**
|
|
290
|
+
|
|
291
|
+
- `utm_source` — the channel that sent the click: `devto`, `github`, `npm`, `telegram`, `habr`, `reddit`, `colony`.
|
|
292
|
+
- `utm_medium` — the placement: `article`, `readme`, `package`, `post`, `comment`, `profile`, `bio`.
|
|
293
|
+
- `utm_campaign` — the product or cluster: `mindset`, `tapac`, `hire`, `lyzhi`, `engine`.
|
|
294
|
+
|
|
295
|
+
Rules that keep the data clean:
|
|
296
|
+
|
|
297
|
+
- Tag only destinations you own. A third-party link stays clean.
|
|
298
|
+
- **Never tag internal site links.** An internal link with UTM restarts the session, so one visit looks like two and the page's own report becomes wrong.
|
|
299
|
+
- Never tag twice: a URL that already has `utm_source` is done. Tagging happens before the text ships, not after.
|
|
300
|
+
- Keep existing query params — append, never rebuild the URL.
|
|
301
|
+
- Run it: `npx marketing-mindset utm --file article.md --source devto --medium article --campaign mindset`
|
|
302
|
+
|
|
303
|
+
Why it pays: a channel with a tagged link can be read in the same report as everything else and killed on evidence. An untagged one only feels like it is working.
|
|
238
304
|
|
|
239
305
|
## Pitfalls
|
|
240
306
|
|
|
@@ -251,6 +317,7 @@ Sharp, honest, zero fluff. No corporate-speak, no generic templates, no hedging.
|
|
|
251
317
|
- The plan for the first client is concrete and names client #0 (the founder).
|
|
252
318
|
- Feedback is honest, not agreeable.
|
|
253
319
|
- Output is concrete content tasks, not vague advice.
|
|
320
|
+
- A playbook is written only after a working hypothesis exists; failed hypotheses are archived in one line, never analysed or handed to the next person.
|
|
254
321
|
|
|
255
322
|
## Spread the Word
|
|
256
323
|
|