Skill: audsmith28/linkedin-autopilot (version 1.1.0)

--- name: linkedin-autopilot description: Your agent builds your LinkedIn presence while you sleep. Schedule posts, auto-engage with target accounts, run personalized DM sequences, and never miss an engagement opportunity. Handles connection requests, profile visiting campaigns, post engagement, and follow-up sequences with safety throttling and human-like behavior patterns. Configure your targets, define engagement rules, and let your agent network 24/7. Use when setting up LinkedIn automation, managing posting schedules, running engagement campaigns, or building agent-driven LinkedIn lead generation workflows. metadata: clawdbot: emoji: "🤝" requires: browser: true env: - LINKEDIN_EMAIL - LINKEDIN_PASSWORD --- # LinkedIn Autopilot — Your Agent Networks 24/7 **You sleep. Your LinkedIn thrives.** LinkedIn Autopilot turns your agent into a 24/7 LinkedIn manager. It schedules posts, auto-engages with target accounts, runs personalized DM sequences, and builds your network while you focus on actual work. No more "I should post more" guilt. No more missing engagement windows. No more manual connection request grinding. **What makes it different:** This isn't a dumb bot — it's your agent using real browser automation with human-like behavior patterns. Random delays, natural engagement patterns, safety throttling, and intelligent targeting. Multi-day sequences with conditional logic. State tracking across sessions. Full reporting on what worked. ## The Pain Points This Solves ❌ **"I spend 2 hours/day on LinkedIn and have nothing to show for it"** ✅ Your agent handles engagement, DMs, and connection building automatically ❌ **"I post inconsistently and my reach is dying"** ✅ Scheduled posts with optimal timing — your agent never forgets ❌ **"I see opportunities to engage but I'm too busy"** ✅ Auto-engage on target accounts' posts with personalized comments ❌ **"Follow-up sequences are tedious and I drop leads"** ✅ Multi-step DM sequences with conditional logic — your agent follows up ❌ **"I want to build my network but connection requests feel spammy"** ✅ Targeted connection campaigns with personalized notes and safety limits ## Setup 1. Run `scripts/setup.sh` to initialize config and data directories 2. Edit `~/.config/linkedin-autopilot/config.json` with targets, sequences, and posting schedule 3. Store LinkedIn credentials in `~/.clawdbot/secrets.env`: ```bash LINKEDIN_EMAIL=[REDACTED_SECRET] LINKEDIN_PASSWORD=your-password ``` 4. Test with: `scripts/engage.sh --dry-run` ## Config Config lives at `~/.config/linkedin-autopilot/config.json`. See `config.example.json` for full schema. Key sections: - **identity** — Your LinkedIn profile info (for personalization) - **targets** — Who/what to engage with (companies, people, keywords) - **posting** — Schedule, content queue, optimal times - **engagement** — Auto-like/comment rules, target post patterns - **outreach** — Connection request campaigns, DM sequences - **safety** — Rate limits, delays, warmup period, blackout windows ## Scripts | Script | Purpose | |--------|---------| | `scripts/setup.sh` | Initialize config and data directories | | `scripts/post.sh` | Post scheduled content from queue | | `scripts/engage.sh` | Auto-engage on target posts (like, comment, share) | | `scripts/dm-sequence.sh` | Manage DM sequences (send, follow-up, track) | | `scripts/connect.sh` | Send connection requests to target profiles | | `scripts/report.sh` | Generate analytics report (engagement, growth, conversions) | All scripts support `--dry-run` for testing without actually posting/engaging. ## Posting Workflow Run `scripts/post.sh` on schedule (cron daily at optimal times). The script: 1. Checks posting queue in config 2. Verifies timing (respects blackout windows, rate limits) 3. Logs into LinkedIn via browser automation 4. Posts content with configured formatting 5. Tracks post performance 6. Updates queue state **Post queue example:** ```json "posts": [ { "content": "5 lessons from building AI agents in production:\n\n1. ...", "scheduled_time": "2024-01-28T09:00:00Z", "status": "pending", "media": null } ] ``` ## Engagement Workflow Run `scripts/engage.sh` 3-4x daily. The script: 1. Searches for posts matching target criteria (keywords, accounts, hashtags) 2. Scores relevance (content match, author influence, engagement level) 3. Engages with top posts (like, thoughtful comment, or share) 4. Tracks engagement to avoid repeats 5. Respects rate limits (20-30 engagements per run) **Target patterns:** - Posts from specific companies/people - Posts with keywords/hashtags - Posts in your feed from connections - Trending posts in your industry **Engagement types:** - **Like:** Quick signal, low friction - **Comment:** Generated from templates + post context (not spammy) - **Share:** With your take/commentary added ## DM Sequence Workflow Run `scripts/dm-sequence.sh` daily. The script: 1. Checks active sequences for people at each stage 2. Sends next message in sequence (respects delays) 3. Detects replies and advances/pauses accordingly 4. Handles conditional branching (replied vs not replied) 5. Reports on conversion rates **Sequence example:** ```json { "name": "consulting-intro", "trigger": "new_connection", "steps": [ { "delay_hours": 24, "message": "Hey {first_name}! Thanks for connecting. I help {title}s with {pain_point}. Are you currently working on anything in this space?", "condition": null }, { "delay_hours": 72, "message": "Following up — I saw your post about {topic}. Would love to chat about {offering}. Free for a quick call this week?", "condition": "no_reply" } ] } ``` ## Connection Request Workflow Run `scripts/connect.sh` weekly (not daily — LinkedIn limits this). The script: 1. Searches for target profiles (job titles, companies, keywords) 2. Filters out existing connections and pending requests 3. Generates personalized connection notes 4. Sends requests with safety throttling (20-30/week max) 5. Tracks acceptance rate **Target criteria:** ```json "connection_targets": [ { "query": "AI consultant OR automation specialist", "companies": ["Microsoft", "Google", "OpenAI"], "exclude_titles": ["Recruiter"], "note_template": "Hey {first_name}, I'm building AI tools for {industry} and saw your work at {company}. Would love to connect!" } ] ``` ## Safety & Rate Limits LinkedIn Autopilot follows conservative rate limits to avoid account flags: | Action | Limit | Timing | |--------|-------|--------| | **Posts** | 1-2/day | Optimal hours (9am-11am, 2pm-4pm) | | **Engagements** | 80-100/day | Spread across 3-4 runs | | **Connection Requests** | 20-30/week | Gradual warmup over first 2 weeks | | **DMs** | 30-50/day | Random delays 5-15min between sends | | **Profile Views** | 50-80/day | Natural browsing pattern | **Warmup Period:** First 2 weeks run at 50% capacity to establish normal behavior pattern. **Blackout Windows:** No activity during nights/weekends (configurable). **Random Delays:** 3-8 seconds between actions, 5-15 minutes between campaigns. **Human-Like Patterns:** Varied engagement times, occasional skips, natural language variance. ## State Tracking All activity is logged and tracked: ``` ~/.config/linkedin-autopilot/ ├── config.json # User configuration ├── posts-queue.json # Scheduled posts ├── engagement-history.json # Posts engaged with (dedup) ├── dm-sequences.json # Active DM threads ├── connections.json # Connection requests + status ├── analytics.json # Performance metrics └── activity-log.json # Full audit trail ``` ## Reporting `scripts/report.sh` generates performance reports: **Weekly Summary:** - Posts published (reach, engagement rate) - Engagements performed (breakdown by type) - Connection requests (sent, accepted, pending) - DM sequences (active, replied, converted) - Growth metrics (followers, connections, profile views) **Lead Conversion Tracking:** - DM replies → qualified leads - Connection acceptances → engaged conversations - Post engagement → inbound interest ## Example Workflows ### 1. Thought Leader Building - Post 1x/day on schedule (industry insights, lessons learned) - Auto-engage with 20-30 posts daily from influencers in your space - Share top posts with your commentary - Track which content types drive the most profile views ### 2. Outbound Lead Gen - Connect with 20-30 target profiles weekly (ICP: CTOs at Series A startups) - Run DM sequence on new connections (intro → value prop → call booking) - Auto-engage with prospects' posts before sending sequence - Report on reply rate and meeting bookings ### 3. Network Maintenance - Like posts from existing connections (stay top of mind) - Comment thoughtfully on key accounts' updates - Share relevant content to your feed - Periodic check-ins via DM (birthday, work anniversary, post milestone) ## LinkedIn TOS Compliance **Important:** LinkedIn's ToS prohibits automation. This tool is designed for: 1. **Personal use** with human oversight (you review/approve actions) 2. **Agent-assisted workflows** (agent suggests, human approves) 3. **Batch scheduling** (compose in bulk, post on schedule) **Recommended approach:** - Use `--dry-run` mode to preview actions - Review queued posts/messages before enabling auto-send - Set conservative rate limits - Monitor for account warnings - Always have a human in the loop for sensitive actions This tool is provided as-is for educational purposes. Use responsibly. ## Data Files ``` ~/.config/linkedin-autopilot/ ├── config.json # Main configuration ├── posts-queue.json # Scheduled content ├── engagement-history.json # Activity dedup ├── dm-sequences.json # Active conversations ├── connections.json # Network building state ├── analytics.json # Performance tracking └── activity-log.json # Full audit trail ``` ## Browser Automation Uses Clawdbot's built-in browser control: - Snapshot → Act → Verify pattern - Handles login, 2FA prompts, session management - Retries on rate limit detection - Graceful handling of LinkedIn UI changes ## Advanced Features **A/B Testing:** Test post variants, measure which performs better **Smart Scheduling:** ML-based optimal posting time suggestion **Reply Detection:** Pauses DM sequences when prospect replies **Sentiment Analysis:** Adjusts engagement strategy based on post sentiment **Network Mapping:** Tracks who engages with your content (potential advocates) ## Troubleshooting **"LinkedIn security check triggered"** → Reduce rate limits in config, extend delays, complete security verification manually **"Posts not publishing"** → Check `activity-log.json` for errors, verify LinkedIn session still valid **"DM sequences not advancing"** → Verify reply detection is working, check conversation state in `dm-sequences.json` **"Connection requests rejected frequently"** → Improve note personalization, target better ICP matches, reduce volume ## Contributing Want to add features? See `references/linkedin-api.md` for browser automation patterns and `references/sequence-engine.md` for DM workflow logic. --- **Remember:** Your agent is a force multiplier, not a replacement for authentic networking. Use it to handle the tedious parts so you can focus on the conversations that matter.

