Generate content in your authentic voice across emails, blogs, social media, and reports
Generates content in your authentic voice by learning from your writing samples across emails, blogs, and social media. Use when you need to write emails, posts, or reports that sound like you, not generic AI.
/plugin marketplace add krishagel/geoffrey/plugin install geoffrey@geoffreyThis skill is limited to using the following tools:
README.mdscripts/README.mdscripts/extract-blog-samples.jsscripts/extract-email-samples.jsscripts/extract-social-samples.jstemplates/interview-questions.jsontemplates/voice-profile-template.jsonGenerate content in your authentic voice by analyzing writing samples and applying learned voice patterns through adaptive interviewing and voice-matched generation.
Key Innovation: This isn't a generic AI writer - it's YOUR voice, learned from YOUR writing.
Unlike generic AI content generation, this skill:
Simplicity: Geoffrey's native LLM capabilities analyze your voice. Scripts just fetch samples. No complex NLP libraries - clean, maintainable architecture.
Use this skill when you need to:
DON'T use for:
Six distinct profiles capture different contexts:
| Profile | Source | Sample Target | Status |
|---|---|---|---|
email_work | PSD Gmail (sent emails, 6mo) | 50+ emails | Check writing-voice.json |
email_personal | Personal/HRG Gmail (sent, 6mo) | 50+ emails | Check writing-voice.json |
blog_technical | psd401.ai + blog.krishagel.com | 10+ posts | Check writing-voice.json |
social_linkedin | LinkedIn profile posts | 30+ posts | Check writing-voice.json |
social_twitter | X/Twitter posts | 30+ posts | Check writing-voice.json |
report_formal | User-provided samples | 5-10 reports | Check writing-voice.json |
Confidence Levels:
Goal: Load the right voice profile and verify it's ready
Process:
Detect content type from user request:
email_work or email_personal (ask which)blog_technicalsocial_linkedinsocial_twitterreport_formalLoad voice profile:
cat ~/Library/Mobile\ Documents/com~apple~CloudDocs/Geoffrey/knowledge/writing-voice.json
Check confidence and sample count:
Low Confidence Response:
Only {sample_count} {content_type} samples (confidence: {confidence}).
Target: {target_samples}+ samples for 0.85+ confidence.
Options:
1. Gather more samples (recommended)
2. Use {alternative_profile} voice as proxy (confidence: {alt_confidence})
3. Proceed anyway (may not fully match your voice)
Preference?
Checkpoint 1: User confirms profile or gathers more samples
Goal: Deeply understand what you want to communicate
Process:
Load interview questions from templates/interview-questions.json
Adapt depth to content type:
Interview like a journalist:
Email Interview Example (complex):
1. Who are the recipient(s) and what's the context?
→ [User answers]
2. What's the primary goal?
→ [User answers]
[If vague: "Can you be more specific about the outcome you want?"]
3. What background do they need?
→ [User answers]
4. What are the key points? (Max 3-5)
→ [User answers]
[If >5: "Let's focus on the most critical 3-5 points."]
... continue through 8 questions
Blog Interview Example:
1. What's your central message?
2. Why does this matter right now?
3. What should readers do/think/feel after?
4. What evidence supports this?
5. Any stories or case studies?
6. Main counterarguments?
7. How should it open?
8. Key sections (3-5)?
9. How should it close?
10. Primary audience and technical level?
11. Desired tone?
Checkpoint 2: Review interview summary, add missing details
Goal: Create a clear structure before writing
Process:
Create outline based on:
Apply voice-specific patterns:
Suggest length from profile:
Email Outline Example:
## Email Plan
**Subject**: [Based on purpose]
**Opening**: [Use opening pattern from profile, e.g., "I've reviewed {topic}..."]
**Body**:
- Point 1: [From interview]
- Point 2: [From interview]
- Point 3: [From interview]
**Ask**: [Specific call-to-action from interview]
**Closing**: [Use closing pattern from profile, e.g., "Let me know if..."]
**Tone**: Direct, professional, action-oriented
**Length**: ~200 words (typical for email_work)
Blog Outline Example:
## Blog Plan
**Title**: [Derived from central message]
**Structure**:
1. Opening: [Hook strategy - context-setting or reflective quote]
2. Background & Context
3. [Main section 1]
4. [Main section 2]
5. [Main section 3]
6. Impact & Results
7. Closing: [Forward-looking reflection]
**Voice elements**:
- Staff quotes (use throughout)
- Chronological narrative flow
- Subheadings for scannability
- Accessible but authoritative tone
**Length**: ~850 words (typical for blog_technical)
Checkpoint 3: User approves outline
Goal: Write content that authentically sounds like you
Process:
Load identity context:
cat ~/Library/Mobile\ Documents/com~apple~CloudDocs/Geoffrey/knowledge/identity-core.json
Use for personality alignment:
communication_preferences.style → Direct, no-nonsense, concisedecision_framework → Analytical, evidence-basedtelos_summary.top_3_values → Equity, excellence, empathyApply voice characteristics as generation guidelines:
voice_characteristics.tonevoice_characteristics.sentence_structureopening_patternsclosing_patternsWrite content naturally:
Reference example emails/posts from profile for inspiration
Generation Approach (Hybrid):
Goal: Ensure draft authentically matches your voice
Native LLM Validation (no script needed):
Geoffrey self-validates by comparing draft to voice profile:
voice_characteristics + examples)Scoring criteria (weighted):
Identify specific deviations:
Scoring thresholds:
Refinement (if score < 85):
Voice Validation: {score}/100
Issues:
- {Issue 1 with specific evidence}
- {Issue 2 with specific evidence}
- {Issue 3 with specific evidence}
Should I refine to better match your voice?
If user approves refinement:
Checkpoint 4: User accepts, requests refinement, or manually edits
Goal: Save draft to Obsidian with proper versioning
Process:
Determine file path:
~/Library/Mobile Documents/iCloud~md~obsidian/Documents/Personal_Notes/Geoffrey/Writing/{ContentType}/{date}-{slug}.md
Content types:
Geoffrey/Writing/Blog/Geoffrey/Writing/Email/Geoffrey/Writing/Social/Geoffrey/Writing/Reports/Generate frontmatter:
---
created: 2025-12-06
type: blog
profile: blog_technical
topic: AI implementation
status: draft
version: 1.0
validation_score: 87
word_count: 847
tags: [geoffrey, writing, ai]
source: geoffrey-writer
interview_date: 2025-12-06
---
Save file using Obsidian MCP tools:
mcp__obsidian-vault__create_vault_file
Also return text directly (copy-paste ready)
Offer to open in Obsidian:
mcp__obsidian-vault__show_file_in_obsidian
Versioning:
version: 1.0version: 1.1, 1.2version: 2.0Output to user:
## Draft Complete
**Validation Score**: 87/100 ✓
**Word Count**: 847
**Profile**: blog_technical
**Saved to**: Geoffrey/Writing/Blog/2025-12-06-ai-implementation.md
[Full draft text here]
Actions:
1. Open in Obsidian
2. Request refinements
3. Mark as final
Required: Gather writing samples for each profile you'll use
Step 1: Email Samples (3 accounts)
# PSD work emails
bun scripts/extract-email-samples.js \
--account psd \
--date-range "2024-06-01:2025-12-06" \
--max-samples 100 \
--output "/tmp/email-samples-psd.json"
# Personal emails
bun scripts/extract-email-samples.js \
--account kh \
--date-range "2024-06-01:2025-12-06" \
--max-samples 50 \
--output "/tmp/email-samples-kh.json"
# Business/consulting emails
bun scripts/extract-email-samples.js \
--account hrg \
--date-range "2024-06-01:2025-12-06" \
--max-samples 50 \
--output "/tmp/email-samples-hrg.json"
Step 2: Blog Samples
# Launch Geoffrey Chrome (for personal blog access)
cd ~/non-ic-code/geoffrey/skills/browser-control
./scripts/launch-chrome.sh
# Extract blog posts
cd ~/non-ic-code/geoffrey/skills/writer
bun scripts/extract-blog-samples.js \
--urls "https://psd401.ai/blog/stanford-ai-tinkery-2025,https://psd401.ai/blog/why-this-website,https://blog.krishagel.com/post1,https://blog.krishagel.com/post2" \
--output "/tmp/blog-samples.json"
Step 3: Social Media Samples (requires login)
# IMPORTANT: Manually log into LinkedIn and X in Geoffrey Chrome first
# LinkedIn
bun scripts/extract-social-samples.js \
--platform linkedin \
--profile-url "https://linkedin.com/in/krishagel" \
--max-posts 50 \
--output "/tmp/social-linkedin.json"
# Twitter/X
bun scripts/extract-social-samples.js \
--platform twitter \
--profile-url "https://x.com/KrisHagel" \
--max-posts 50 \
--output "/tmp/social-twitter.json"
Step 4: Geoffrey Analyzes
Tell Geoffrey:
Analyze my writing samples and create voice profiles.
Email samples: /tmp/email-samples-psd.json, /tmp/email-samples-kh.json, /tmp/email-samples-hrg.json
Blog samples: /tmp/blog-samples.json
Social samples: /tmp/social-linkedin.json, /tmp/social-twitter.json
Geoffrey will:
writing-voice.json:
~/Library/Mobile Documents/com~apple~CloudDocs/Geoffrey/knowledge/writing-voice.json
Estimated time: 30-45 min initial setup
When: Phase 4 (Draft Generation)
Purpose: Ensure voice reflects personality (analytical, direct, impact-driven)
How:
cat ~/Library/Mobile\ Documents/com~apple~CloudDocs/Geoffrey/knowledge/identity-core.json
Use:
communication_preferences → Tone, style, dislikesdecision_framework → Analytical, evidence-based approachtelos_summary → Values (equity, excellence, empathy), missionstrengths_essence → Input (collector), Significance (impact), AnalyticalWhen: Initial voice creation + quarterly refresh
Scripts: search_messages.js, read_message.js
Process:
When: Initial voice creation + ad-hoc updates
Prerequisites: Geoffrey Chrome running with logins
Process:
When: Phase 6 (Storage)
Folder structure:
Geoffrey/Writing/
├── Blog/
├── Email/
├── Social/
└── Reports/
File format: YYYY-MM-DD-{slug}.md with frontmatter
Scenario: User requests email, but only 12 samples (confidence 0.62)
Response:
Only 12 email_work samples (0.62 confidence). Target: 50+ for 0.85+ confidence.
Options:
1. Gather ~40 more email samples from recent sent (recommended)
2. Use email_personal as proxy (if similar, confidence: 0.88)
3. Proceed with low confidence (may not fully match your voice)
Note: Voice profiles improve with more samples. I can still write, but authenticity may vary.
Preference?
Scenario: Profile last updated 18 months ago
Detection: Check last_updated in writing-voice.json
Response:
Your email_work profile is 18 months old (last updated: 2024-06-15).
Writing styles evolve over time.
Recommendation: Refresh with recent samples (past 6 months)
Run:
bun scripts/extract-email-samples.js --account psd --date-range "2024-06-01:2025-12-06" --max-samples 100 --output "/tmp/email-refresh.json"
Then ask me to analyze and update the profile.
Proceed with current profile or refresh first?
Scenario: Email samples vary significantly (45% formal, 35% casual, 20% mixed)
Geoffrey analyzes and responds:
Your email_work voice varies significantly across samples:
- 45% formal (board, superintendent, external)
- 35% casual (staff, peers, project teams)
- 20% mixed
Options:
1. Split into email_work_formal and email_work_casual profiles
2. Choose dominant style (formal) as default
3. Let me dynamically adjust based on recipient (you specify each time)
Preference?
Scenario: Draft scores 62/100
Response:
Voice Validation: 62/100 ⚠️
Issues:
- Tone too formal (target: direct, action-oriented)
Example: "It would be appreciated if you could consider..." vs typical "Please review and confirm."
- Sentences 35% longer (avg 19 words vs typical 14)
Example: Draft paragraph 2 avg 21 words, your emails avg 14 words.
- Missing bullet points (you use bullets 67% of the time for key points)
Draft uses prose for 5 key points, you typically bullet them.
Should I refine to better match your voice?
Scenario: User requests "write a press release"
Response:
I don't have a press_release voice profile yet.
Options:
1. Use report_formal profile as starting point (confidence: 0.83)
2. Provide 5-10 past press releases for me to analyze
3. Write without voice matching (generic professional press release style)
Note: If you provide samples, I can create a new press_release profile.
Preference?
User: "Write email to my team about next week's leadership meeting"
Geoffrey:
I'll use your email_work profile (confidence: 0.92, 156 samples).
Quick interview (4 questions):
1. Who's the team and what's your relationship?
→ [User: Direct reports - IT leadership team]
2. Purpose? (inform, request, respond, update)
→ [User: Inform and request prep]
3. Key information?
→ [User: Meeting Tuesday 2pm, agenda items: budget, staffing, AI roadmap. Need their input on AI priorities.]
4. Tone?
→ [User: Professional but casual - these are my directs]
[Generates outline] → User approves
[Generates draft, validates (score: 89), presents to user]
User: "Write blog post about our AI implementation journey"
Geoffrey:
I'll use your blog_technical profile (confidence: 0.78, 4 samples).
Note: Only 4 blog samples. Recommend 6+ more for 0.85+ confidence.
Proceed or gather more samples first?
→ [User: Proceed]
Standard interview (11 questions):
1. Central message?
→ [User: ...]
2. Why now?
→ [User: ...]
[... continues through 11 questions ...]
[Creates detailed outline] → User approves
[Generates ~850 word draft with staff quotes, chronological flow, reflective close]
[Validates (score: 87), presents draft]
[Saves to Geoffrey/Writing/Blog/2025-12-06-ai-implementation-journey.md]
User: "LinkedIn post about Stanford AI Tinkery visit"
Geoffrey:
I'll use your social_linkedin profile (confidence: 0.91, 48 posts).
Quick interview (5 questions):
1. Main point (1-2 sentences)?
→ [User: Visited Stanford's AI Tinkery with district team. Collaborative learning happening everywhere, not just at elite institutions.]
2. Target audience?
→ [User: Ed tech leaders, superintendents]
3. Tone?
→ [User: Inspirational, reflective]
4. Call-to-action?
→ [User: Encourage others to build their own learning networks]
5. Link or visual?
→ [User: No link, maybe photo but I'll add later]
[Generates ~180 word LinkedIn post]
[Validates (score: 92), presents]
Sample Dependency: Voice quality directly tied to sample quantity and quality
Voice Drift: Styles evolve over time
New Contexts: No profile for content types you haven't written before
Platform Nuances: Social media scraping limitations
Multilingual: Currently English only
Collaborative Writing: Single voice only
Quantitative:
Qualitative:
Before presenting draft:
Cause: writing-voice.json doesn't exist or profile type missing
Solution:
cat ~/Library/Mobile\ Documents/com~apple~CloudDocs/Geoffrey/knowledge/writing-voice.json
Cause: Fewer than 20 samples for profile
Solution:
Cause: Social/blog extraction requires Geoffrey Chrome with remote debugging
Solution:
cd ~/non-ic-code/geoffrey/skills/browser-control
./scripts/launch-chrome.sh
Cause: Not logged into LinkedIn/X, or selectors changed
Solution:
Applies Anthropic's official brand colors and typography to any sort of artifact that may benefit from having Anthropic's look-and-feel. Use it when brand colors or style guidelines, visual formatting, or company design standards apply.
Create beautiful visual art in .png and .pdf documents using design philosophy. You should use this skill when the user asks to create a poster, piece of art, design, or other static piece. Create original visual designs, never copying existing artists' work to avoid copyright violations.
Guide users through a structured workflow for co-authoring documentation. Use when user wants to write documentation, proposals, technical specs, decision docs, or similar structured content. This workflow helps users efficiently transfer context, refine content through iteration, and verify the doc works for readers. Trigger when user mentions writing docs, creating proposals, drafting specs, or similar documentation tasks.