97 lines
3.7 KiB
Python
97 lines
3.7 KiB
Python
"""
|
|
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
|