path: config.example.json
content: {
  "identity": {
    "name": "Emma Chen",
    "headline": "AI Solutions Architect | Helping teams automate with agents",
    "industry": "Technology & AI",
    "current_role": "Independent Consultant",
    "location": "San Francisco Bay Area",
    "profile_url": "https://linkedin.com/in/yourprofile"
  },
  "targets": {
    "companies": [
      "OpenAI",
      "Anthropic",
      "Microsoft",
      "Google DeepMind"
    ],
    "job_titles": [
      "CTO",
      "VP Engineering",
      "AI Product Manager",
      "Head of AI"
    ],
    "keywords": [
      "AI automation",
      "agent frameworks",
      "LLM applications",
      "workflow automation",
      "n8n",
      "LangChain"
    ],
    "hashtags": [
      "#AIAgents",
      "#Automation",
      "#LLM",
      "#ProductivityHacks"
    ],
    "influencers": [
      "https://linkedin.com/in/example1",
      "https://linkedin.com/in/example2"
    ]
  },
  "posting": {
    "enabled": true,
    "schedule": {
      "days": ["monday", "wednesday", "friday"],
      "optimal_times": ["09:00", "14:00"],
      "timezone": "America/Los_Angeles"
    },
    "queue": [],
    "formats": {
      "default": {
        "max_length": 3000,
        "include_hashtags": true,
        "hashtag_limit": 3,
        "include_emoji": true
      }
    }
  },
  "engagement": {
    "enabled": true,
    "auto_like": {
      "enabled": true,
      "target_types": ["influencer_posts", "keyword_matches", "connection_posts"],
      "min_relevance_score": 0.7,
      "max_per_run": 30
    },
    "auto_comment": {
      "enabled": true,
      "target_types": ["influencer_posts", "high_engagement_posts"],
      "min_relevance_score": 0.85,
      "max_per_run": 10,
      "templates": [
        "Great insights on {topic}! I've found that {relevant_experience}.",
        "This resonates. We've seen similar results with {related_work}.",
        "Appreciate you sharing this. The point about {key_point} is spot on.",
        "{topic} is such an important area. Have you explored {related_question}?"
      ],
      "avoid_generic": true
    },
    "auto_share": {
      "enabled": false,
      "target_types": ["exceptional_posts"],
      "min_relevance_score": 0.9,
      "max_per_run": 2,
      "add_commentary": true
    },
    "runs_per_day": 3,
    "spread_hours": [9, 14, 18]
  },
  "outreach": {
    "connection_requests": {
      "enabled": true,
      "campaigns": [
        {
          "name": "ai-consultants",
          "active": true,
          "search_query": "AI consultant OR automation consultant",
          "filters": {
            "companies": [],
            "locations": ["United States", "United Kingdom", "Canada"],
            "exclude_titles": ["Recruiter", "Sales Development Representative"]
          },
          "note_template": "Hi {first_name}, I help teams build AI automation workflows and saw your work at {company}. Would love to connect and exchange ideas!",
          "max_per_week": 20,
          "acceptance_goal": 0.30
        }
      ]
    },
    "dm_sequences": {
      "enabled": true,
      "sequences": [
        {
          "name": "new-connection-intro",
          "trigger": "connection_accepted",
          "active": true,
          "steps": [
            {
              "delay_hours": 24,
              "message": "Hey {first_name}! Thanks for connecting. I saw you're working on {topic_from_profile}. I help teams with AI automation — happy to share resources if useful!",
              "condition": null
            },
            {
              "delay_hours": 96,
              "message": "Following up — I noticed your post about {recent_topic}. We've built similar solutions. Would you be open to a quick call to share notes?",
              "condition": "no_reply"
            }
          ]
        },
        {
          "name": "consulting-lead-gen",
          "trigger": "manual",
          "active": false,
          "steps": [
            {
              "delay_hours": 0,
              "message": "Hi {first_name}, I help {title}s at {company_type} companies build AI workflows that save 10-20 hours/week. Are you currently exploring automation for your team?",
              "condition": null
            },
            {
              "delay_hours": 72,
              "message": "Hey {first_name}, wanted to follow up. I've worked with teams like {similar_company} to automate {use_case}. Would a 15-min intro call be helpful?",
              "condition": "no_reply"
            },
            {
              "delay_hours": 120,
              "message": "Last ping! If automation isn't a priority right now, no worries. Feel free to reach out if things change. Here's a resource I think you'd find useful: {resource_link}",
              "condition": "no_reply"
            }
          ]
        }
      ],
      "reply_detection": {
        "enabled": true,
        "auto_pause_on_reply": true,
        "notify_on_reply": true
      }
    }
  },
  "safety": {
    "rate_limits": {
      "posts_per_day": 2,
      "engagements_per_day": 100,
      "connection_requests_per_week": 25,
      "dms_per_day": 40,
      "profile_views_per_day": 80
    },
    "delays": {
      "between_actions_seconds": [3, 8],
      "between_campaigns_minutes": [5, 15],
      "between_dms_minutes": [10, 20]
    },
    "warmup": {
      "enabled": true,
      "duration_days": 14,
      "start_percentage": 0.5,
      "daily_increase": 0.05
    },
    "blackout_windows": [
      {
        "days": ["saturday", "sunday"],
        "reason": "weekends"
      },
      {
        "hours": ["00:00-07:00", "23:00-23:59"],
        "reason": "late_night"
      }
    ],
    "detection": {
      "rate_limit_keywords": ["unusual activity", "verify", "security check"],
      "pause_on_detection": true,
      "notify_human": true
    }
  },
  "analytics": {
    "track_metrics": [
      "post_reach",
      "post_engagement_rate",
      "connection_acceptance_rate",
      "dm_reply_rate",
      "profile_views",
      "follower_growth"
    ],
    "reporting_frequency": "weekly",
    "benchmark_goals": {
      "connection_acceptance_rate": 0.30,
      "dm_reply_rate": 0.25,
      "post_engagement_rate": 0.05
    }
  },
  "reporting": {
    "channel": "telegram",
    "frequency": "weekly",
    "include": [
      "activity_summary",
      "top_performing_posts",
      "dm_conversions",
      "network_growth",
      "engagement_highlights"
    ],
    "alert_on": [
      "rate_limit_warning",
      "security_check_triggered",
      "dm_reply_received",
      "high_performing_post"
    ]
  },
  "browser": {
    "profile": "linkedin-autopilot",
    "headless": true,
    "session_persistence": true,
    "2fa_handling": "manual_prompt",
    "viewport": {
      "width": 1920,
      "height": 1080
    }
  }
}


