@tidyfactor/marketing 1.3.0 โ 1.6.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/.tidyfactor +53 -52
- package/CHANGELOG.md +47 -0
- package/README.ar.md +20 -9
- package/README.md +20 -9
- package/SKILL.md +46 -30
- package/bin/add-skill.js +65 -50
- package/brand.json +67 -67
- package/brand.yaml +55 -0
- package/manifest.json +256 -0
- package/package.json +5 -1
- package/references/commands/audit.md +34 -0
- package/references/commands/brief.md +7 -5
- package/references/memory/20-brain-baas-integration.md +89 -0
- package/references/memory/ad-copy-templates.md +94 -93
- package/references/memory/arabic-writing.md +1 -1
- package/references/memory/campaign-mindmap.md +85 -0
- package/references/memory/decision-points.md +74 -73
- package/references/memory/frameworks.md +87 -86
- package/references/memory/lifecycle-flows.md +107 -106
- package/references/memory/metrics-benchmarks.md +71 -70
- package/references/memory/naming-conventions.md +75 -0
- package/references/memory/philosophy.md +2 -0
- package/references/memory/platform-specs.md +76 -75
- package/references/memory/promotions-math.md +57 -56
- package/references/memory/quality-bar.md +56 -55
- package/references/workflows/brief.md +74 -35
- package/references/workflows/campaign-launch.md +1 -1
- package/references/workflows/content-engine.md +1 -1
- package/references/workflows/email-lifecycle.md +1 -1
- package/references/workflows/paid-acquisition.md +1 -1
- package/references/workflows/promo-conversion.md +1 -1
- package/references/workflows/social-growth.md +1 -1
- package/references/workflows/viral-retention.md +1 -1
- package/scripts/audit_copy.py +112 -0
- package/scripts/calc_promo_math.py +69 -0
- package/scripts/clean_orphaned_assets.py +108 -0
- package/tests/scenarios.md +87 -0
- package/tools/build-skill.js +4 -0
- package/tools/validate_skill.py +265 -112
- package/assets/og-default.png +0 -0
|
@@ -1,72 +1,111 @@
|
|
|
1
1
|
# Marketing Discovery & Brief Workflow
|
|
2
2
|
|
|
3
|
-
> **Outcome**: Generates an authoritative `.tidyfactor/marketing-brief.md`
|
|
3
|
+
> **Outcome**: Generates an authoritative `.tidyfactor/marketing-brief.md` baseline capturing target market, brand voice, funnel stage, conversion model, and delivery scope.
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
## ๐ Step 0:
|
|
7
|
+
## ๐ Step 0: Context Delta Resolution Engine
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
2. If it exists and user did not specify `--force` or `--reset`:
|
|
11
|
-
- Display the active brief summary.
|
|
12
|
-
- Ask if the user wants to keep the existing baseline or update specific parameters.
|
|
9
|
+
Before asking any questions, execute the mechanical resolution formula:
|
|
13
10
|
|
|
14
|
-
|
|
11
|
+
$$\text{Unknowns} = \text{Required Decisions} - (\text{Discovered Facts} \cup \text{Brain KIs})$$
|
|
15
12
|
|
|
16
|
-
|
|
13
|
+
### 1. Required Decisions Set (from `manifest.json["decision_gates"]`):
|
|
14
|
+
- `target_market`: Regional calibration (GCC, Egypt/Levant, Global B2B SaaS, Bilingual MENA).
|
|
15
|
+
- `brand_voice`: Voice archetype (Authoritative Challenger, Empathetic Guide, Elite Luxury, High-Energy Direct Response).
|
|
16
|
+
- `funnel_stage`: Conversion focus (Top / Middle / Bottom of funnel).
|
|
17
|
+
- `core_offer`: Headline value proposition and transaction vehicle.
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
### 2. Discovered Facts (Auto-Sensing + Local Staleness Tracking):
|
|
20
|
+
- Inspect `brand.yaml`, `brand.json`, and `BRAND-GUIDELINES.md` on disk.
|
|
21
|
+
- If `track_staleness: true` is configured, verify file hash/mtime against stored snapshot.
|
|
22
|
+
- Any decision successfully extracted from local disk is removed from $\text{Unknowns}$.
|
|
19
23
|
|
|
20
|
-
###
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
- **
|
|
24
|
+
### 3. Fail-Open MCP Brain Acceleration:
|
|
25
|
+
- If unresolved unknowns remain AND `search_knowledge_base` is available:
|
|
26
|
+
- Query `search_knowledge_base(query="marketing persona brand voice", scope="project")`.
|
|
27
|
+
- If a valid marketing KI exists, populate the context and remove from $\text{Unknowns}$.
|
|
28
|
+
- **Fail-Open Invariant**: If Brain MCP is unavailable or offline, skip instantly with 0ms delay without warnings.
|
|
25
29
|
|
|
26
|
-
|
|
27
|
-
- **A) Authoritative Challenger** (Direct, contrarian, proof-backed, no-nonsense).
|
|
28
|
-
- **B) Empathetic Guide** (Supportive, story-driven, transformational, warm).
|
|
29
|
-
- **C) Elite Luxury / High-End** (Minimalist, aspirational, refined confidence).
|
|
30
|
-
- **D) High-Energy Direct Response** (Urgent, benefit-stacked, conversion-focused).
|
|
30
|
+
---
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
-
|
|
32
|
+
## ๐ฌ Step 1: Interactive Modal Protocol (CDL v2.0)
|
|
33
|
+
|
|
34
|
+
If $\text{Unknowns} = \emptyset$:
|
|
35
|
+
- Display the synthesized 4-line baseline summary.
|
|
36
|
+
- Suggest next commands (`/strategy`, `/advertising`, `/email`, `/content`) immediately.
|
|
37
|
+
|
|
38
|
+
If $\text{Unknowns} \neq \emptyset$:
|
|
39
|
+
- **Interactive Wizard Invariant**: Present genuine Unknowns exclusively via the native interactive question tool (`ask_question`). Never dump static text questionnaires or bullet lists in chat.
|
|
40
|
+
- **Zero Robotic Preamble**: Forbid greetings or conversational filler.
|
|
41
|
+
|
|
42
|
+
### Operational Mode Selection:
|
|
43
|
+
|
|
44
|
+
#### [MODE A] Smart 3-Round Protocol (๐ฏ ุงูุงุฑุชุฌุงู ุงูุฐูู ุงูู
ููุฏ)
|
|
45
|
+
Presents structured choices one step at a time via `ask_question`:
|
|
46
|
+
1. **Round 1 (Target Market & Regional Nuance)**:
|
|
47
|
+
- `(Recommended) Bilingual / Unified MENA` โ Pan-Arab modern standard paired with English tech terminology.
|
|
48
|
+
- `Gulf / GCC (Saudi Arabia ๐ธ๐ฆ, UAE ๐ฆ๐ช, Kuwait ๐ฐ๐ผ, Qatar ๐ถ๐ฆ)` โ Prestige, trust-first, WhatsApp/Installment framing.
|
|
49
|
+
- `Egypt & Levant (Egypt ๐ช๐ฌ, Jordan ๐ฏ๐ด)` โ Practical ROI, high energy, relatable wit, InstaPay framing.
|
|
50
|
+
- `Global / B2B SaaS` โ Direct, metric-dense, self-serve focused, English-first.
|
|
51
|
+
2. **Round 2 (Brand Voice Archetype)**:
|
|
52
|
+
- `(Recommended) Authoritative Challenger` โ Direct, contrarian, proof-backed, zero-nonsense.
|
|
53
|
+
- `Empathetic Guide` โ Supportive, story-driven, transformational, warm.
|
|
54
|
+
- `Elite Luxury / High-End` โ Minimalist, aspirational, refined confidence.
|
|
55
|
+
- `High-Energy Direct Response` โ Urgent, benefit-stacked, conversion-focused.
|
|
56
|
+
3. **Round 3 (Funnel Focus & Core Offer)**:
|
|
57
|
+
- `(Recommended) Bottom-of-Funnel Direct Sale / Promo` โ Immediate transaction, launch offer.
|
|
58
|
+
- `Middle-of-Funnel Trial / Demo` โ Product-led trial, strategy session.
|
|
59
|
+
- `Top-of-Funnel Lead Magnet` โ Free high-value guide, benchmark, audit.
|
|
60
|
+
|
|
61
|
+
#### [MODE B] Debate Mode (๐ฅ ุงูุงุณุชุฌูุงุจ ูุงูู
ูุงุธุฑุฉ ุงููุงููุงุฆูุฉ)
|
|
62
|
+
- Activated via `/debate`, explicit user prompt ("ู
ูุงุธุฑุฉ" / "ุงุณุชุฌูุจูู"), or Mode A escalation.
|
|
63
|
+
- Relentlessly challenges marketing assumptions, price elasticity, CAC-to-LTV payback periods, and unproven claims.
|
|
64
|
+
- Presents binary architectural trade-offs one step at a time via `ask_question`.
|
|
65
|
+
- Terminates only upon explicit user trigger (`"END DEBATE"` / `"ุงุนุชู
ุงุฏ"`), emitting a formal synthesis.
|
|
36
66
|
|
|
37
67
|
---
|
|
38
68
|
|
|
39
|
-
## ๐พ Step 2:
|
|
40
|
-
|
|
41
|
-
Format and persist the confirmed choices:
|
|
69
|
+
## ๐พ Step 2: Persist Baseline & Single-Direction Brain Push
|
|
42
70
|
|
|
71
|
+
1. Format and write `.tidyfactor/marketing-brief.md`:
|
|
43
72
|
```markdown
|
|
44
73
|
# Marketing Brief Baseline
|
|
45
74
|
|
|
46
75
|
- **Product / Brand**: [Extracted or Confirmed Name]
|
|
47
|
-
- **Target Market
|
|
48
|
-
- **Brand Voice
|
|
49
|
-
- **Funnel Stage
|
|
50
|
-
- **Core Offer
|
|
51
|
-
- **Deliverable Scope
|
|
76
|
+
- **Target Market**: [GCC / Egypt & Levant / Global / Unified MENA]
|
|
77
|
+
- **Brand Voice**: [Authoritative / Empathetic / Luxury / Direct Response]
|
|
78
|
+
- **Funnel Stage**: [Top / Middle / Bottom]
|
|
79
|
+
- **Core Offer**: [Lead Magnet / Trial / Direct Transaction]
|
|
80
|
+
- **Deliverable Scope**: [Sprint Copy / Multi-Channel Blueprint]
|
|
52
81
|
- **Last Updated**: [Current Date]
|
|
53
82
|
```
|
|
54
83
|
|
|
84
|
+
2. Format YAML snapshot `.tidyfactor/marketing-brief.snapshot.yaml` for deterministic local staleness tracking (Rule 15).
|
|
85
|
+
|
|
86
|
+
3. **Anti-Dual-Write Outbound Push (`--sync-brain`)**:
|
|
87
|
+
- The local file is ALWAYS the single source of truth.
|
|
88
|
+
- When explicitly passed `--sync-brain`, format the deliverable as an Atomic KI and push to Brain MCP via `extract_knowledge_item`.
|
|
89
|
+
- Never perform simultaneous dual writes.
|
|
90
|
+
|
|
55
91
|
---
|
|
56
92
|
|
|
57
|
-
## ๐ฏ Step 3: Self-Critique &
|
|
93
|
+
## ๐ฏ Step 3: Self-Critique & Actionable Summary
|
|
58
94
|
|
|
59
95
|
Stamp the 7-axis critique:
|
|
60
96
|
```markdown
|
|
61
97
|
/* Pre-emit critique: P5 H5 E5 S5 R5 V5 D5 */
|
|
62
98
|
```
|
|
99
|
+
Display a concise summary and suggest the next logical marketing command (`/strategy`, `/advertising`, `/email`, `/content`, `/audit`).
|
|
63
100
|
|
|
64
101
|
---
|
|
65
102
|
|
|
66
|
-
##
|
|
103
|
+
## Validation checklist
|
|
67
104
|
|
|
105
|
+
- [ ] Context Delta Resolution computed prior to prompting user.
|
|
106
|
+
- [ ] No questions asked for parameters already discovered on disk.
|
|
107
|
+
- [ ] Unknowns presented via native interactive modal tool (`ask_question`).
|
|
68
108
|
- [ ] `.tidyfactor/marketing-brief.md` created or verified on disk.
|
|
69
|
-
- [ ] Exactly 3 or fewer questions asked in a single round.
|
|
70
109
|
- [ ] Regional calibration (GCC, Egypt, Global) explicitly recorded.
|
|
71
110
|
- [ ] Brand voice archetype explicitly recorded.
|
|
72
|
-
- [ ] Confirmed baseline summary displayed to user with next command suggestions
|
|
111
|
+
- [ ] Confirmed baseline summary displayed to user with next command suggestions.
|
|
@@ -60,7 +60,7 @@ Before emitting the final strategy, evaluate against all 7 axes from `../memory/
|
|
|
60
60
|
|
|
61
61
|
---
|
|
62
62
|
|
|
63
|
-
## Validation
|
|
63
|
+
## Validation checklist
|
|
64
64
|
|
|
65
65
|
- [ ] CDL brief parameters resolved from `.tidyfactor/marketing-brief.md` or prompt defaults
|
|
66
66
|
- [ ] Canonical positioning statement formulated with concrete proof (no generic slogans)
|
|
@@ -56,7 +56,7 @@ Before emitting the final content assets, evaluate against all 7 axes from `../m
|
|
|
56
56
|
|
|
57
57
|
---
|
|
58
58
|
|
|
59
|
-
## Validation
|
|
59
|
+
## Validation checklist
|
|
60
60
|
|
|
61
61
|
- [ ] CDL brief parameters resolved from `.tidyfactor/marketing-brief.md` or prompt defaults
|
|
62
62
|
- [ ] Every post includes a 0-3s attention hook matching platform specs
|
|
@@ -44,7 +44,7 @@ Before emitting the final email copy or flows, evaluate against all 7 axes from
|
|
|
44
44
|
|
|
45
45
|
---
|
|
46
46
|
|
|
47
|
-
## Validation
|
|
47
|
+
## Validation checklist
|
|
48
48
|
|
|
49
49
|
- [ ] CDL brief parameters resolved from `.tidyfactor/marketing-brief.md` or prompt defaults
|
|
50
50
|
- [ ] Lead magnet promises a specific, actionable win achievable in < 10 minutes
|
|
@@ -54,7 +54,7 @@ Before emitting ad copy or landing page wireframes, evaluate against all 7 axes
|
|
|
54
54
|
|
|
55
55
|
---
|
|
56
56
|
|
|
57
|
-
## Validation
|
|
57
|
+
## Validation checklist
|
|
58
58
|
|
|
59
59
|
- [ ] CDL brief parameters resolved from `.tidyfactor/marketing-brief.md` or prompt defaults
|
|
60
60
|
- [ ] At least 3 distinct psychological ad copy angles produced
|
|
@@ -46,7 +46,7 @@ Before emitting pricing, promotions, or sale mechanics, evaluate against all 7 a
|
|
|
46
46
|
|
|
47
47
|
---
|
|
48
48
|
|
|
49
|
-
## Validation
|
|
49
|
+
## Validation checklist
|
|
50
50
|
|
|
51
51
|
- [ ] CDL brief parameters resolved from `.tidyfactor/marketing-brief.md` or prompt defaults
|
|
52
52
|
- [ ] Discount structure verified against gross margins to prevent profit erosion
|
|
@@ -53,7 +53,7 @@ Before emitting social media playbooks or profile copy, evaluate against all 7 a
|
|
|
53
53
|
|
|
54
54
|
---
|
|
55
55
|
|
|
56
|
-
## Validation
|
|
56
|
+
## Validation checklist
|
|
57
57
|
|
|
58
58
|
- [ ] CDL brief parameters resolved from `.tidyfactor/marketing-brief.md` or prompt defaults
|
|
59
59
|
- [ ] Bio is optimized with clear target, authority proof, and single action CTA
|
|
@@ -51,7 +51,7 @@ Before emitting loyalty programs, referral systems, or outreach scripts, evaluat
|
|
|
51
51
|
|
|
52
52
|
---
|
|
53
53
|
|
|
54
|
-
## Validation
|
|
54
|
+
## Validation checklist
|
|
55
55
|
|
|
56
56
|
- [ ] CDL brief parameters resolved from `.tidyfactor/marketing-brief.md` or prompt defaults
|
|
57
57
|
- [ ] Retention drop-off point diagnosed before prescribing loyalty mechanics
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
TidyFactor Marketing Copy Quality Auditor
|
|
4
|
+
Scans direct-response marketing copy, ad headlines, and landing page scripts
|
|
5
|
+
for AI anti-patterns, banned cliches, robotic phrasing, and angle diversity.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import sys
|
|
9
|
+
import os
|
|
10
|
+
import re
|
|
11
|
+
import json
|
|
12
|
+
import argparse
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
# Ensure UTF-8 output on Windows console
|
|
16
|
+
if sys.stdout and hasattr(sys.stdout, "reconfigure"):
|
|
17
|
+
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
|
|
18
|
+
if sys.stderr and hasattr(sys.stderr, "reconfigure"):
|
|
19
|
+
sys.stderr.reconfigure(encoding="utf-8", errors="replace")
|
|
20
|
+
|
|
21
|
+
BANNED_AI_CLICHES = [
|
|
22
|
+
# English Slop
|
|
23
|
+
r"\bunleash\b", r"\belevate\b", r"\bgame-changer\b", r"\brevolutionize\b",
|
|
24
|
+
r"\bseamlessly\b", r"\btap into\b", r"\bdive deep\b", r"\bdelve into\b",
|
|
25
|
+
r"\bunlock your potential\b", r"\bin today's fast-paced world\b",
|
|
26
|
+
r"\blook no further\b", r"\bcutting-edge\b", r"\bstate-of-the-art\b",
|
|
27
|
+
# Arabic Slop
|
|
28
|
+
r"ูู ุนุงูู
ูุง ุงูููู
ุงูู
ุชุณุงุฑุน", r"ูู ุนุตุฑ ุงูุชูููููุฌูุง", r"ุฃุทูู ุงูุนูุงู",
|
|
29
|
+
r"ุงูุบู
ุณ ูู", r"ุบููุฑ ููุงุนุฏ ุงููุนุจุฉ", r"ุญููู ุณุญุฑูุฉ", r"ูุฑูุฏุฉ ู
ู ููุนูุง",
|
|
30
|
+
r"ููุฏู
ููู
ุจูู ูุฎุฑ", r"ูุง ุฏุงุนู ููุจุญุซ ุจุนุฏ ุงูุขู", r"ุจูุงุจุชู ูุญู"
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
def audit_text_content(text: str, file_name: str = "inline-copy") -> dict:
|
|
34
|
+
issues = []
|
|
35
|
+
lines = text.splitlines()
|
|
36
|
+
|
|
37
|
+
# 1. Check for AI Cliches & Marketing Slop
|
|
38
|
+
for idx, line in enumerate(lines, start=1):
|
|
39
|
+
for pattern in BANNED_AI_CLICHES:
|
|
40
|
+
matches = re.finditer(pattern, line, re.IGNORECASE)
|
|
41
|
+
for m in matches:
|
|
42
|
+
issues.append({
|
|
43
|
+
"type": "banned_cliche",
|
|
44
|
+
"severity": "high",
|
|
45
|
+
"line": idx,
|
|
46
|
+
"matched": m.group(0),
|
|
47
|
+
"message": f"Banned marketing clichรฉ detected: '{m.group(0)}'. Replace with concrete proof or specific benefit."
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
# 2. Check for Pre-emit critique stamp
|
|
51
|
+
has_critique = bool(re.search(r"/\*\s*Pre-emit critique:[^\*]+\*/", text, re.IGNORECASE))
|
|
52
|
+
if not has_critique and not text.startswith("#"):
|
|
53
|
+
issues.append({
|
|
54
|
+
"type": "missing_critique_stamp",
|
|
55
|
+
"severity": "medium",
|
|
56
|
+
"line": 1,
|
|
57
|
+
"message": "Missing 7-axis pre-emit critique stamp: /* Pre-emit critique: P5 H5 E5 S5 R5 V5 D5 */"
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
# 3. Calculate Score
|
|
61
|
+
high_issues = [i for i in issues if i["severity"] == "high"]
|
|
62
|
+
med_issues = [i for i in issues if i["severity"] == "medium"]
|
|
63
|
+
|
|
64
|
+
score = max(0, 100 - (len(high_issues) * 20) - (len(med_issues) * 10))
|
|
65
|
+
passed = len(high_issues) == 0 and score >= 80
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
"file": file_name,
|
|
69
|
+
"score": score,
|
|
70
|
+
"passed": passed,
|
|
71
|
+
"total_issues": len(issues),
|
|
72
|
+
"issues": issues,
|
|
73
|
+
"timestamp": "2026-09-02T06:00:00Z"
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
def main():
|
|
77
|
+
parser = argparse.ArgumentParser(description="TidyFactor Marketing Copy Auditor")
|
|
78
|
+
parser.add_argument("target", nargs="?", help="Path to copy file or markdown script")
|
|
79
|
+
parser.add_argument("--text", help="Direct copy string to audit")
|
|
80
|
+
parser.add_argument("--json", action="store_true", help="Output pure JSON format")
|
|
81
|
+
|
|
82
|
+
args = parser.parse_args()
|
|
83
|
+
|
|
84
|
+
if args.text:
|
|
85
|
+
content = args.text
|
|
86
|
+
filename = "string-input"
|
|
87
|
+
elif args.target and Path(args.target).exists():
|
|
88
|
+
target_path = Path(args.target)
|
|
89
|
+
content = target_path.read_text(encoding="utf-8", errors="replace")
|
|
90
|
+
filename = str(target_path)
|
|
91
|
+
else:
|
|
92
|
+
# Default sample check
|
|
93
|
+
content = "ูู ุนุงูู
ูุง ุงูููู
ุงูู
ุชุณุงุฑุนุ ููุฏู
ููู
ุจูู ูุฎุฑ ุงูุญู ุงูุณุญุฑู ูุชุบููุฑ ููุงุนุฏ ุงููุนุจุฉ."
|
|
94
|
+
filename = "demo-sample"
|
|
95
|
+
|
|
96
|
+
result = audit_text_content(content, filename)
|
|
97
|
+
|
|
98
|
+
if args.json:
|
|
99
|
+
print(json.dumps(result, indent=2, ensure_ascii=False))
|
|
100
|
+
else:
|
|
101
|
+
status_str = "[PASS]" if result["passed"] else "[FAIL]"
|
|
102
|
+
print(f"\n{status_str} Marketing Copy Quality Audit โ Score: {result['score']}/100")
|
|
103
|
+
print(f"Target: {result['file']}")
|
|
104
|
+
print(f"Issues Found: {result['total_issues']}\n")
|
|
105
|
+
for iss in result["issues"]:
|
|
106
|
+
print(f" - [Line {iss.get('line', '?')}] [{iss['severity'].upper()}] {iss['message']}")
|
|
107
|
+
print()
|
|
108
|
+
|
|
109
|
+
sys.exit(0 if result["passed"] else 1)
|
|
110
|
+
|
|
111
|
+
if __name__ == "__main__":
|
|
112
|
+
main()
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
TidyFactor Marketing Promotion & Margin Protection Calculator
|
|
4
|
+
Calculates break-even ROAS, gross margin impact, and discount thresholds.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import sys
|
|
8
|
+
import json
|
|
9
|
+
import argparse
|
|
10
|
+
|
|
11
|
+
# Ensure UTF-8 output on Windows console
|
|
12
|
+
if sys.stdout and hasattr(sys.stdout, "reconfigure"):
|
|
13
|
+
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
|
|
14
|
+
if sys.stderr and hasattr(sys.stderr, "reconfigure"):
|
|
15
|
+
sys.stderr.reconfigure(encoding="utf-8", errors="replace")
|
|
16
|
+
|
|
17
|
+
def calculate_promo_metrics(cogs: float, price: float, discount_percent: float, ad_spend_per_order: float = 0.0) -> dict:
|
|
18
|
+
if price <= 0:
|
|
19
|
+
raise ValueError("Price must be greater than 0")
|
|
20
|
+
|
|
21
|
+
discount_amount = price * (discount_percent / 100.0)
|
|
22
|
+
discounted_price = price - discount_amount
|
|
23
|
+
gross_profit = discounted_price - cogs - ad_spend_per_order
|
|
24
|
+
gross_margin_percent = (gross_profit / discounted_price) * 100.0 if discounted_price > 0 else 0.0
|
|
25
|
+
|
|
26
|
+
# Break-even ROAS = 1 / Gross Margin before ads
|
|
27
|
+
margin_before_ads = (discounted_price - cogs) / discounted_price if discounted_price > 0 else 0.0
|
|
28
|
+
breakeven_roas = (1.0 / margin_before_ads) if margin_before_ads > 0 else 0.0
|
|
29
|
+
|
|
30
|
+
is_margin_safe = gross_margin_percent >= 30.0 and gross_profit > 0
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
"original_price": round(price, 2),
|
|
34
|
+
"discount_percent": round(discount_percent, 2),
|
|
35
|
+
"discount_amount": round(discount_amount, 2),
|
|
36
|
+
"discounted_price": round(discounted_price, 2),
|
|
37
|
+
"cogs": round(cogs, 2),
|
|
38
|
+
"ad_spend_per_order": round(ad_spend_per_order, 2),
|
|
39
|
+
"net_gross_profit": round(gross_profit, 2),
|
|
40
|
+
"net_gross_margin_percent": round(gross_margin_percent, 2),
|
|
41
|
+
"breakeven_roas": round(breakeven_roas, 2),
|
|
42
|
+
"is_margin_safe": is_margin_safe,
|
|
43
|
+
"recommendation": "SAFE_TO_RUN" if is_margin_safe else "HIGH_RISK_MARGIN_COMPRESSION"
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
def main():
|
|
47
|
+
parser = argparse.ArgumentParser(description="TidyFactor Margin & Promo Calculator")
|
|
48
|
+
parser.add_argument("--price", type=float, default=100.0, help="Original product price")
|
|
49
|
+
parser.add_argument("--cogs", type=float, default=30.0, help="Cost of Goods Sold (COGS)")
|
|
50
|
+
parser.add_argument("--discount", type=float, default=20.0, help="Discount percentage (e.g. 20 for 20%)")
|
|
51
|
+
parser.add_argument("--cac", type=float, default=15.0, help="Estimated ad spend / CAC per order")
|
|
52
|
+
parser.add_argument("--json", action="store_true", help="Output pure JSON")
|
|
53
|
+
|
|
54
|
+
args = parser.parse_args()
|
|
55
|
+
|
|
56
|
+
result = calculate_promo_metrics(args.cogs, args.price, args.discount, args.cac)
|
|
57
|
+
|
|
58
|
+
if args.json:
|
|
59
|
+
print(json.dumps(result, indent=2))
|
|
60
|
+
else:
|
|
61
|
+
print("\n๐ฐ TidyFactor Margin & Promotion Math Report")
|
|
62
|
+
print(f" Price: ${result['original_price']} -> Discounted: ${result['discounted_price']} (-{result['discount_percent']}%)")
|
|
63
|
+
print(f" COGS: ${result['cogs']} | Est. CAC: ${result['ad_spend_per_order']}")
|
|
64
|
+
print(f" Net Gross Profit: ${result['net_gross_profit']} ({result['net_gross_margin_percent']}%)")
|
|
65
|
+
print(f" Break-Even ROAS Target: {result['breakeven_roas']}x")
|
|
66
|
+
print(f" Status: {result['recommendation']}\n")
|
|
67
|
+
|
|
68
|
+
if __name__ == "__main__":
|
|
69
|
+
main()
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
clean_orphaned_assets.py โ TidyFactor Asset & Folder Structure Hygiene Engine.
|
|
4
|
+
Detects and remediates:
|
|
5
|
+
1. Binary duplicate image assets using SHA-256 hashing.
|
|
6
|
+
2. Unreferenced orphan images in `assets/`.
|
|
7
|
+
3. Advises WebP compression for raster assets > 50KB.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
import sys
|
|
12
|
+
import hashlib
|
|
13
|
+
import re
|
|
14
|
+
import argparse
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
# Ensure UTF-8 output on Windows console
|
|
18
|
+
if sys.platform == "win32":
|
|
19
|
+
sys.stdout.reconfigure(encoding="utf-8")
|
|
20
|
+
sys.stderr.reconfigure(encoding="utf-8")
|
|
21
|
+
|
|
22
|
+
def compute_sha256(filepath: Path) -> str:
|
|
23
|
+
h = hashlib.sha256()
|
|
24
|
+
with open(filepath, "rb") as f:
|
|
25
|
+
while chunk := f.read(8192):
|
|
26
|
+
h.update(chunk)
|
|
27
|
+
return h.hexdigest()
|
|
28
|
+
|
|
29
|
+
def scan_assets(root: Path):
|
|
30
|
+
assets_dir = root / "assets"
|
|
31
|
+
if not assets_dir.exists():
|
|
32
|
+
print("[INFO] No assets/ directory found.")
|
|
33
|
+
return 0
|
|
34
|
+
|
|
35
|
+
image_extensions = {".png", ".jpg", ".jpeg", ".webp", ".svg", ".gif"}
|
|
36
|
+
asset_files = [p for p in assets_dir.iterdir() if p.is_file() and p.suffix.lower() in image_extensions]
|
|
37
|
+
|
|
38
|
+
# 1. SHA-256 Duplication Check
|
|
39
|
+
hashes = {}
|
|
40
|
+
duplicates = []
|
|
41
|
+
for asset in asset_files:
|
|
42
|
+
digest = compute_sha256(asset)
|
|
43
|
+
if digest in hashes:
|
|
44
|
+
duplicates.append((asset, hashes[digest]))
|
|
45
|
+
else:
|
|
46
|
+
hashes[digest] = asset
|
|
47
|
+
|
|
48
|
+
# 2. Markdown Reference Check
|
|
49
|
+
md_files = list(root.rglob("*.md")) + [root / "brand.yaml", root / "brand.json"]
|
|
50
|
+
all_content = ""
|
|
51
|
+
for md in md_files:
|
|
52
|
+
if "dist" in md.parts or ".git" in md.parts or "__pycache__" in md.parts:
|
|
53
|
+
continue
|
|
54
|
+
if md.exists():
|
|
55
|
+
all_content += md.read_text(encoding="utf-8", errors="ignore") + "\n"
|
|
56
|
+
|
|
57
|
+
orphans = []
|
|
58
|
+
for asset in asset_files:
|
|
59
|
+
# Match asset name in text
|
|
60
|
+
if asset.name not in all_content:
|
|
61
|
+
orphans.append(asset)
|
|
62
|
+
|
|
63
|
+
print("=" * 60)
|
|
64
|
+
print(" TIDYFACTOR MARKETING ASSET HYGIENE AUDIT")
|
|
65
|
+
print("=" * 60)
|
|
66
|
+
print(f"Total assets analyzed: {len(asset_files)}")
|
|
67
|
+
|
|
68
|
+
print(f"\n[1] Duplicate Asset Check (SHA-256):")
|
|
69
|
+
if duplicates:
|
|
70
|
+
print(f" [WARN] Found {len(duplicates)} duplicate asset(s):")
|
|
71
|
+
for dup, orig in duplicates:
|
|
72
|
+
print(f" - {dup.name} is identical to {orig.name}")
|
|
73
|
+
else:
|
|
74
|
+
print(" [OK] Zero binary duplicates found.")
|
|
75
|
+
|
|
76
|
+
print(f"\n[2] Orphan Asset Check:")
|
|
77
|
+
if orphans:
|
|
78
|
+
print(f" [WARN] Found {len(orphans)} unreferenced orphan asset(s):")
|
|
79
|
+
for orph in orphans:
|
|
80
|
+
print(f" - {orph.name} ({orph.stat().st_size / 1024:.1f} KB)")
|
|
81
|
+
else:
|
|
82
|
+
print(" [OK] Zero unreferenced orphan assets found.")
|
|
83
|
+
|
|
84
|
+
print(f"\n[3] Large Raster File Check (>50KB):")
|
|
85
|
+
large_rasters = [a for a in asset_files if a.suffix.lower() in {".png", ".jpg", ".jpeg"} and a.stat().st_size > 50 * 1024]
|
|
86
|
+
if large_rasters:
|
|
87
|
+
for lr in large_rasters:
|
|
88
|
+
print(f" [INFO] {lr.name}: {lr.stat().st_size / 1024:.1f} KB. Recommend WebP conversion for ~80% savings.")
|
|
89
|
+
else:
|
|
90
|
+
print(" [OK] All raster assets optimized or under 50KB.")
|
|
91
|
+
|
|
92
|
+
print("=" * 60)
|
|
93
|
+
return len(duplicates) + len(orphans)
|
|
94
|
+
|
|
95
|
+
def main():
|
|
96
|
+
parser = argparse.ArgumentParser(description="TidyFactor Asset Hygiene Engine")
|
|
97
|
+
parser.add_argument("--check", action="store_true", help="Run audit and return non-zero if issues exist")
|
|
98
|
+
args = parser.parse_args()
|
|
99
|
+
|
|
100
|
+
root = Path(__file__).resolve().parent.parent
|
|
101
|
+
issues_count = scan_assets(root)
|
|
102
|
+
|
|
103
|
+
if args.check and issues_count > 0:
|
|
104
|
+
sys.exit(1)
|
|
105
|
+
sys.exit(0)
|
|
106
|
+
|
|
107
|
+
if __name__ == "__main__":
|
|
108
|
+
main()
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Test Scenarios: tidyfactor-marketing
|
|
2
|
+
|
|
3
|
+
Comprehensive evaluation scenarios validating deterministic command dispatch, Contextual Decision Layer auto-sensing, Arabic direct-response generation, margin math protection, and automated copy linting.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Scenario 1: E-Commerce 72-Hour Flash Sale with Margin Guardrails (GCC / KSA ๐ธ๐ฆ)
|
|
8
|
+
|
|
9
|
+
### Objective
|
|
10
|
+
Generate a margin-safe promotional strategy and high-urgency WhatsApp/Instagram copy for a Saudi Arabian DTC brand launching a 72-hour flash sale.
|
|
11
|
+
|
|
12
|
+
### Inputs & Context
|
|
13
|
+
- **Product**: Leather Travel Bag
|
|
14
|
+
- **Price**: 400 SAR, **COGS**: 120 SAR, **Proposed Discount**: 25% (100 SAR off)
|
|
15
|
+
- **Target Market**: Saudi Arabia (Riyadh, Jeddah)
|
|
16
|
+
- **Channel**: WhatsApp Broadcast + Instagram Story Ads (9:16)
|
|
17
|
+
|
|
18
|
+
### Expected Execution & Checks
|
|
19
|
+
1. **Margin Safety Gate**: `calc_promo_math.py` confirms:
|
|
20
|
+
- Discounted Price: 300 SAR
|
|
21
|
+
- Net Gross Margin: 60% (>30% threshold)
|
|
22
|
+
- Status: `SAFE_TO_RUN`
|
|
23
|
+
2. **Copy Generation**:
|
|
24
|
+
- High-urgency hook without slop (`"ุฃุทูู ุงูุนูุงู"` โ forbidden).
|
|
25
|
+
- Trust and payment framing: Mada, Tabby, Tamara 4-installment split.
|
|
26
|
+
- 7-axis pre-emit critique stamp included.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Scenario 2: B2B Multi-Tenant SaaS Phased Launch (Global / English)
|
|
31
|
+
|
|
32
|
+
### Objective
|
|
33
|
+
Formulate a complete T-30 to T+14 launch sequence, positioning statement, and competitive differentiation for an AI agent observability tool.
|
|
34
|
+
|
|
35
|
+
### Inputs & Context
|
|
36
|
+
- **Product**: AgentTrace (Observability for AI Coding Agents)
|
|
37
|
+
- **Pricing**: $49/seat/month
|
|
38
|
+
- **Primary Moat**: Zero-runtime latency, SQLite-native trace indexing.
|
|
39
|
+
|
|
40
|
+
### Expected Execution & Checks
|
|
41
|
+
1. **Positioning Matrix**: Formulates statement: *For [engineering leaders] who [struggle with invisible agent regressions], [AgentTrace] is an [observability engine] that [indexes traces locally in SQLite with 0ms runtime overhead] unlike [Datadog/LangSmith]*.
|
|
42
|
+
2. **Phased Roadmap**:
|
|
43
|
+
- T-30 to T-15: Technical teardown blogs and waitlist alpha.
|
|
44
|
+
- T-14 to T-1: Private beta with 50 design partners.
|
|
45
|
+
- T-0: Product Hunt, Hacker News Show HN, and Twitter thread.
|
|
46
|
+
- T+1 to T+14: Onboarding case studies and customer referral loop.
|
|
47
|
+
3. **Checklist Validation**: Workflow satisfies 100% of `references/workflows/campaign-launch.md` checklist.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Scenario 3: 3-Stage Abandoned Cart Recovery Sequence (Egypt ๐ช๐ฌ)
|
|
52
|
+
|
|
53
|
+
### Objective
|
|
54
|
+
Build a culturally calibrated 3-email abandoned cart recovery flow for an Egyptian fashion brand utilizing local payment incentives (InstaPay, Cash on Delivery).
|
|
55
|
+
|
|
56
|
+
### Inputs & Context
|
|
57
|
+
- **Market**: Egypt (Cairo, Alexandria)
|
|
58
|
+
- **Currency**: EGP
|
|
59
|
+
- **Average Order Value**: 850 EGP
|
|
60
|
+
- **Tone**: Friendly, relatable, solution-oriented Egyptian Arabic.
|
|
61
|
+
|
|
62
|
+
### Expected Execution & Checks
|
|
63
|
+
1. **Flow Structure**:
|
|
64
|
+
- Email 1 (1 hour post-abandonment): Gentle reminder, photo of cart items, customer service WhatsApp link.
|
|
65
|
+
- Email 2 (24 hours post-abandonment): Overcoming objections, sizing guide, InstaPay instant discount.
|
|
66
|
+
- Email 3 (48 hours post-abandonment): Final urgency notice, reserving items for 12 hours.
|
|
67
|
+
2. **Quality Bar**: Free of generic translation artifacts; utilizes authentic Egyptian phrasing with clear CTAs.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Scenario 4: Direct-Response Ad Copy Multi-Angle Audit
|
|
72
|
+
|
|
73
|
+
### Objective
|
|
74
|
+
Generate 3 distinct psychological ad copy angles (Pain, ROI, Proof) and verify zero AI marketing clichรฉs via automated linter.
|
|
75
|
+
|
|
76
|
+
### Inputs & Context
|
|
77
|
+
- **Offer**: Fast-track web performance audit service.
|
|
78
|
+
- **Audience**: Agency owners and e-commerce founders.
|
|
79
|
+
|
|
80
|
+
### Expected Execution & Checks
|
|
81
|
+
1. **Angles Emitted**:
|
|
82
|
+
- Angle 1 (Pain): Frustration of paying high Meta ad spend while 60% bounce on slow mobile pages.
|
|
83
|
+
- Angle 2 (ROI/Logic): Every 100ms speed improvement raises conversion rate by 1.1%, recovering lost ad spend.
|
|
84
|
+
- Angle 3 (Social Proof): Before/after case study showing Lighthouse score 34 โ 98 and 2.4x ROAS increase.
|
|
85
|
+
2. **Linter Execution**:
|
|
86
|
+
- Runs `python scripts/audit_copy.py target.md --json`.
|
|
87
|
+
- Result: `passed: true`, `score: 100`, zero banned clichรฉs detected.
|
package/tools/build-skill.js
CHANGED