@antoneeo/mkt-agentic-sdlc-skill 0.2.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/CHANGELOG.md +18 -0
- package/README.md +45 -0
- package/gemini-extension.json +6 -0
- package/package.json +45 -0
- package/scripts/init.js +146 -0
- package/scripts/lib.js +170 -0
- package/scripts/postinstall.js +42 -0
- package/scripts/preuninstall.js +17 -0
- package/skills/mkt-agentic-sdlc/ENFORCEMENT.md +82 -0
- package/skills/mkt-agentic-sdlc/SKILL.md +201 -0
- package/skills/mkt-agentic-sdlc/elicitation.md +89 -0
- package/skills/mkt-agentic-sdlc/frameworks.md +105 -0
- package/skills/mkt-agentic-sdlc/research.md +104 -0
- package/skills/mkt-agentic-sdlc/review.md +73 -0
- package/skills/mkt-agentic-sdlc/scripts/mkt_check.py +567 -0
- package/skills/mkt-agentic-sdlc/templates.md +444 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.2.0 — 2026-07-09 (v1.0 hardening)
|
|
4
|
+
|
|
5
|
+
- **Deterministic doctrine gate**: `scripts/test_skill_invariants.py` asserts the load-bearing invariants (three guarantees, review red-flags R1/R11b/R15, elicitation rules, research URL rule, parseable template tokens, sales-led funnel guidance, support-file wiring). Fails on a real regression.
|
|
6
|
+
- **Opt-in behavioral eval layer**: `evals/run_behavioral.py` (zero-LLM driver) + 6 scenarios (triage/escalation, owned-facts elicitation, no-number-without-ledger, swap-test enforced, low-cost-trap flagged, no-guaranteed-success). Mirrors the sibling skill.
|
|
7
|
+
- **Contrast validation (B2B sales-led)**: second synthetic eval on a business unlike the first — the Vision Alignment / amendment discipline caught and held a deliberate vision-divergence (self-serve tier) instead of absorbing it.
|
|
8
|
+
- **Calibration from the contrast run**: sales-led/B2B funnel guidance (funnel output = qualified demos not closed customers; separate pipeline build-up table; closed-won lag) in `frameworks.md` + `templates.md`; B2B firmographic-ICP + buying-committee variant in `templates.md`.
|
|
9
|
+
- ENFORCEMENT.md §5/§6 updated to run both deterministic batteries + the behavioral layer.
|
|
10
|
+
|
|
11
|
+
## 0.1.0 — 2026-07-09
|
|
12
|
+
|
|
13
|
+
Initial release.
|
|
14
|
+
|
|
15
|
+
- Operating contract `SKILL.md`: Marketing Values, Rule Zero engagement triage (E1/E2/E3/Spike), dual operating modes (Standalone `mkt_docs/`, Hybrid devPNT), E3 nine-phase SOSTAC workflow with user gates, adversarial review gates and mechanical validation.
|
|
16
|
+
- Support files: `frameworks.md` (framework selection guide), `elicitation.md` (question waves, only-facts-you-own rule), `research.md` (research playbook + evidence ledger discipline), `templates.md` (all artifact templates), `review.md` (CMO review discipline + marketing red flags), `ENFORCEMENT.md`.
|
|
17
|
+
- Mechanical validator `scripts/mkt_check.py`: `check`, `validate`, `ledger`, `budget`, `funnel`, `trace`, `index`.
|
|
18
|
+
- npm packaging: `mkt-sdlc-init` (project scaffold), `mkt-sdlc-install-skill` (multi-client skill install: Claude Code, Gemini CLI, Codex, Google Antigravity).
|
package/README.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Marketing Agentic SDLC Skill
|
|
2
|
+
|
|
3
|
+
Evidence-First marketing planning protocol for AI coding agents (Claude Code, Gemini CLI, Google Antigravity, Codex). The sibling of [`@antoneeo/agentic-sdlc-skill`](https://www.npmjs.com/package/@antoneeo/agentic-sdlc-skill), transplanted from software engineering to marketing strategy.
|
|
4
|
+
|
|
5
|
+
## What it does
|
|
6
|
+
|
|
7
|
+
Turns an AI agent into a disciplined marketing strategist that produces a professional, professionally-recognized marketing plan (SOSTAC structure) with three engineered guarantees:
|
|
8
|
+
|
|
9
|
+
1. **Evidence ledger** — every market number is classified FACT / BENCHMARK / ASSUMPTION and carries an `[EV-nn]` reference to its source. No invented numbers.
|
|
10
|
+
2. **Mechanical validator** (`mkt_check.py`) — budget sums, funnel math and the objective→tactic→KPI chain are checked mechanically, not rhetorically.
|
|
11
|
+
3. **Adversarial CMO review** — an independent, fresh-context reviewer attacks the strategy before the user sees it (generic-positioning swap test, untraced claims, orphan tactics).
|
|
12
|
+
|
|
13
|
+
The agent asks the user only for facts the user uniquely owns (product, price, budget, capacity); everything else — market sizing, competitor analysis, channel benchmarks — is derived from real web research.
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm i -g @antoneeo/mkt-agentic-sdlc-skill
|
|
19
|
+
mkt-sdlc-install-skill # copies the skill into every detected AI client
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Initialize a project:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
cd my-business-project
|
|
26
|
+
npx mkt-sdlc-init # creates mkt_docs/ + protocol pointers
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Engagement levels (Rule Zero)
|
|
30
|
+
|
|
31
|
+
| Level | Scope | Process |
|
|
32
|
+
|---|---|---|
|
|
33
|
+
| E1 Quick | single question / asset feedback | direct answer, sourced numbers |
|
|
34
|
+
| E2 Campaign | one campaign or channel plan | mini-brief + targeted research + campaign doc |
|
|
35
|
+
| E3 Full Plan | complete marketing plan | full SOSTAC workflow, 9 phases, all gates |
|
|
36
|
+
| Research Spike | time-boxed market question | `mkt_docs/spikes/RESEARCH_[topic].md` |
|
|
37
|
+
|
|
38
|
+
## Modes
|
|
39
|
+
|
|
40
|
+
- **Standalone** — everything on the filesystem under `mkt_docs/`.
|
|
41
|
+
- **Hybrid with devPNT** — plans and strategy artifacts governed as versioned devPNT documents (MKT-VISION, ICP/Personas, Threat Map, Strategy, Tactical Plan, Measurement Plan), with proposal/approval workflow and independent review gates.
|
|
42
|
+
|
|
43
|
+
## License
|
|
44
|
+
|
|
45
|
+
MIT — Antonio Pinto
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@antoneeo/mkt-agentic-sdlc-skill",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Evidence-First marketing planning protocol for Claude Code, Gemini CLI, Google Antigravity and Codex: engagement triage, SOSTAC workflow, evidence ledger, mechanical validator and optional devPNT integration.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"claude-code",
|
|
7
|
+
"claude-skill",
|
|
8
|
+
"gemini-cli",
|
|
9
|
+
"skill",
|
|
10
|
+
"marketing",
|
|
11
|
+
"marketing-plan",
|
|
12
|
+
"sostac",
|
|
13
|
+
"ai-agent"
|
|
14
|
+
],
|
|
15
|
+
"author": "Antonio Pinto (https://github.com/Antoneeo)",
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"access": "public"
|
|
19
|
+
},
|
|
20
|
+
"bin": {
|
|
21
|
+
"mkt-sdlc-init": "scripts/init.js",
|
|
22
|
+
"mkt-sdlc-install-skill": "scripts/postinstall.js"
|
|
23
|
+
},
|
|
24
|
+
"scripts": {
|
|
25
|
+
"postinstall": "node scripts/postinstall.js",
|
|
26
|
+
"preuninstall": "node scripts/preuninstall.js"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"skills/mkt-agentic-sdlc/SKILL.md",
|
|
30
|
+
"skills/mkt-agentic-sdlc/frameworks.md",
|
|
31
|
+
"skills/mkt-agentic-sdlc/elicitation.md",
|
|
32
|
+
"skills/mkt-agentic-sdlc/research.md",
|
|
33
|
+
"skills/mkt-agentic-sdlc/templates.md",
|
|
34
|
+
"skills/mkt-agentic-sdlc/review.md",
|
|
35
|
+
"skills/mkt-agentic-sdlc/ENFORCEMENT.md",
|
|
36
|
+
"skills/mkt-agentic-sdlc/scripts/mkt_check.py",
|
|
37
|
+
"gemini-extension.json",
|
|
38
|
+
"README.md",
|
|
39
|
+
"CHANGELOG.md",
|
|
40
|
+
"scripts/lib.js",
|
|
41
|
+
"scripts/init.js",
|
|
42
|
+
"scripts/postinstall.js",
|
|
43
|
+
"scripts/preuninstall.js"
|
|
44
|
+
]
|
|
45
|
+
}
|
package/scripts/init.js
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { execSync } = require('child_process');
|
|
6
|
+
const { SKILL_SOURCE, CLIENTS, clientDetected, loadTemplates, templateFor } = require('./lib');
|
|
7
|
+
|
|
8
|
+
const cwd = process.cwd();
|
|
9
|
+
|
|
10
|
+
// 1. Directory layout (canonical mkt_docs structure)
|
|
11
|
+
const directories = [
|
|
12
|
+
'mkt_docs',
|
|
13
|
+
'mkt_docs/vision',
|
|
14
|
+
'mkt_docs/research',
|
|
15
|
+
'mkt_docs/strategy',
|
|
16
|
+
'mkt_docs/tactics',
|
|
17
|
+
'mkt_docs/deliverables',
|
|
18
|
+
'mkt_docs/audit',
|
|
19
|
+
'mkt_docs/spikes',
|
|
20
|
+
].map((d) => path.join(cwd, d));
|
|
21
|
+
|
|
22
|
+
// 2. Project protocol (thin pointer — the operating contract is the skill).
|
|
23
|
+
// Deliberately short: duplicating the skill's rules here made them drift.
|
|
24
|
+
const protocolContent = `# Marketing Agentic SDLC — Project Protocol (pointer)
|
|
25
|
+
|
|
26
|
+
This project follows the Marketing Agentic SDLC Evidence-First process. The full
|
|
27
|
+
operating contract is the \`mkt-agentic-sdlc\` skill (installed in your agent's
|
|
28
|
+
skills directory); this file is only the minimal always-on pointer.
|
|
29
|
+
|
|
30
|
+
## Rule Zero — Triage every request
|
|
31
|
+
- E1 Quick: single question or asset feedback (positioning opinion, copy critique). Answer directly; numbers still need a source.
|
|
32
|
+
- E2 Campaign: single-campaign or single-channel plan. Light path: mini-brief + targeted research + campaign document.
|
|
33
|
+
- E3 Full Plan: complete marketing plan. Full SOSTAC workflow via the skill: Discovery -> Research -> Situation -> Objectives -> Strategy -> Tactics -> Action -> Control -> Packaging.
|
|
34
|
+
- Research Spike: time-boxed market question; outcome in \`mkt_docs/spikes/RESEARCH_[topic].md\`.
|
|
35
|
+
- When in doubt, pick the higher level. Declare the chosen level when starting.
|
|
36
|
+
|
|
37
|
+
## The three non-negotiables
|
|
38
|
+
1. Evidence ledger: every market number carries an [EV-nn] reference (FACT / BENCHMARK / ASSUMPTION). No invented numbers, ever.
|
|
39
|
+
2. Ask only what the user owns: facts come from the user, analysis comes from research. Never ask the user to do the analysis.
|
|
40
|
+
3. Internal consistency: budget sums, funnel math and the objective->tactic->KPI chain are validated mechanically before delivery.
|
|
41
|
+
|
|
42
|
+
## Where things live
|
|
43
|
+
- Vision (gate for E3): \`mkt_docs/vision/MKT_VISION.md\` — \`Status: DRAFT\` informs, \`Status: APPROVED\` binds.
|
|
44
|
+
- Evidence: \`mkt_docs/research/evidence_ledger.md\` (the single source for every number).
|
|
45
|
+
- Strategy artifacts: \`mkt_docs/strategy/\`; tactical artifacts: \`mkt_docs/tactics/\`; final deliverables: \`mkt_docs/deliverables/\`.
|
|
46
|
+
- Must-reads: \`mkt_docs/README.md\`; full generated manifest: \`mkt_docs/INDEX.md\`.
|
|
47
|
+
- If devPNT is available for this project, its M-VISION / plans / governed artifacts take over (Hybrid mode — see the skill).
|
|
48
|
+
|
|
49
|
+
## Closure gate
|
|
50
|
+
Deliverables ship only after \`python <skill_dir>/scripts/mkt_check.py check\` is
|
|
51
|
+
CLEAN (where the validator is adopted) and the CMO review passed.
|
|
52
|
+
|
|
53
|
+
If the mkt-agentic-sdlc skill is not available in this client, ask the user to install it:
|
|
54
|
+
\`npm i -g @antoneeo/mkt-agentic-sdlc-skill && mkt-sdlc-install-skill\`
|
|
55
|
+
`;
|
|
56
|
+
|
|
57
|
+
console.log('🚀 Initializing Marketing Agentic SDLC workflow...');
|
|
58
|
+
|
|
59
|
+
// 3. Load templates from the single source (skill's templates.md)
|
|
60
|
+
let sections;
|
|
61
|
+
try {
|
|
62
|
+
sections = loadTemplates();
|
|
63
|
+
} catch (err) {
|
|
64
|
+
console.error(`❌ Cannot load templates: ${err.message}`);
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
let seedFiles;
|
|
69
|
+
try {
|
|
70
|
+
seedFiles = [
|
|
71
|
+
['mkt_docs/README.md', templateFor(sections, 'mkt_docs/README.md')],
|
|
72
|
+
['mkt_docs/vision/MKT_VISION.md', templateFor(sections, 'MKT_VISION.md')],
|
|
73
|
+
['mkt_docs/vision/principles.md', templateFor(sections, 'principles.md')],
|
|
74
|
+
['mkt_docs/research/evidence_ledger.md', templateFor(sections, 'evidence_ledger.md')],
|
|
75
|
+
// NOTE: INDEX.md is NOT seeded — it is generated by `mkt_check.py index`
|
|
76
|
+
// and would immediately fail validate.
|
|
77
|
+
];
|
|
78
|
+
} catch (err) {
|
|
79
|
+
console.error(`❌ ${err.message}`);
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// 4. Create directories
|
|
84
|
+
directories.forEach((dir) => {
|
|
85
|
+
if (!fs.existsSync(dir)) {
|
|
86
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
87
|
+
console.log(`📁 Created directory: ${path.relative(cwd, dir)}`);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// 5. Write seed files (never overwrite)
|
|
92
|
+
const writeIfNotExists = (relPath, content, description) => {
|
|
93
|
+
const filePath = path.join(cwd, relPath);
|
|
94
|
+
if (!fs.existsSync(filePath)) {
|
|
95
|
+
fs.writeFileSync(filePath, content, 'utf8');
|
|
96
|
+
console.log(`📄 Created file: ${relPath}${description ? ` (${description})` : ''}`);
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
console.log(`⏭️ Skipped: ${relPath} already exists.`);
|
|
100
|
+
return false;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
seedFiles.forEach(([relPath, content]) => writeIfNotExists(relPath, content));
|
|
104
|
+
|
|
105
|
+
// 6. Client discovery and protocol pointers
|
|
106
|
+
console.log('\n--- Environment Analysis ---');
|
|
107
|
+
|
|
108
|
+
const protocolFiles = {
|
|
109
|
+
claude: 'CLAUDE.md',
|
|
110
|
+
gemini: 'GEMINI.md',
|
|
111
|
+
codex: 'AGENTS.md',
|
|
112
|
+
antigravity: 'AGENTS.md', // Antigravity CLI reads AGENTS.md; single protocolContent reused.
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
for (const client of CLIENTS) {
|
|
116
|
+
if (clientDetected(client)) {
|
|
117
|
+
console.log(`✅ ${client.label} detected.`);
|
|
118
|
+
writeIfNotExists(protocolFiles[client.key], protocolContent, `${client.label} protocol pointer`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Cursor/Windsurf (always recommended)
|
|
123
|
+
writeIfNotExists('.cursorrules', protocolContent, 'Cursor/Windsurf rules');
|
|
124
|
+
|
|
125
|
+
// 7. Generate mkt_docs/INDEX.md so the very first `validate` is already clean.
|
|
126
|
+
// The manifest is generated, never seeded: delegate to the validator if Python is available.
|
|
127
|
+
const validator = path.join(SKILL_SOURCE, 'scripts', 'mkt_check.py');
|
|
128
|
+
let indexed = false;
|
|
129
|
+
for (const py of ['python', 'python3', 'py']) {
|
|
130
|
+
try {
|
|
131
|
+
execSync(`${py} "${validator}" index --root "${cwd}"`, { stdio: 'ignore' });
|
|
132
|
+
console.log('📇 Generated mkt_docs/INDEX.md (document manifest).');
|
|
133
|
+
indexed = true;
|
|
134
|
+
break;
|
|
135
|
+
} catch (e) { /* try the next interpreter */ }
|
|
136
|
+
}
|
|
137
|
+
if (!indexed) {
|
|
138
|
+
console.log('ℹ️ Python not found: generate the manifest later with '
|
|
139
|
+
+ '"python <skill_dir>/scripts/mkt_check.py index" (validate reports it until then).');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
console.log('\n✅ Setup completed successfully!');
|
|
143
|
+
console.log('💡 Next steps:');
|
|
144
|
+
console.log(' 1. Make sure the mkt-agentic-sdlc skill is installed (mkt-sdlc-install-skill).');
|
|
145
|
+
console.log(' 2. Restart/open the project in your AI client so it reads the protocol pointer.');
|
|
146
|
+
console.log(' 3. Start an E3 engagement: the skill runs Discovery (its questions) before anything else.');
|
package/scripts/lib.js
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
// Shared helpers for the Marketing Agentic SDLC npm scripts (init / postinstall / preuninstall).
|
|
2
|
+
// Single source for client detection and skill-target paths: init and postinstall
|
|
3
|
+
// must never disagree on what "Claude Code is installed" means.
|
|
4
|
+
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const os = require('os');
|
|
8
|
+
const { execSync } = require('child_process');
|
|
9
|
+
|
|
10
|
+
const PACKAGE_ROOT = path.resolve(__dirname, '..');
|
|
11
|
+
const SKILL_SOURCE = path.join(PACKAGE_ROOT, 'skills', 'mkt-agentic-sdlc');
|
|
12
|
+
const TEMPLATES_PATH = path.join(SKILL_SOURCE, 'templates.md');
|
|
13
|
+
const SKILL_DIR_NAME = 'mkt-agentic-sdlc';
|
|
14
|
+
|
|
15
|
+
// One entry per supported AI client. `home` may be overridden by an env var
|
|
16
|
+
// (Claude Desktop / portable installs); presence of the home dir counts as
|
|
17
|
+
// detection even when the CLI is not on PATH.
|
|
18
|
+
const CLIENTS = [
|
|
19
|
+
{
|
|
20
|
+
key: 'claude',
|
|
21
|
+
label: 'Claude Code',
|
|
22
|
+
cmd: 'claude',
|
|
23
|
+
home: process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), '.claude'),
|
|
24
|
+
envVar: 'CLAUDE_CONFIG_DIR',
|
|
25
|
+
reload: 'Restart Claude Code to load it. Invoke via Skill tool as "mkt-agentic-sdlc".',
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
key: 'gemini',
|
|
29
|
+
label: 'Gemini CLI',
|
|
30
|
+
cmd: 'gemini',
|
|
31
|
+
home: process.env.GEMINI_HOME || path.join(os.homedir(), '.gemini'),
|
|
32
|
+
envVar: 'GEMINI_HOME',
|
|
33
|
+
reload: 'Run "gemini skills reload" or restart Gemini CLI to load it.',
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
key: 'codex',
|
|
37
|
+
label: 'Codex AI',
|
|
38
|
+
cmd: 'codex',
|
|
39
|
+
home: process.env.CODEX_HOME || path.join(os.homedir(), '.codex'),
|
|
40
|
+
envVar: 'CODEX_HOME',
|
|
41
|
+
reload: 'Restart Codex to load it. Invoke it as "$mkt-agentic-sdlc" or by asking for the Marketing SDLC skill.',
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
// Google Antigravity 2.0 discovers global agent skills under
|
|
45
|
+
// ~/.gemini/config/skills/ -- the SAME home the legacy Gemini CLI claims.
|
|
46
|
+
// To avoid a shared-home double-install, this entry sets:
|
|
47
|
+
// - skillsSubdir 'config/skills': distinct target from gemini's ~/.gemini/skills
|
|
48
|
+
// - homeMarker on ~/.gemini/config/skills: detection never fires on bare
|
|
49
|
+
// ~/.gemini (which every Antigravity user has); only the Antigravity skills
|
|
50
|
+
// dir, the `agy` CLI, or ANTIGRAVITY_HOME count as "Antigravity installed".
|
|
51
|
+
key: 'antigravity',
|
|
52
|
+
label: 'Google Antigravity',
|
|
53
|
+
cmd: 'agy',
|
|
54
|
+
home: process.env.ANTIGRAVITY_HOME || path.join(os.homedir(), '.gemini'),
|
|
55
|
+
envVar: 'ANTIGRAVITY_HOME',
|
|
56
|
+
skillsSubdir: 'config/skills',
|
|
57
|
+
homeMarker: path.join(
|
|
58
|
+
process.env.ANTIGRAVITY_HOME || path.join(os.homedir(), '.gemini'),
|
|
59
|
+
'config',
|
|
60
|
+
'skills',
|
|
61
|
+
),
|
|
62
|
+
reload: 'Restart Antigravity, or run "agy skills reload", to load it. Invoke by asking for the Marketing SDLC skill.',
|
|
63
|
+
},
|
|
64
|
+
];
|
|
65
|
+
|
|
66
|
+
function commandExists(cmd) {
|
|
67
|
+
try {
|
|
68
|
+
execSync(`${cmd} --version`, { stdio: 'ignore' });
|
|
69
|
+
return true;
|
|
70
|
+
} catch (e) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function clientDetected(client) {
|
|
76
|
+
// An entry may override the fs-existence probe with a `homeMarker` (a more
|
|
77
|
+
// specific path than the bare home) so two clients sharing a home dir do not
|
|
78
|
+
// both fire on its mere existence. Entries without a marker check `home`
|
|
79
|
+
// exactly as before (backward-compatible).
|
|
80
|
+
const homePathToCheck = client.homeMarker || client.home;
|
|
81
|
+
return commandExists(client.cmd)
|
|
82
|
+
|| Boolean(process.env[client.envVar])
|
|
83
|
+
|| fs.existsSync(homePathToCheck);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function skillTarget(client) {
|
|
87
|
+
// An entry may override the default `skills` sub-path with `skillsSubdir`
|
|
88
|
+
// (split on '/' to keep cross-platform path.join correctness). Entries
|
|
89
|
+
// without it resolve to <home>/skills/mkt-agentic-sdlc exactly as before.
|
|
90
|
+
const subdir = client.skillsSubdir ? client.skillsSubdir.split('/') : ['skills'];
|
|
91
|
+
return path.join(client.home, ...subdir, SKILL_DIR_NAME);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function copyRecursive(src, dest) {
|
|
95
|
+
if (typeof fs.cpSync === 'function') {
|
|
96
|
+
fs.cpSync(src, dest, { recursive: true, force: true });
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
// Fallback for Node < 16.7
|
|
100
|
+
if (!fs.existsSync(dest)) fs.mkdirSync(dest, { recursive: true });
|
|
101
|
+
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
102
|
+
const s = path.join(src, entry.name);
|
|
103
|
+
const d = path.join(dest, entry.name);
|
|
104
|
+
if (entry.isDirectory()) copyRecursive(s, d);
|
|
105
|
+
else fs.copyFileSync(s, d);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Parse templates.md into { headingText: [fencedBlock, ...] }.
|
|
111
|
+
* Templates are single-sourced there: the init script must extract them
|
|
112
|
+
* instead of carrying its own inline copies (which historically drifted).
|
|
113
|
+
*/
|
|
114
|
+
function loadTemplates() {
|
|
115
|
+
const text = fs.readFileSync(TEMPLATES_PATH, 'utf8');
|
|
116
|
+
const lines = text.split(/\r?\n/);
|
|
117
|
+
const sections = {};
|
|
118
|
+
let heading = null;
|
|
119
|
+
let block = null;
|
|
120
|
+
for (const line of lines) {
|
|
121
|
+
const h = line.match(/^##\s+(.*)$/);
|
|
122
|
+
if (h && block === null) {
|
|
123
|
+
heading = h[1].trim();
|
|
124
|
+
sections[heading] = sections[heading] || [];
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (/^```/.test(line)) {
|
|
128
|
+
if (block === null) {
|
|
129
|
+
block = [];
|
|
130
|
+
} else {
|
|
131
|
+
if (heading) sections[heading].push(block.join('\n') + '\n');
|
|
132
|
+
block = null;
|
|
133
|
+
}
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
if (block !== null) block.push(line);
|
|
137
|
+
}
|
|
138
|
+
return sections;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Return the Nth fenced block of the section whose heading contains `needle`.
|
|
143
|
+
* Throws with a clear message when missing: writing a wrong or empty
|
|
144
|
+
* boilerplate silently would be worse than failing the init.
|
|
145
|
+
*/
|
|
146
|
+
function templateFor(sections, needle, index = 0) {
|
|
147
|
+
const heading = Object.keys(sections).find((h) => h.includes(needle));
|
|
148
|
+
const blocks = heading ? sections[heading] : undefined;
|
|
149
|
+
if (!blocks || !blocks[index]) {
|
|
150
|
+
throw new Error(
|
|
151
|
+
`Template section containing "${needle}" (block ${index}) not found in ${TEMPLATES_PATH}. ` +
|
|
152
|
+
'The package is corrupted or templates.md was restructured: fix templates.md, do not improvise content.'
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
return blocks[index];
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
module.exports = {
|
|
159
|
+
PACKAGE_ROOT,
|
|
160
|
+
SKILL_SOURCE,
|
|
161
|
+
TEMPLATES_PATH,
|
|
162
|
+
SKILL_DIR_NAME,
|
|
163
|
+
CLIENTS,
|
|
164
|
+
commandExists,
|
|
165
|
+
clientDetected,
|
|
166
|
+
skillTarget,
|
|
167
|
+
copyRecursive,
|
|
168
|
+
loadTemplates,
|
|
169
|
+
templateFor,
|
|
170
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const { SKILL_SOURCE, CLIENTS, clientDetected, skillTarget, copyRecursive } = require('./lib');
|
|
5
|
+
|
|
6
|
+
function installSkill(client) {
|
|
7
|
+
if (!fs.existsSync(SKILL_SOURCE)) {
|
|
8
|
+
console.log(`⚠️ Skill source not found at ${SKILL_SOURCE}; skipping ${client.label} install.`);
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
const target = skillTarget(client);
|
|
12
|
+
try {
|
|
13
|
+
fs.mkdirSync(target, { recursive: true });
|
|
14
|
+
copyRecursive(SKILL_SOURCE, target);
|
|
15
|
+
console.log(`📦 Installed ${client.label} skill at: ${target}`);
|
|
16
|
+
console.log(` ${client.reload}`);
|
|
17
|
+
return true;
|
|
18
|
+
} catch (err) {
|
|
19
|
+
console.log(`⚠️ Failed to install ${client.label} skill: ${err.message}`);
|
|
20
|
+
console.log(` Manual install: copy "${SKILL_SOURCE}" to "${target}".`);
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
console.log('\n--- Marketing Agentic SDLC Skill Discovery ---');
|
|
26
|
+
|
|
27
|
+
let detected = false;
|
|
28
|
+
for (const client of CLIENTS) {
|
|
29
|
+
if (clientDetected(client)) {
|
|
30
|
+
console.log(`✅ Detected: ${client.label}`);
|
|
31
|
+
detected = true;
|
|
32
|
+
installSkill(client);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (!detected) {
|
|
37
|
+
console.log('ℹ️ No specific AI CLI detected globally, but you can still use the skill.');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
console.log('\nTo initialize a project with the marketing protocol, run:');
|
|
41
|
+
console.log('👉 npx mkt-sdlc-init');
|
|
42
|
+
console.log('------------------------------------\n');
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const { CLIENTS, skillTarget } = require('./lib');
|
|
5
|
+
|
|
6
|
+
function removeSkill(client) {
|
|
7
|
+
const target = skillTarget(client);
|
|
8
|
+
if (!fs.existsSync(target)) return;
|
|
9
|
+
try {
|
|
10
|
+
fs.rmSync(target, { recursive: true, force: true });
|
|
11
|
+
console.log(`🧹 Removed ${client.label} skill at: ${target}`);
|
|
12
|
+
} catch (err) {
|
|
13
|
+
console.log(`⚠️ Could not remove ${target}: ${err.message}`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
CLIENTS.forEach(removeSkill);
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Mechanical Enforcement (optional)
|
|
2
|
+
|
|
3
|
+
The prompt is not enforcement. Where the project needs repeatable guarantees,
|
|
4
|
+
wire the validator into the workflow. Everything here is optional: the skill
|
|
5
|
+
must stay usable without Python or hooks, declaring what it cannot verify.
|
|
6
|
+
|
|
7
|
+
## 1. Pre-delivery gate (the one that matters)
|
|
8
|
+
|
|
9
|
+
Before presenting any E2/E3 deliverable as finished:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
python <skill_dir>/scripts/mkt_check.py check --root <project_root>
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
`check` runs `validate + ledger + budget + funnel + trace`. Errors block the
|
|
16
|
+
delivery; warnings ship only with explicit user acknowledgment. This is the
|
|
17
|
+
marketing twin of "tests must pass before DONE".
|
|
18
|
+
|
|
19
|
+
## 2. CI
|
|
20
|
+
|
|
21
|
+
For a marketing repo kept under version control:
|
|
22
|
+
|
|
23
|
+
```yaml
|
|
24
|
+
# e.g. GitHub Actions step
|
|
25
|
+
- run: python skills/mkt-agentic-sdlc/scripts/mkt_check.py validate --strict --root .
|
|
26
|
+
- run: python skills/mkt-agentic-sdlc/scripts/mkt_check.py ledger --root .
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Use `--strict` only in CI: locally, warnings are guidance; in CI they are
|
|
30
|
+
drift.
|
|
31
|
+
|
|
32
|
+
## 3. Git hook (pre-commit)
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
#!/bin/sh
|
|
36
|
+
python skills/mkt-agentic-sdlc/scripts/mkt_check.py check --root . || {
|
|
37
|
+
echo "mkt_check failed — fix the plan before committing."; exit 1; }
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## 4. What the validator cannot check (honesty list)
|
|
41
|
+
|
|
42
|
+
- Whether a BENCHMARK's URL actually supports the claimed number (it checks
|
|
43
|
+
presence, not truth) — that is the review's R2/R3 territory.
|
|
44
|
+
- Whether the positioning passes the swap test (R1) — adversarial review only.
|
|
45
|
+
- Whether kill/scale thresholds are sensible — review, with ledger evidence.
|
|
46
|
+
- Whether the deliverable language matches the target market — Discovery
|
|
47
|
+
record + review.
|
|
48
|
+
|
|
49
|
+
Declare these residuals when reporting a CLEAN check: mechanical CLEAN plus
|
|
50
|
+
review PASS is the full gate, neither alone.
|
|
51
|
+
|
|
52
|
+
## 5. Skill self-test (skill development only)
|
|
53
|
+
|
|
54
|
+
Two deterministic batteries — the release gate. Run both:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
python -m unittest discover -s skills/mkt-agentic-sdlc/scripts -p "test_*.py"
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
- `test_mkt_check.py` — the validator itself; gate for changes to
|
|
61
|
+
`mkt_check.py` or to the parseable template formats in `templates.md` (the
|
|
62
|
+
two must move together: a template format change without a validator change
|
|
63
|
+
is drift).
|
|
64
|
+
- `test_skill_invariants.py` — the doctrine invariants: asserts the
|
|
65
|
+
load-bearing rules are still present in `SKILL.md` and the support files
|
|
66
|
+
(the three guarantees, the review red-flags R1/R11b/R15, the elicitation
|
|
67
|
+
rules, the research URL rule, the parseable template tokens, every support
|
|
68
|
+
file wired). Fails when a rule is deleted or weakened — a real regression,
|
|
69
|
+
never flakiness.
|
|
70
|
+
|
|
71
|
+
## 6. Behavioral eval layer (opt-in, non-gating)
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
python skills/mkt-agentic-sdlc/evals/run_behavioral.py skills/mkt-agentic-sdlc/evals/scenarios/<scenario>.md
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Declarative scenarios exercise real agent *adherence* (elicitation asks only
|
|
78
|
+
owned facts, no number without a ledger entry, swap-test enforced, low-cost
|
|
79
|
+
trap flagged, E2-without-strategy escalates, no guaranteed-success promise).
|
|
80
|
+
The driver seeds a throwaway fixture, prints the prompt + pass criteria, makes
|
|
81
|
+
NO model call, and never gates — LLM nondeterminism is why the deterministic
|
|
82
|
+
gate stays §5. See `evals/scenarios/README.md`.
|