path: scripts/connect.sh
content: #!/bin/bash
# linkedin-autopilot/scripts/connect.sh — Send connection requests to target profiles

set -euo pipefail

CONFIG_DIR="${LINKEDIN_AUTOPILOT_DIR:-$HOME/.config/linkedin-autopilot}"
DRY_RUN=false
VERBOSE=false

# --- Helper Functions ---
log() {
  echo "[$(date +'%Y-%m-%d %H:%M:%S')] - $1"
}

# --- Argument Parsing ---
for arg in "$@"; do
  case $arg in
    --dry-run)
      DRY_RUN=true
      log "Running in dry-run mode. No actual connection requests will be sent."
      shift
      ;;
    --verbose)
      VERBOSE=true
      log "Verbose mode enabled."
      shift
      ;;
  esac
done

# --- Main Logic Placeholder ---
log "Starting connect.sh script..."

# 1. Load configuration and connection history
log "Loading config from $CONFIG_DIR/config.json"
# config=$(cat "$CONFIG_DIR/config.json")
# history=$(cat "$CONFIG_DIR/connections.json")

# 2. Check if outreach is enabled and within weekly limits
# enabled=$(echo "$config" | jq -r '.outreach.connection_requests.enabled')
# weekly_limit=$(...)
# sent_this_week=$(...)
# if [ "$enabled" != "true" ] || [ "$sent_this_week" -ge "$weekly_limit" ]; then
#   log "Connection requests are disabled or weekly limit has been reached. Exiting."
#   exit 0
# fi

