Skill: dylanbaker24/linkedin-inbox (version 0.1.0)

--- name: linkedin-inbox description: LinkedIn inbox management with scheduled scanning, auto-draft responses following user's communication style, and approval workflows. Use when monitoring LinkedIn messages, drafting replies, managing inbox during off-hours, or setting up morning ping summaries of LinkedIn activity. --- # LinkedIn Inbox Manager Automated LinkedIn inbox monitoring with human-in-the-loop approval for responses. Uses Peekaboo for UI automation (no API rate limits, works with any LinkedIn account). ## Requirements - macOS with Peekaboo CLI installed (`brew install steipete/tap/peekaboo`) - Screen Recording + Accessibility permissions granted - LinkedIn logged in via browser (Chrome recommended) - Clawdbot with browser capability ## Quick Start ### 1. One-time Setup ```bash # Grant Peekaboo permissions peekaboo permissions # Verify LinkedIn is accessible peekaboo app launch "Google Chrome" peekaboo see --app "Google Chrome" --annotate --path /tmp/linkedin-check.png ``` ### 2. Configure User Style Create `linkedin-inbox-config.json` in your workspace: ```json { "scan": { "intervalMinutes": 60, "activeHours": { "start": 9, "end": 18, "timezone": "America/Los_Angeles" }, "skipWeekends": true }, "drafting": { "styleProfile": "USER.md", "templates": { "decline": "Thanks for reaching out. Not a fit for us right now, but best of luck.", "interested": "This looks interesting. Happy to chat more. What's your availability?", "referral": "I might know someone. Let me check and get back to you." } }, "notifications": { "channel": "discord", "target": "#linkedin" } } ``` ### 3. Start Monitoring Tell your agent: "Start LinkedIn inbox monitoring" or add to HEARTBEAT.md: ```markdown - Check LinkedIn inbox if last scan >1 hour ago ``` ## Core Workflow ### Scan Inbox ```bash # Navigate to LinkedIn messaging peekaboo app launch "Google Chrome" peekaboo menu click --app "Google Chrome" --item "New Tab" peekaboo type "https://www.linkedin.com/messaging/" --return sleep 3 # Capture inbox state peekaboo see --app "Google Chrome" --window-title "Messaging" --annotate --path /tmp/linkedin-inbox.png ``` The agent reads the annotated screenshot to identify: - Unread messages (bold names, blue dots) - Message previews - Sender names and titles ### Draft Responses For each unread message: 1. Agent reads the conversation 2. Classifies intent (pitch, networking, job inquiry, spam) 3. Drafts response matching user's communication style 4. Posts draft to notification channel for approval Example notification: ``` 💼 LinkedIn: New message from **Alex M.** (Founder @ SomeCompany) Preview: "Hi, I noticed you're growing and wondered if..." **My read:** Services pitch. Doesn't fit current needs. **Draft reply:** > Thanks for reaching out. We're set on that side for now, but I'll keep you in mind if that changes. React ✅ to send, ❌ to skip, or reply with edits. ``` ### Send Approved Messages On approval: ```bash # Click into conversation peekaboo click --on [message-element-id] --app "Google Chrome" sleep 1 # Type response peekaboo type "Your approved message here" --app "Google Chrome" # Send (Enter or click Send button) peekaboo press return --app "Google Chrome" ``` ## Communication Style Matching The skill reads `USER.md` (or configured style file) to match the user's tone: **Extract these signals:** - Formality level (casual vs professional) - Typical greeting style - Sign-off patterns - Sentence length preference - Banned words/phrases - Response length norms **Apply to drafts:** - Mirror detected patterns - Use user's vocabulary - Match their directness level - Respect their guardrails (no "excited", no hype, etc.) See `references/style-extraction.md` for detailed guidance. ## Morning Ping Integration Add LinkedIn summary to your morning ping: ```markdown 📣 The Morning Ping — Monday, Jan 27 **LinkedIn:** • 💚 Sarah Chen replied — "That sounds great, let's do Thursday" → Draft ready • 💚 Mike R. replied — "Not interested right now" → No action needed • 📩 3 new connection requests (2 sales pitches, 1 relevant) • 📩 1 unread message from Alex (job inquiry) → Draft ready Reply "send sarah" to approve, "skip mike" to archive. ``` ## Approval Commands Users can respond with: - `send [name]` - Send the drafted reply - `send all` - Send all pending drafts - `skip [name]` - Archive without replying - `edit [name]: [new message]` - Replace draft and send - `show [name]` - Show full conversation ## Scheduled Scanning ### Via Cron (Recommended) ```json { "schedule": "0 */2 9-18 * * 1-5", "text": "Scan LinkedIn inbox and post any new messages to #linkedin with draft replies" } ``` ### Via Heartbeat In HEARTBEAT.md: ```markdown - If 9am-6pm PT and last LinkedIn scan >60min: scan inbox, draft replies, post to #linkedin ``` ## Safety Rules 1. **Never send without explicit approval** - Always wait for user confirmation 2. **Rate limit actions** - Max 20 LinkedIn actions per hour 3. **Respect quiet hours** - Don't scan outside configured activeHours 4. **Log everything** - Record all actions in daily memory file 5. **Preserve originals** - Never delete messages, only archive ## Troubleshooting ### "Can't find messaging UI" - Ensure Chrome is open with LinkedIn logged in - Check window title matches (may vary by language) - Use `peekaboo list windows --app "Google Chrome" --json` to debug ### "Session expired" - LinkedIn sessions expire periodically - Re-authenticate manually in browser - Skill will detect login page and notify user ### "Peekaboo permissions denied" ```bash peekaboo permissions # Check status # Grant via System Preferences > Privacy & Security > Screen Recording + Accessibility ``` ## Files - `scripts/scan_inbox.sh` - Peekaboo commands for inbox capture - `scripts/send_message.sh` - Peekaboo commands for sending - `references/style-extraction.md` - Guide for communication style matching

