📦 deps(thirdparty): update snapshots
This commit is contained in:
+82
@@ -0,0 +1,82 @@
|
||||
"""
|
||||
generate_calendar.py — LinkedIn Content Calendar Prompt Builder
|
||||
|
||||
Usage:
|
||||
python generate_calendar.py --niche "<niche>" [--days <n>] [--frequency "<freq>"] [--goal <goal>]
|
||||
|
||||
Goal: awareness | engagement | leads | authority | growth
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
import os
|
||||
|
||||
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, SCRIPT_DIR)
|
||||
from utils import get_base_prompt_context
|
||||
|
||||
GOAL_GUIDE = {
|
||||
"awareness": "Maximise reach. Focus on shareable, relatable, trending content. Heavy on carousels and controversial takes.",
|
||||
"engagement": "Maximise comments. Focus on opinion posts, polls, questions, and storytelling.",
|
||||
"leads": "Generate DMs. Mix educational value posts with authority-building and clear CTAs to contact.",
|
||||
"authority": "Position as expert. Deep insights, data-backed posts, newsletter content, thought leadership.",
|
||||
"growth": "Grow followers fast. Mix viral formats (carousels, lists, contrarian) with high-value education.",
|
||||
}
|
||||
|
||||
FORMAT_MIX = {
|
||||
"Text Post": "Pure conversational text — personal story or insight",
|
||||
"Carousel": "Multi-slide document — educational or list-based",
|
||||
"Poll": "LinkedIn poll with 2-4 options — quick engagement spike",
|
||||
"Newsletter Link": "Teaser post linking to your newsletter edition",
|
||||
"Video Script": "Script outline for a talking-head video",
|
||||
"Image + Caption": "Strong visual with punchy caption",
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Generate a LinkedIn Content Calendar prompt")
|
||||
parser.add_argument("--niche", required=True)
|
||||
parser.add_argument("--days", required=False, type=int, default=30)
|
||||
parser.add_argument("--frequency", required=False, default="3 times a week")
|
||||
parser.add_argument("--goal", required=False, default="growth", choices=list(GOAL_GUIDE.keys()))
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
goal_instruction = GOAL_GUIDE.get(args.goal, GOAL_GUIDE["growth"])
|
||||
formats_list = "\n".join([f" - **{k}**: {v}" for k, v in FORMAT_MIX.items()])
|
||||
context = get_base_prompt_context(args.niche, "LinkedIn Content Calendar")
|
||||
|
||||
prompt = f"""{context}
|
||||
|
||||
<TASK>
|
||||
Generate a {args.days}-day LinkedIn Content Calendar for the "{args.niche}" niche.
|
||||
|
||||
**Posting Frequency**: {args.frequency}
|
||||
**Primary Goal**: {args.goal.upper()} — {goal_instruction}
|
||||
|
||||
Available formats (use a strategic mix):
|
||||
{formats_list}
|
||||
|
||||
For each post entry provide a Markdown table row:
|
||||
| # | Day | Format | Topic / Angle | Hook (First Line) | CTA |
|
||||
|
||||
Calendar rules:
|
||||
1. Never repeat the same format two days in a row
|
||||
2. For every 4 posts: 2 educational, 1 personal/story, 1 opinion/controversial
|
||||
3. Include at least 2 polls per month
|
||||
4. Space carousels and newsletters evenly across the month
|
||||
5. End each week with a reflection or motivational post
|
||||
|
||||
After the calendar table, provide:
|
||||
- 📌 **Monthly Theme**: One overarching narrative tying the month together
|
||||
- 🔑 **Top 5 SEO Keywords** to embed naturally across posts
|
||||
- 📊 **Format Breakdown**: e.g., "8 Text Posts, 5 Carousels, 3 Polls..."
|
||||
|
||||
Output as a clean Markdown table. Ready to copy into Notion or Google Sheets.
|
||||
</TASK>"""
|
||||
|
||||
print(prompt)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
"""
|
||||
generate_carousel.py — LinkedIn Carousel Prompt Builder
|
||||
|
||||
Usage:
|
||||
python generate_carousel.py --topic "<topic>" --niche "<niche>" [--slides <n>] [--style <style>]
|
||||
|
||||
Style: how-to | listicle | myth-busting | framework | story-arc
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
import os
|
||||
|
||||
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, SCRIPT_DIR)
|
||||
from utils import get_base_prompt_context
|
||||
|
||||
CAROUSEL_STYLES = {
|
||||
"how-to": "Step-by-step guide. Slide 1 = problem, slides 2-N = steps, last = result/CTA.",
|
||||
"listicle": "Curated list. Each slide = one item with bold title + 1-2 sentence explanation.",
|
||||
"myth-busting": "Each slide = one myth debunked. Format: 'MYTH: [belief]' → 'TRUTH: [reality]'.",
|
||||
"framework": "Introduce a proprietary framework. Each slide = one component of the framework.",
|
||||
"story-arc": "Transformation story. Slide 1 = before, middle = journey, last = after + CTA.",
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Generate a LinkedIn Carousel prompt")
|
||||
parser.add_argument("--topic", required=True)
|
||||
parser.add_argument("--niche", required=True)
|
||||
parser.add_argument("--slides", required=False, type=int, default=7)
|
||||
parser.add_argument("--style", required=False, default="listicle", choices=list(CAROUSEL_STYLES.keys()))
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
slides = max(3, min(args.slides, 12))
|
||||
style_instruction = CAROUSEL_STYLES.get(args.style, CAROUSEL_STYLES["listicle"])
|
||||
context = get_base_prompt_context(args.niche, "LinkedIn Carousel")
|
||||
|
||||
prompt = f"""{context}
|
||||
|
||||
<TASK>
|
||||
Generate a complete LinkedIn Carousel with exactly {slides} slides.
|
||||
|
||||
**Topic**: {args.topic}
|
||||
**Niche**: {args.niche}
|
||||
**Style**: {args.style.upper()} — {style_instruction}
|
||||
|
||||
Slide structure:
|
||||
- Slide 1 (Cover): Massive hook headline (max 8 words) + optional 1-sentence sub-headline
|
||||
- Slides 2–{slides-1}: Follow the "{args.style}" style. Bold Title + 2-3 lines per slide.
|
||||
- Slide {slides} (CTA): One clear action (e.g., "Follow for more", "Save this for later")
|
||||
|
||||
After the slides, provide:
|
||||
---
|
||||
📝 LinkedIn Caption:
|
||||
- Hook line (different wording from Slide 1, same energy)
|
||||
- 2-3 lines of teaser context
|
||||
- "Swipe to see all {slides} →"
|
||||
- 3-5 hashtags
|
||||
|
||||
Output slides numbered clearly. No extra commentary.
|
||||
</TASK>"""
|
||||
|
||||
print(prompt)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
"""
|
||||
generate_newsletter.py — LinkedIn Newsletter Prompt Builder
|
||||
|
||||
Usage:
|
||||
python generate_newsletter.py --topic "<topic>" --niche "<niche>" [--title "<title>"] [--length <length>]
|
||||
|
||||
Length: short (~700w) | medium (~1200w) | long (~2000w)
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
import os
|
||||
|
||||
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, SCRIPT_DIR)
|
||||
from utils import get_base_prompt_context
|
||||
|
||||
LENGTH_GUIDE = {
|
||||
"short": "~600-800 words. Quick, punchy, skimmable. 2-3 sections max.",
|
||||
"medium": "~1000-1400 words. Balanced depth and readability. 3-4 sections.",
|
||||
"long": "~1800-2500 words. Deep dive. 4-6 sections with subsections.",
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Generate a LinkedIn Newsletter prompt")
|
||||
parser.add_argument("--topic", required=True)
|
||||
parser.add_argument("--niche", required=True)
|
||||
parser.add_argument("--title", required=False, default="")
|
||||
parser.add_argument("--length", required=False, default="medium", choices=list(LENGTH_GUIDE.keys()))
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
length_instruction = LENGTH_GUIDE.get(args.length, LENGTH_GUIDE["medium"])
|
||||
title_line = f"**Newsletter Title**: {args.title}" if args.title else "**Newsletter Title**: Generate a compelling SEO-optimised headline."
|
||||
context = get_base_prompt_context(args.niche, "LinkedIn Newsletter Article")
|
||||
|
||||
prompt = f"""{context}
|
||||
|
||||
<TASK>
|
||||
Generate a complete LinkedIn Newsletter edition.
|
||||
|
||||
**Topic**: {args.topic}
|
||||
**Niche**: {args.niche}
|
||||
{title_line}
|
||||
**Length**: {args.length.upper()} — {length_instruction}
|
||||
|
||||
Required structure:
|
||||
1. Headline (H1) — catchy, SEO-optimised, keyword-rich
|
||||
2. Opening Hook — personal anecdote, surprising statistic, or bold claim (2-3 sentences)
|
||||
3. Body Sections (H2 subheadings) — background, insights, examples, data
|
||||
4. Key Takeaways — bulleted list (3-5 items)
|
||||
5. Action Step — 1 specific thing to do this week
|
||||
6. Engagement Question — ask 1 question to spark comments
|
||||
|
||||
Formatting: Markdown (H1, H2, H3, bold, bullets). Short paragraphs only.
|
||||
Output ONLY the final newsletter. No commentary.
|
||||
</TASK>"""
|
||||
|
||||
print(prompt)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,77 @@
|
||||
"""
|
||||
generate_post.py — LinkedIn Post Prompt Builder
|
||||
|
||||
Usage:
|
||||
python generate_post.py --topic "<topic>" --niche "<niche>" [--tone <tone>] [--style <style>]
|
||||
|
||||
Tone: professional | storytelling | controversial | educational | motivational
|
||||
Style: text-only | list-based | storytelling | data-driven | contrarian
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
import os
|
||||
|
||||
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, SCRIPT_DIR)
|
||||
from utils import get_base_prompt_context
|
||||
|
||||
TONE_GUIDE = {
|
||||
"professional": "Write with authority and expertise. Clear, polished, data-backed where possible.",
|
||||
"storytelling": "Lead with a personal story or narrative. Make the reader feel something before delivering the insight.",
|
||||
"controversial": "Take a bold, contrarian stance. Challenge the conventional wisdom in the niche. Prepare for debate.",
|
||||
"educational": "Break down a complex concept simply. Use analogies, numbered steps, or mini-frameworks.",
|
||||
"motivational": "Inspire and energize. Use strong action verbs. Make the reader feel capable and driven.",
|
||||
}
|
||||
|
||||
STYLE_GUIDE = {
|
||||
"text-only": "Write as flowing text paragraphs. No bullet points. Pure conversational prose.",
|
||||
"list-based": "Structure the core value as a numbered or bulleted list. Maximum 7 items.",
|
||||
"storytelling":"Write as a narrative arc: Setup → Conflict → Resolution → Lesson.",
|
||||
"data-driven": "Anchor every key point with a statistic, study, or concrete example.",
|
||||
"contrarian": "Start by stating what everyone believes, then flip it. Use 'But here's what they miss:' or similar.",
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Generate a LinkedIn Post prompt")
|
||||
parser.add_argument("--topic", required=True)
|
||||
parser.add_argument("--niche", required=True)
|
||||
parser.add_argument("--tone", required=False, default="professional", choices=list(TONE_GUIDE.keys()))
|
||||
parser.add_argument("--style", required=False, default="list-based", choices=list(STYLE_GUIDE.keys()))
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
tone_instruction = TONE_GUIDE.get(args.tone, TONE_GUIDE["professional"])
|
||||
style_instruction = STYLE_GUIDE.get(args.style, STYLE_GUIDE["list-based"])
|
||||
context = get_base_prompt_context(args.niche, "LinkedIn Text Post")
|
||||
|
||||
prompt = f"""{context}
|
||||
|
||||
<TASK>
|
||||
Generate a single, ready-to-publish LinkedIn post.
|
||||
|
||||
**Topic**: {args.topic}
|
||||
**Niche**: {args.niche}
|
||||
**Tone**: {tone_instruction}
|
||||
**Style**: {style_instruction}
|
||||
|
||||
Mandatory output structure:
|
||||
1. Hook (2 lines — scroll-stopping)
|
||||
2. [blank line]
|
||||
3. Body (follow tone + style instructions)
|
||||
4. [blank line]
|
||||
5. Key Takeaway (1-2 punchy sentences)
|
||||
6. [blank line]
|
||||
7. CTA (specific, value-driven)
|
||||
8. [blank line]
|
||||
9. Hashtags (3-5 only)
|
||||
|
||||
Output ONLY the final post. No preamble. Ready to paste into LinkedIn.
|
||||
</TASK>"""
|
||||
|
||||
print(prompt)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,49 @@
|
||||
# LinkedIn Content Memory
|
||||
|
||||
This file is the reinforcement learning database for the LinkedIn Content Skill.
|
||||
It is automatically read by every generator script to personalise your content.
|
||||
Use `/feedback` to update it. Use `/show-memory` to review it.
|
||||
|
||||
---
|
||||
|
||||
## 🧠 Core Identity & Tone
|
||||
- **Primary Niche:** (Update this — e.g. "AI & Technology", "Marketing", "SaaS")
|
||||
- **Tone:** Professional, insightful, concise, and story-driven.
|
||||
- **Voice:** First-person. Confident but humble. Write to one person, not an audience.
|
||||
- **Formatting Preference:** Short paragraphs (1-2 sentences). Aggressive line breaks. Bullet points over dense paragraphs.
|
||||
- **Emojis:** Use sparingly — 2-3 max per post, only where they genuinely add value.
|
||||
- **CTA Style:** Specific and value-driven. Never "like and share" — always give a reason.
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Successful Hooks
|
||||
> Add hooks that received high engagement here.
|
||||
- (Empty — use `/feedback` to add your first successful hook)
|
||||
|
||||
---
|
||||
|
||||
## 📈 Top Performing Formats
|
||||
> Note which content formats get the best reactions.
|
||||
- (Empty — use `/feedback` to log your best performing format)
|
||||
|
||||
---
|
||||
|
||||
## 🔑 High-Performing Topics
|
||||
> Track which topics resonate most with your audience.
|
||||
- (Empty — use `/feedback` to log topics that hit well)
|
||||
|
||||
---
|
||||
|
||||
## 🚫 What to Avoid
|
||||
> Patterns, phrases, or formats that underperformed.
|
||||
- Avoid cliché openers like "In today's fast-paced world..."
|
||||
- Avoid posting without a clear CTA
|
||||
- Avoid hashtag stuffing (max 5)
|
||||
|
||||
---
|
||||
|
||||
## 📝 Positive Feedback Log
|
||||
|
||||
### [2026-06-01 21:58] — test-01
|
||||
- **What worked:** Great hook!
|
||||
- **Tags:** `hook`
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
"""
|
||||
memory_manager.py — Reinforcement Learning Memory Manager for LinkedIn Content Skill.
|
||||
Resolves memory.md relative to this script's location (inside .claude/skills/scripts/).
|
||||
|
||||
Commands:
|
||||
python memory_manager.py add --id <id> --feedback <text> [--tags <tags>]
|
||||
python memory_manager.py read
|
||||
python memory_manager.py clear
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from datetime import datetime
|
||||
|
||||
# ─── Configuration ────────────────────────────────────────────────────────────
|
||||
|
||||
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
MEMORY_FILE = os.path.join(SCRIPT_DIR, "memory.md")
|
||||
|
||||
MEMORY_TEMPLATE = """# LinkedIn Content Memory
|
||||
|
||||
This file is the reinforcement learning database for the LinkedIn Content Skill.
|
||||
It is automatically read by every generator script to personalise your content.
|
||||
Use `/feedback` to update it. Use `/show-memory` to review it.
|
||||
|
||||
---
|
||||
|
||||
## 🧠 Core Identity & Tone
|
||||
- **Primary Niche:** (Update this — e.g. "AI & Technology", "Marketing", "SaaS")
|
||||
- **Tone:** Professional, insightful, concise, and story-driven.
|
||||
- **Voice:** First-person. Confident but humble. Write to one person, not an audience.
|
||||
- **Formatting Preference:** Short paragraphs (1-2 sentences). Aggressive line breaks. Bullet points over dense paragraphs.
|
||||
- **Emojis:** Use sparingly — 2-3 max per post, only where they genuinely add value.
|
||||
- **CTA Style:** Specific and value-driven. Never "like and share" — always give a reason.
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Successful Hooks
|
||||
> Add hooks that received high engagement here.
|
||||
- (Empty — use `/feedback` to add your first successful hook)
|
||||
|
||||
---
|
||||
|
||||
## 📈 Top Performing Formats
|
||||
> Note which content formats get the best reactions.
|
||||
- (Empty — use `/feedback` to log your best performing format)
|
||||
|
||||
---
|
||||
|
||||
## 🔑 High-Performing Topics
|
||||
> Track which topics resonate most with your audience.
|
||||
- (Empty — use `/feedback` to log topics that hit well)
|
||||
|
||||
---
|
||||
|
||||
## 🚫 What to Avoid
|
||||
> Patterns, phrases, or formats that underperformed.
|
||||
- Avoid cliché openers like "In today's fast-paced world..."
|
||||
- Avoid posting without a clear CTA
|
||||
- Avoid hashtag stuffing (max 5)
|
||||
|
||||
---
|
||||
|
||||
## 📝 Positive Feedback Log
|
||||
"""
|
||||
|
||||
|
||||
def ensure_memory_exists():
|
||||
if not os.path.exists(MEMORY_FILE):
|
||||
with open(MEMORY_FILE, "w", encoding="utf-8") as f:
|
||||
f.write(MEMORY_TEMPLATE)
|
||||
|
||||
|
||||
def read_memory() -> str:
|
||||
ensure_memory_exists()
|
||||
with open(MEMORY_FILE, "r", encoding="utf-8") as f:
|
||||
return f.read()
|
||||
|
||||
|
||||
def append_feedback(content_id: str, feedback_text: str, tags: str = ""):
|
||||
ensure_memory_exists()
|
||||
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M")
|
||||
entry = f"\n### [{timestamp}] — {content_id}\n"
|
||||
entry += f"- **What worked:** {feedback_text}\n"
|
||||
if tags:
|
||||
entry += f"- **Tags:** `{tags.strip()}`\n"
|
||||
|
||||
with open(MEMORY_FILE, "a", encoding="utf-8") as f:
|
||||
f.write(entry)
|
||||
|
||||
print(json.dumps({
|
||||
"status": "success",
|
||||
"message": f"✅ Memory updated in {MEMORY_FILE}",
|
||||
"entry_id": content_id,
|
||||
"timestamp": timestamp,
|
||||
"instruction": "This feedback will now be injected into all future content generation prompts."
|
||||
}, indent=2))
|
||||
|
||||
|
||||
def clear_memory():
|
||||
with open(MEMORY_FILE, "w", encoding="utf-8") as f:
|
||||
f.write(MEMORY_TEMPLATE)
|
||||
print(json.dumps({
|
||||
"status": "success",
|
||||
"message": "✅ Memory has been cleared and reset to defaults."
|
||||
}, indent=2))
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="LinkedIn Content Skill — Memory Manager")
|
||||
subparsers = parser.add_subparsers(dest="command", required=True)
|
||||
|
||||
add_parser = subparsers.add_parser("add", help="Save positive feedback to memory")
|
||||
add_parser.add_argument("--id", required=True)
|
||||
add_parser.add_argument("--feedback", required=True)
|
||||
add_parser.add_argument("--tags", required=False, default="")
|
||||
|
||||
subparsers.add_parser("read", help="Display current memory")
|
||||
subparsers.add_parser("clear", help="Reset memory to defaults")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.command == "add":
|
||||
append_feedback(args.id, args.feedback, args.tags)
|
||||
elif args.command == "read":
|
||||
print(read_memory())
|
||||
elif args.command == "clear":
|
||||
clear_memory()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,96 @@
|
||||
"""
|
||||
utils.py — Shared prompt-building utilities for the LinkedIn Content Skill.
|
||||
Reads the user's reinforcement learning memory from memory.md (same directory)
|
||||
and constructs richly engineered system prompts for Claude to consume.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Always resolve paths relative to THIS script's location (inside scripts/)
|
||||
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
MEMORY_FILE = os.path.join(SCRIPT_DIR, "memory.md")
|
||||
|
||||
# ─── LinkedIn SEO Rules ───────────────────────────────────────────────────────
|
||||
|
||||
LINKEDIN_SEO_RULES = """
|
||||
## LinkedIn SEO & Content Rules (MANDATORY — Follow Exactly)
|
||||
|
||||
### Hook Engineering (Most Critical)
|
||||
- Line 1 MUST be a scroll-stopping hook. Use one of these proven formats:
|
||||
a) Bold contrarian statement: "Most LinkedIn advice is wrong. Here's why."
|
||||
b) Surprising statistic: "95% of LinkedIn posts get fewer than 100 views. Here's the 5% secret."
|
||||
c) Provocative question: "What if everything you knew about personal branding was backwards?"
|
||||
d) Personal story opener: "3 years ago, I had 47 LinkedIn followers. Here's what changed."
|
||||
- Line 2 MUST create a pattern interrupt — force the reader to click "see more"
|
||||
- NEVER start with: "In today's...", "I am excited to...", "Happy to share...", "Thrilled to announce..."
|
||||
|
||||
### Content Structure
|
||||
- Hook (2 lines, must not trigger "see more" cutoff)
|
||||
- [blank line]
|
||||
- Context/Problem (2-3 short sentences max)
|
||||
- [blank line]
|
||||
- Core Value (use numbered lists or bullets — max 7 items)
|
||||
- [blank line]
|
||||
- Key Takeaway (1-2 punchy sentences)
|
||||
- [blank line]
|
||||
- Call to Action (1 specific, non-generic CTA)
|
||||
- [blank line]
|
||||
- Hashtags (3-5 only — mix broad + niche)
|
||||
|
||||
### Readability Rules
|
||||
- Maximum 2 sentences per paragraph
|
||||
- Use line breaks aggressively — white space wins on LinkedIn
|
||||
- Bold sparingly, only for truly critical points
|
||||
- Sentences: short, punchy, declarative. Vary rhythm.
|
||||
- Reading level: Grade 8 or below
|
||||
|
||||
### Tone & Voice
|
||||
- Write like you're talking to ONE person, not an audience
|
||||
- Use "you" and "I" — personal, not corporate
|
||||
- Confident, not arrogant. Helpful, not preachy.
|
||||
- Zero jargon unless explaining it is the point
|
||||
|
||||
### Hashtag Strategy
|
||||
- 1 broad hashtag (#AI, #Marketing, #Leadership)
|
||||
- 2 niche hashtags (#AIAgents, #ContentMarketing, #StartupLife)
|
||||
- 1-2 community hashtags (#LinkedInTips, #PersonalBranding)
|
||||
- Total: NEVER more than 5
|
||||
"""
|
||||
|
||||
|
||||
def read_memory() -> str:
|
||||
"""Read and return the full contents of memory.md."""
|
||||
if not os.path.exists(MEMORY_FILE):
|
||||
return "No memory found. Use /feedback to start building personalised memory."
|
||||
with open(MEMORY_FILE, "r", encoding="utf-8") as f:
|
||||
return f.read()
|
||||
|
||||
|
||||
def get_base_prompt_context(niche: str, content_type: str) -> str:
|
||||
"""
|
||||
Build a complete system prompt context for the AI.
|
||||
Injects LinkedIn SEO rules + the user's personal reinforcement learning memory.
|
||||
"""
|
||||
memory_context = read_memory()
|
||||
|
||||
prompt = f"""<SYSTEM_INSTRUCTION>
|
||||
You are an elite LinkedIn Content Strategist and Copywriter working for a specific user.
|
||||
Your task is to generate a world-class {content_type} for the niche: "{niche}".
|
||||
|
||||
{LINKEDIN_SEO_RULES}
|
||||
|
||||
## User's Personal Memory & Preferences (HIGHEST PRIORITY)
|
||||
The following reinforcement learning memory reflects what has worked for this user.
|
||||
You MUST prioritize and replicate these patterns in your output:
|
||||
|
||||
<MEMORY>
|
||||
{memory_context}
|
||||
</MEMORY>
|
||||
|
||||
If memory contains specific hooks, tones, or formats that worked well — USE THEM as inspiration.
|
||||
If memory is empty — default to the SEO rules above and high-performing LinkedIn best practices.
|
||||
|
||||
</SYSTEM_INSTRUCTION>"""
|
||||
|
||||
return prompt
|
||||
Reference in New Issue
Block a user