# 3. Find target profiles via browser automation
log "Executing browser automation to find target profiles..."
if [ "$DRY_RUN" = "true" ]; then
  log "DRY RUN: Would search for profiles matching query: 'AI Product Manager'..."
  log "DRY RUN: Found 5 potential profiles to connect with."
else
  # Browser automation to search for people
  #
  # Example steps:
  # a. Login to LinkedIn
  # b. Construct search URL from config campaign
  # c. Navigate and snapshot results
  # d. Parse snapshot to get profile URLs, names, and titles
  # e. Filter out already connected or pending requests
  log "Placeholder for browser automation: searching for profiles."
fi

# 4. Send connection requests
log "Sending connection requests with personalized notes..."
if [ "$DRY_RUN" = "true" ]; then
    log "DRY RUN: Sending request to Profile 1 with note: 'Hi Jane, saw your work at XYZ...'"
    log "DRY RUN: Sending request to Profile 2 with note: 'Hi John, loved your post on AI...'"
else
  # Browser automation to send requests
  #
  # Example steps:
  # a. For each profile, navigate to their page
  # b. Click the "Connect" button
  # c. Click "Add a note"
  # d. Type the personalized note into the text area
  # e. Click "Send"
  # f. Apply random delays
  log "Placeholder for browser automation: sending connection requests."