path: config-example.json
content: {
  "scan": {
    "intervalMinutes": 60,
    "activeHours": {
      "start": 9,
      "end": 18,
      "timezone": "America/Los_Angeles"
    },
    "skipWeekends": true,
    "browser": "Google Chrome"
  },
  "drafting": {
    "styleProfile": "USER.md",
    "autoClassify": true,
    "templates": {
      "decline_pitch": "Thanks for reaching out. Not a fit for us right now, but best of luck.",
      "interested": "This looks interesting. Happy to chat more. What's your availability?",
      "defer": "Let me think on this and get back to you.",
      "referral": "I might know someone. Let me check and get back to you.",
      "not_hiring": "Appreciate you thinking of me. Not looking for new opportunities right now."
    },
    "classificationRules": {
      "pitch": ["services", "help you", "partnership", "offering", "solution"],
      "job": ["opportunity", "role", "position", "hiring", "recruiter"],
      "networking": ["connect", "coffee", "catch up", "learn more about"],
      "spam": ["crypto", "guaranteed", "million", "investment opportunity"]
    }
  },
  "notifications": {
    "channel": "discord",
    "target": "#linkedin",
    "includeInMorningPing": true,
    "urgentKeywords": ["urgent", "deadline", "asap", "today"]
  },
  "safety": {
    "maxActionsPerHour": 20,
    "requireApproval": true,
    "dryRunMode": false,
    "logAllActions": true
  }
}


path: references/style-extraction.md
content: # Communication Style Extraction Guide

How to analyze a user's communication patterns and apply them to LinkedIn draft responses.

## Step 1: Read Style Source

Check for style information in this order:
1. `USER.md` - Usually contains explicit communication rules
2. `linkedin-inbox-config.json` - May have custom style overrides
3. Historical messages - If available, analyze past sent messages

## Step 2: Extract Key Signals

### Formality Level
- **Formal:** "Dear [Name]", full sentences, "Best regards"
- **Professional casual:** "Hi [Name]", contractions OK, "Thanks"
- **Casual:** "Hey", fragments OK, emoji allowed

### Greeting Patterns
Common patterns to detect:
- `Hi [Name]` / `Hey [Name]` / `Hello [Name]`
- No greeting (jumps to content)
- First name only vs "Mr./Ms."