fi

# 5. Update connection history
log "Updating connection history with pending requests."
# new_history=$(...)
# echo "$new_history" > "$CONFIG_DIR/connections.json"

# 7. Log activity
log "Logging activity to activity-log.json"

log "connect.sh script finished."


path: scripts/dm-sequence.sh
content: #!/bin/bash
# linkedin-autopilot/scripts/dm-sequence.sh — Manage DM sequences

set -euo pipefail

CONFIG_DIR="${LINKEDIN_AUTOPILOT_DIR:-$HOME/.config/linkedin-autopilot}"
DRY_RUN=false
VERBOSE=false

# --- Helper Functions ---
log() {
  echo "[$(date +'%Y-%m-%d %H:%M:%S')] - $1"
}

# --- Argument Parsing ---
for arg in "$@"; do
  case $arg in
    --dry-run)
      DRY_RUN=true
      log "Running in dry-run mode. No actual DMs will be sent."
      shift
      ;;
    --verbose)
      VERBOSE=true
      log "Verbose mode enabled."
      shift
      ;;
  esac
done

# --- Main Logic Placeholder ---
log "Starting dm-sequence.sh script..."

# 1. Load config and active sequence state
log "Loading config and sequence state from $CONFIG_DIR/"
# config=$(cat "$CONFIG_DIR/config.json")
# sequences=$(cat "$CONFIG_DIR/dm-sequences.json")

# 2. Check for replies in existing conversations
log "Checking for replies..."
if [ "$DRY_RUN" = "true" ]; then
  log "DRY RUN: Would check message threads for new replies."
  log "DRY RUN: Found 1 new reply. Pausing sequence for that contact."
else
  # Browser automation to check messages
  #
  # Example steps:
  # a. Navigate to messaging page: https://www.linkedin.com/messaging/
  # b. Snapshot the conversation list
  # c. Identify conversations with unread messages
  # d. For each unread message, check if it's from a contact in an active sequence
  # e. If so, update the state in dm-sequences.json to 'paused_reply_received'
  log "Placeholder for browser automation: checking for replies."
fi

# 3. Find contacts due for their next message
log "Finding contacts due for next sequence step..."
# due_contacts=$(...) # Logic to iterate through active sequences and check timestamps

# 4. If no contacts are due, exit
# if [ -z "$due_contacts" ]; then
#   log "No contacts are due for a message. Exiting."
#   exit 0
# fi

log "Found 2 contacts due for a follow-up message." # Placeholder

# 5. Send messages via browser automation
if [ "$DRY_RUN" = "true" ]; then
  log "DRY RUN: Would send message to Contact 1: 'Hey! Thanks for connecting...'"
  log "DRY RUN: Would send message to Contact 2: 'Following up on our chat...'"
else
  # Browser automation to send DMs
  #
  # Example steps:
  # a. For each contact, navigate to their message thread URL
  # b. Type the message template (with personalized variables) into the message box
  #    clawd browser act --kind type --ref '...' --text "..."
  # c. Click send
  #    clawd browser act --kind click --ref 'button:has-text("Send")'
  # d. Apply random delays between messages
  log "Placeholder for browser automation: sending DMs."
fi

# 6. Update sequence state
log "Updating sequence state for contacts."
# new_sequences_state=$(...) # Logic to update JSON with new timestamps and steps
# echo "$new_sequences_state" > "$CONFIG_DIR/dm-sequences.json"

# 7. Log activity
log "Logging activity to activity-log.json"

log "dm-sequence.sh script finished."


path: scripts/engage.sh
content: #!/bin/bash
# linkedin-autopilot/scripts/engage.sh — Auto-engage on target posts

set -euo pipefail

CONFIG_DIR="${LINKEDIN_AUTOPILOT_DIR:-$HOME/.config/linkedin-autopilot}"
DRY_RUN=false
VERBOSE=false

# --- Helper Functions ---
log() {
  echo "[$(date +'%Y-%m-%d %H:%M:%S')] - $1"
}

# --- Argument Parsing ---
for arg in "$@"; do
  case $arg in
    --dry-run)
      DRY_RUN=true
      log "Running in dry-run mode. No actual engagement will happen."
      shift
      ;;
    --verbose)
      VERBOSE=true
      log "Verbose mode enabled."
      shift
      ;;
  esac
done

# --- Main Logic Placeholder ---
log "Starting engage.sh script..."

# 1. Load configuration and engagement history
log "Loading config from $CONFIG_DIR/config.json"
# config=$(cat "$CONFIG_DIR/config.json")
# history=$(cat "$CONFIG_DIR/engagement-history.json")

# 2. Check if engagement is enabled
# engage_enabled=$(echo "$config" | jq -r '.engagement.enabled')
# if [ "$engage_enabled" != "true" ]; then
#   log "Engagement is disabled in config.json. Exiting."
#   exit 0
# fi

# 3. Execute browser automation to find target posts
log "Executing browser automation to find target posts..."
if [ "$DRY_RUN" = "true" ]; then
  log "DRY RUN: Would search for posts matching keywords: AI automation, agent frameworks..."
  log "DRY RUN: Found 3 relevant posts."
else
  # This is where the call to `clawd browser` would happen
  #
  # Example steps:
  # a. Login to LinkedIn (see post.sh for logic)
  # b. Construct search URL from config targets
  #    search_url="https://www.linkedin.com/search/results/content/?keywords=...&sortBy=DATE"
  # c. Navigate and snapshot the results
  #    clawd browser navigate --url "$search_url"
  #    clawd browser snapshot --refs aria > snapshot.json
  # d. Parse snapshot to identify relevant posts
  #    - Find post containers, extract text, author, engagement stats
  #    - Filter out already-engaged posts (check against engagement-history.json)
  log "Placeholder for browser automation: searching for posts."
fi

# 4. Score and select posts for engagement
log "Scoring posts and selecting top 3 for engagement."
# selected_posts=$(...) # Logic to score based on relevance, author, etc.

# 5. Perform engagement actions (like/comment)
for i in {1..3}; do
  if [ "$DRY_RUN" = "true" ]; then
    log "DRY RUN: Engaging with Post #$i."
    log "DRY RUN:   Action: Like"
    log "DRY RUN:   Action: Comment -> 'Great insights on this topic!'"
  else
    # Browser automation to like and comment
    #
    # Example steps:
    # a. Find the "Like" button for the post ref and click it
    #    clawd browser act --kind click --ref '...'
    # b. Find the "Comment" button, click it, type a generated comment
    #    clawd browser act --kind click --ref '...'
    #    clawd browser act --kind type --ref '...' --text "..."
    #    clawd browser act --kind click --ref 'button:has-text("Post")'
    # c. Apply random delays between actions
    #    sleep $((RANDOM % 5 + 3))
    log "Placeholder for browser automation: Liking and commenting on Post #$i."
  fi
done

# 6. Update engagement history
log "Updating engagement history."
# new_history=$(...) # Logic to add new post IDs to JSON
# echo "$new_history" > "$CONFIG_DIR/engagement-history.json"

# 7. Log activity
log "Logging activity to activity-log.json"

log "engage.sh script finished."


path: scripts/post.sh
content: #!/bin/bash
# linkedin-autopilot/scripts/post.sh — Post scheduled content from the queue