### Sign-off Patterns
- `Best` / `Thanks` / `Cheers`
- Name only
- No sign-off

### Sentence Structure
- Short, punchy sentences
- Longer, flowing prose
- Bullet points for clarity
- Questions to engage

### Vocabulary Preferences
**Detect positive patterns:**
- Preferred words they use often
- Industry jargon comfort level
- Contraction usage (don't vs do not)

**Detect negative patterns (banned):**
- Words explicitly called out as banned
- Overly salesy language they avoid
- Corporate buzzwords they skip

### Response Length
- One-liner responses
- 2-3 sentence default
- Detailed paragraphs
- Match to context (short for simple, longer for complex)

## Step 3: Build Style Profile

Create a mental model like:
```
Tone: Professional casual
Greeting: "Hi [Name]" or direct start
Sign-off: None or "Thanks"
Length: 2-4 sentences max
Vocabulary: Plain English, no jargon
Banned: "excited", "leverage", "circle back"
Special: Uses colons instead of dashes
```

## Step 4: Apply to Drafts

### Template Selection
Based on message type:
- **Decline pitch:** Polite but firm, 1-2 sentences
- **Express interest:** Warm but not eager, ask one question
- **Defer:** Acknowledge, buy time, no commitment

### Draft Generation
1. Start with appropriate greeting (or none)
2. Address their point directly
3. State position clearly
4. Offer next step (if any)
5. Close with user's typical sign-off

### Quality Check
Before presenting draft:
- [ ] No banned words?
- [ ] Matches typical length?
- [ ] Sounds like the user wrote it?
- [ ] Not too eager or too cold?
- [ ] Clear and actionable?

## Example Style Profiles

### Founder-to-Founder (Low-BS)
```
Tone: Calm, controlled, non-reactive
Greeting: "Hi [Name]" or skip
Sign-off: None
Length: 3-6 lines max
Banned: excited, game-changer, hop on a call, quick win, leverage
Special: Always leave an exit ("all good if not")
```

### Friendly Networker
```
Tone: Warm, approachable
Greeting: "Hey [Name]!"
Sign-off: "Cheers" or "Talk soon"
Length: 2-4 sentences
Allowed: Light emoji (😊), exclamations
Special: Ask about them before pitching
```

### Direct Operator
```
Tone: No-nonsense
Greeting: Skip
Sign-off: Skip
Length: 1-2 sentences
Style: Get to the point immediately
Special: Binary questions ("Yes or no?")
```

## Handling Edge Cases

### Unknown Style
If no style info available:
- Default to professional casual
- Keep drafts short (2-3 sentences)
- Avoid anything too bold
- Flag to user: "No style profile found, using defaults"

### Conflicting Signals
If USER.md contradicts config:
- Config takes precedence for explicit overrides
- USER.md provides baseline defaults
- Note the conflict in draft: "Using config override for [X]"

### Cultural Adaptation
For international contacts:
- Slightly more formal by default
- Full words over contractions
- Clearer structure
- Avoid idioms


path: scripts/open_conversation.sh
content: #!/bin/bash
# Open a specific LinkedIn conversation using Peekaboo
# Usage: ./open_conversation.sh "person_name"

set -e

PERSON_NAME="$1"

if [ -z "$PERSON_NAME" ]; then
    echo "Usage: ./open_conversation.sh \"person_name\""
    exit 1
fi

echo "📖 Opening conversation with: $PERSON_NAME"

# Ensure Chrome is focused
peekaboo app launch "Google Chrome"
sleep 0.5

# Navigate to messaging with search
SEARCH_URL="https://www.linkedin.com/messaging/?searchTerm=$(echo "$PERSON_NAME" | sed 's/ /%20/g')"
peekaboo menu click --app "Google Chrome" --item "New Tab" 2>/dev/null || true
sleep 0.5
peekaboo type "$SEARCH_URL" --app "Google Chrome"
peekaboo press return --app "Google Chrome"
sleep 3

# Capture the conversation
OUTPUT_PATH="/tmp/linkedin-conversation-$(date +%s).png"
peekaboo see \
    --app "Google Chrome" \
    --annotate \
    --path "$OUTPUT_PATH"

echo "✅ Conversation captured: $OUTPUT_PATH"
echo "$OUTPUT_PATH"


path: scripts/scan_inbox.sh
content: #!/bin/bash
# LinkedIn Inbox Scanner using Peekaboo
# Usage: ./scan_inbox.sh [output_dir]

set -e

OUTPUT_DIR="${1:-/tmp/linkedin-inbox}"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
SCREENSHOT_PATH="$OUTPUT_DIR/inbox_$TIMESTAMP.png"

mkdir -p "$OUTPUT_DIR"

echo "📨 Scanning LinkedIn inbox..."

# Ensure Chrome is running
if ! pgrep -x "Google Chrome" > /dev/null; then
    echo "Starting Chrome..."
    peekaboo app launch "Google Chrome"
    sleep 2
fi

# Navigate to LinkedIn messaging
echo "Navigating to LinkedIn messaging..."
peekaboo menu click --app "Google Chrome" --item "New Tab" 2>/dev/null || true
sleep 1

# Type URL and navigate
peekaboo type "https://www.linkedin.com/messaging/" --app "Google Chrome"
peekaboo press return --app "Google Chrome"
sleep 3

# Wait for page load (check for messaging UI)
echo "Waiting for page load..."
sleep 2

# Capture annotated screenshot
echo "Capturing inbox state..."
peekaboo see \
    --app "Google Chrome" \
    --annotate \
    --path "$SCREENSHOT_PATH" \
    --json > "$OUTPUT_DIR/inbox_$TIMESTAMP.json" 2>/dev/null || \
peekaboo image \
    --app "Google Chrome" \
    --path "$SCREENSHOT_PATH"

echo "✅ Inbox captured: $SCREENSHOT_PATH"
echo "📋 Analysis JSON: $OUTPUT_DIR/inbox_$TIMESTAMP.json"

# Output path for agent consumption
echo "$SCREENSHOT_PATH"


path: scripts/send_message.sh
content: #!/bin/bash
# Send LinkedIn message using Peekaboo
# Usage: ./send_message.sh "conversation_name" "message_text"

set -e

CONVERSATION_NAME="$1"
MESSAGE_TEXT="$2"

if [ -z "$CONVERSATION_NAME" ] || [ -z "$MESSAGE_TEXT" ]; then
    echo "Usage: ./send_message.sh \"conversation_name\" \"message_text\""
    exit 1
fi

echo "💬 Sending message to: $CONVERSATION_NAME"

# Ensure we're on LinkedIn messaging
CURRENT_URL=$(peekaboo see --app "Google Chrome" --json 2>/dev/null | jq -r '.url // empty' || echo "")
if [[ "$CURRENT_URL" != *"linkedin.com/messaging"* ]]; then
    echo "Navigating to LinkedIn messaging..."
    peekaboo type "https://www.linkedin.com/messaging/" --app "Google Chrome"
    peekaboo press return --app "Google Chrome"
    sleep 3
fi

# Search for conversation
echo "Finding conversation..."
# Click search box (usually first text field in messaging)
peekaboo hotkey --keys "cmd,k" --app "Google Chrome"
sleep 0.5

# Type conversation name to filter
peekaboo type "$CONVERSATION_NAME" --app "Google Chrome"
sleep 1

# Press down + enter to select first result
peekaboo press down --app "Google Chrome"
peekaboo press return --app "Google Chrome"
sleep 2

# Type message
echo "Typing message..."
# Focus message input (usually at bottom of conversation)
peekaboo hotkey --keys "cmd,shift,m" --app "Google Chrome" 2>/dev/null || true
sleep 0.5

# Clear any existing text and type new message
peekaboo type "$MESSAGE_TEXT" --app "Google Chrome"

# Send with Enter
echo "Sending..."
peekaboo press return --app "Google Chrome"
sleep 1

echo "✅ Message sent to $CONVERSATION_NAME"


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: suspicious | SkillSpector: suspicious (CRITICAL)