set -euo pipefail

CONFIG_DIR="${LINKEDIN_AUTOPILOT_DIR:-$HOME/.config/linkedin-autopilot}"
DRY_RUN=false
VERBOSE=false

# --- Helper Functions ---
log() {
  echo "[$(date +'%Y-%m-%d %H:%M:%S')] - $1"
}

# --- Argument Parsing ---
for arg in "$@"; do
  case $arg in
    --dry-run)
      DRY_RUN=true
      log "Running in dry-run mode. No actual posts will be made."
      shift
      ;;
    --verbose)
      VERBOSE=true
      log "Verbose mode enabled."
      shift
      ;;
  esac
done

# --- Main Logic Placeholder ---
log "Starting post.sh script..."

# 1. Load configuration and post queue
log "Loading config from $CONFIG_DIR/config.json"
# config=$(cat "$CONFIG_DIR/config.json")
# queue=$(cat "$CONFIG_DIR/posts-queue.json")

# 2. Check if posting is enabled
# posting_enabled=$(echo "$config" | jq -r '.posting.enabled')
# if [ "$posting_enabled" != "true" ]; then
#   log "Posting is disabled in config.json. Exiting."
#   exit 0
# fi

# 3. Find posts scheduled for now
log "Checking for posts to publish..."
# scheduled_posts=$(...) # Logic to filter queue by current time

# 4. If no posts, exit
# if [ -z "$scheduled_posts" ]; then
#   log "No posts scheduled for now. Exiting."
#   exit 0
# fi

log "Found 1 post to publish." # Placeholder

# 5. Execute browser automation
if [ "$DRY_RUN" = "true" ]; then
  log "DRY RUN: Would execute browser automation to post content."
  log "DRY RUN: Content: '5 lessons from building AI agents...'"
else
  log "Executing browser automation..."
  # This is where the call to `clawd browser` would happen
  #
  # Example steps:
  # a. Start browser with profile
  #    clawd browser start --profile linkedin-autopilot
  # b. Navigate to LinkedIn
  #    clawd browser navigate --url "https://www.linkedin.com/"
  # c. Handle login (check if session is valid, otherwise use credentials)
  #    - snapshot page, check for profile icon vs login form
  #    - if login form: clawd browser act ... --kind fill --ref 'input[name=session_key]' --text "$LINKEDIN_EMAIL"
  # d. Open post creation dialog
  #    clawd browser act --kind click --ref 'button:has-text("Start a post")'
  # e. Paste content and submit
  #    clawd browser act --kind type --ref 'div.ql-editor' --text "..."
  #    clawd browser act --kind click --ref 'button:has-text("Post")'
  # f. Verify post success
  #    - snapshot page, check for "Post successful" toast
  # g. Close browser
  #    clawd browser stop --profile linkedin-autopilot
  log "Placeholder for browser automation logic."
  log "Post successfully published."
fi

# 6. Update queue state
log "Updating post queue status to 'published'."
# new_queue=$(...) # Logic to update JSON
# echo "$new_queue" > "$CONFIG_DIR/posts-queue.json"

# 7. Log activity
log "Logging activity to activity-log.json"
# echo '{"timestamp": "...", "action": "post", "status": "success", "content": "..."}' >> "$CONFIG_DIR/activity-log.json"

log "post.sh script finished."


path: scripts/report.sh
content: #!/bin/bash
# linkedin-autopilot/scripts/report.sh — Generate analytics report

set -euo pipefail

CONFIG_DIR="${LINKEDIN_AUTOPILOT_DIR:-$HOME/.config/linkedin-autopilot}"
CHANNEL="telegram" # Default channel

# --- Argument Parsing ---
for arg in "$@"; do
  case $arg in
    --channel=*)
      CHANNEL="${arg#*=}"
      shift
      ;;
  esac
done

# --- Main Logic Placeholder ---
echo "📊 LinkedIn Autopilot Weekly Report"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"

# 1. Load all data files
# posts=$(cat "$CONFIG_DIR/posts-queue.json")
# engagements=$(cat "$CONFIG_DIR/engagement-history.json")
# dms=$(cat "$CONFIG_DIR/dm-sequences.json")
# connections=$(cat "$CONFIG_DIR/connections.json")
# analytics=$(cat "$CONFIG_DIR/analytics.json")

# 2. Calculate metrics (placeholders)
POSTS_PUBLISHED=3
REACH_TOTAL=12500
ENGAGEMENT_RATE=4.7
CONNECTIONS_SENT=22
CONNECTIONS_ACCEPTED=7
ACCEPTANCE_RATE=$(echo "scale=2; $CONNECTIONS_ACCEPTED*100/$CONNECTIONS_SENT" | bc)%
DMS_SENT=15
DMS_REPLIED=4

# 3. Format the report
REPORT_TEXT=$(cat <<EOF
*📊 LinkedIn Autopilot Weekly Report*

*🚀 Performance Summary:*
- *Posts Published:* $POSTS_PUBLISHED
- *Total Reach:* ~$REACH_TOTAL
- *Avg. Engagement Rate:* $ENGAGEMENT_RATE%

*📈 Network Growth:*
- *Connection Requests Sent:* $CONNECTIONS_SENT
- *New Connections:* $CONNECTIONS_ACCEPTED
- *Acceptance Rate:* $ACCEPTANCE_RATE

*💬 Outreach:*
- *New DM Sequences Started:* $DMS_SENT
- *Replies Received:* $DMS_REPLIED

*💡 Top Performing Post:*
"5 lessons from building AI agents..." (25 likes, 12 comments)

*Action Items:*
- Review the 4 DM replies and respond manually.
- Queue up new posts for next week.
EOF
)

# 4. Send report to the specified channel
echo "Sending report to channel: $CHANNEL"
# This is where the call to `clawd message` would happen
#
# Example:
# clawd message send --channel "$CHANNEL" --message "$REPORT_TEXT"

echo ""
echo "$REPORT_TEXT"
echo ""
echo "Report generated successfully."



path: scripts/setup.sh
content: #!/bin/bash
# linkedin-autopilot/scripts/setup.sh — Initialize config and data directories

set -euo pipefail

CONFIG_DIR="${LINKEDIN_AUTOPILOT_DIR:-$HOME/.config/linkedin-autopilot}"
SKILL_DIR="$(cd "$(dirname "$0")/.." && pwd)"

echo "🤝 LinkedIn Autopilot Setup"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━"

# Create config directory
mkdir -p "$CONFIG_DIR"
echo "✓ Created $CONFIG_DIR"

# Copy example config if none exists
if [ ! -f "$CONFIG_DIR/config.json" ]; then
  cp "$SKILL_DIR/config.example.json" "$CONFIG_DIR/config.json"
  echo "✓ Created config.json (from example — edit with your targets and sequences)"
else
  echo "• config.json already exists (skipped)"
fi

# Initialize data files
for file in posts-queue.json engagement-history.json dm-sequences.json connections.json analytics.json activity-log.json; do
  if [ ! -f "$CONFIG_DIR/$file" ]; then
    case "$file" in
      posts-queue.json)
        echo '{"posts":[]}' > "$CONFIG_DIR/$file"
        ;;
      engagement-history.json)
        echo '{"engagements":{}}' > "$CONFIG_DIR/$file"
        ;;
      dm-sequences.json)
        echo '{"sequences":{}}' > "$CONFIG_DIR/$file"
        ;;
      connections.json)
        echo '{"connections":{}}' > "$CONFIG_DIR/$file"
        ;;
      analytics.json)
        echo '{"history":[]}' > "$CONFIG_DIR/$file"
        ;;
      activity-log.json)
        echo '[]' > "$CONFIG_DIR/$file"
        ;;
    esac
    echo "✓ Created $file"
  else
    echo "• $file already exists (skipped)"
  fi
done

# Check for credentials
SECRETS_FILE="$HOME/.clawdbot/secrets.env"
if [ -f "$SECRETS_FILE" ]; then
  if grep -q "LINKEDIN_EMAIL" "$SECRETS_FILE" 2>/dev/null && grep -q "LINKEDIN_PASSWORD" "$SECRETS_FILE" 2>/dev/null; then
    echo "✓ LINKEDIN_EMAIL and LINKEDIN_PASSWORD found in secrets.env"
  else
    echo "⚠ LinkedIn credentials not found in secrets.env"
    echo "  Add:"
    echo "  LINKEDIN_EMAIL=[REDACTED_SECRET]"
    echo "  LINKEDIN_PASSWORD=your-password"
    echo "  to $SECRETS_FILE"
  fi
else
  echo "⚠ $SECRETS_FILE not found"
  echo "  Create it and add your LinkedIn credentials."
fi

echo ""
echo "Next steps:"
echo "  1. Edit $CONFIG_DIR/config.json with your identity, targets, and content"
echo "  2. Ensure your LinkedIn credentials are in $SECRETS_FILE"
echo "  3. Test with: $(dirname "$0")/engage.sh --dry-run"
echo ""
echo "🚀 LinkedIn Autopilot is ready to engage."


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