{
  "schemaVersion": "1.0",
  "item": {
    "slug": "linkedin-followup",
    "name": "LinkedIn Follow-up",
    "source": "tencent",
    "type": "skill",
    "category": "效率提升",
    "sourceUrl": "https://clawhub.ai/10Madh/linkedin-followup",
    "canonicalUrl": "https://clawhub.ai/10Madh/linkedin-followup",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/linkedin-followup",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=linkedin-followup",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "SKILL.md",
      "references/browser-workflow.md",
      "references/sheet-schema.md"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
        },
        {
          "label": "Upgrade existing",
          "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-04-23T16:43:11.935Z",
      "expiresAt": "2026-04-30T16:43:11.935Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=4claw-imageboard",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=4claw-imageboard",
        "contentDisposition": "attachment; filename=\"4claw-imageboard-1.0.1.zip\"",
        "redirectLocation": null,
        "bodySnippet": null
      },
      "scope": "source",
      "summary": "Source download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this source.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/linkedin-followup"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/linkedin-followup",
    "agentPageUrl": "https://openagent3.xyz/skills/linkedin-followup/agent",
    "manifestUrl": "https://openagent3.xyz/skills/linkedin-followup/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/linkedin-followup/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
      },
      {
        "label": "Upgrade existing",
        "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "linkedin-followup",
        "body": "Manage ongoing LinkedIn conversations from a central Google Sheet CRM. Read threads, draft context-aware replies, send messages, and keep the sheet updated — all from one skill."
      },
      {
        "title": "Pre-flight Checklist",
        "body": "Before doing anything:\n\nSheet ID — Confirm the CRM sheet ID (from linkedin-dm setup). Default: 1eEZDGcr1dIbSC782mNkxvD7pVrF8rOFySWCVZ1RXkhM, tab: Sheet1 (or Outreach if renamed).\ngog auth — Run gog auth list. If no tokens: see gog auth setup below.\nBrowser — Open the openclaw browser profile and confirm LinkedIn is logged in. Navigate to /feed/ first.\nMode — Identify which mode the user wants (see Modes)."
      },
      {
        "title": "Sheet Schema",
        "body": "The CRM sheet uses these columns (A–P):\n\nColFieldNotesADate SentISO dateBPerson NameFull nameCRole / TitleDCompanyELinkedIn URLProfile URLFRelationship HookHook used in openerGOpener SentMessage 1 textHPitch SentMessage 2 textICampaignBatch labelJStatusCurrent pipeline stageKNotesContext and historyLLast UpdatedISO timestampMLast Reply DateWhen they last repliedNLast Reply (preview)First 200 chars of their last replyOConversation LogFull thread (see format below)PNext ActionWhat to do next (agent or human)\n\nStatus values:\nSent → Replied → Call Scheduled → Demo Done → Follow Up Sent → No Response → Closed Won → Closed Lost\n\nConversation Log format (column O):\n\n[2026-02-13 17:05 SENT] Hey Rishabh, we both had stints at CRED...\n[2026-02-13 17:05 SENT] I'm building an AI calling agent...\n[2026-02-15 09:30 RECEIVED] Hey! Sounds interesting, tell me more.\n[2026-02-15 09:45 SENT] Happy to show you a live demo — are you free Thursday?\n\nIf columns M–P don't exist yet, add them first:\n\ngog sheets update <SHEET_ID> \"Sheet1!M1:P1\" \\\n  --values-json '[[\"Last Reply Date\",\"Last Reply (preview)\",\"Conversation Log\",\"Next Action\"]]' \\\n  --input USER_ENTERED"
      },
      {
        "title": "Mode 1 — Quick Status Update",
        "body": "User says: \"Mark Rishabh as Replied\" or \"Rishabh got back to me, he's interested\"\n\nFind the row — Search the sheet for the person:\ngog sheets get <SHEET_ID> \"Sheet1!A:P\" --json\n\nMatch by name (col B) or LinkedIn URL (col E). Get the row number.\n\n\nUpdate status (col J) and last updated (col L):\ngog sheets update <SHEET_ID> \"Sheet1!J<ROW>:L<ROW>\" \\\n  --values-json '[[\"Replied\",\"\",\"<ISO_TIMESTAMP>\"]]' \\\n  --input USER_ENTERED\n\n\n\nIf the user provides reply content, also update:\n\nCol M: Last Reply Date\nCol N: Last Reply preview (first 200 chars)\nCol O: Append to Conversation Log\nCol P: Next Action (what should happen next)\n\n\n\nConfirm update to user."
      },
      {
        "title": "Mode 2 — Full Follow-up (Read + Draft + Send)",
        "body": "User says: \"Follow up with Rishabh\" or \"Send a follow-up to everyone who replied\"\n\nStep 1 — Load the person's data from sheet\n\ngog sheets get <SHEET_ID> \"Sheet1!A:P\" --json\n\nFind their row. Load: Name, Company, Role, LinkedIn URL, Opener Sent, Pitch Sent, Status, Notes, Conversation Log, Next Action.\n\nStep 2 — Navigate to their LinkedIn profile\n\nAlways go to feed first (anti-detection):\n\nhttps://www.linkedin.com/feed/\n\nWait 2–4 seconds. Then navigate to their profile URL (col E).\n\nStep 3 — Open message thread and read conversation\n\nClick the Message button on their profile. Wait for the conversation bubble to load.\n\nScrape the full thread with JavaScript:\n\nconst events = Array.from(document.querySelectorAll('.msg-s-message-list__event'));\nconst messages = [];\nevents.forEach(el => {\n  const groups = el.querySelectorAll('.msg-s-event-listitem');\n  groups.forEach(g => {\n    const nameEl = g.closest('.msg-s-message-group')?.querySelector('.msg-s-message-group__profile-link');\n    const bodyEl = g.querySelector('.msg-s-event-listitem__body');\n    const timeEl = g.closest('.msg-s-message-group')?.querySelector('.msg-s-message-group__timestamp');\n    if (bodyEl?.textContent?.trim()) {\n      messages.push({\n        sender: nameEl?.textContent?.trim() || 'unknown',\n        time: timeEl?.textContent?.trim() || '',\n        text: bodyEl.textContent.trim()\n      });\n    }\n  });\n});\nreturn JSON.stringify(messages);\n\nIf the thread is empty or not loading, scroll up in the conversation bubble to load older messages.\n\nStep 4 — Analyse the conversation\n\nWith the full thread loaded + their profile data, determine:\n\nWhat did they say last? — Identify the most recent message from them.\nWhat's the intent? — Interested / wants more info / asked a question / cold / objection / not interested.\nWhat's the right next message? — See Response Playbook below.\nTone — Mirror their tone (casual vs formal, brief vs detailed).\n\nStep 5 — Draft the follow-up\n\nWrite a response that:\n\nDirectly addresses what they said last\nDoesn't re-pitch unless they asked for it\nMoves toward a specific action (demo, call, intro, forward to team)\nIs brief — 2–4 sentences max\nFeels human, not templated\n\nShow the draft to the user and ask for approval before sending:\n\nDraft reply to [Name]:\n[message]\nSend this? (y / edit / skip)\n\nStep 6 — Send the message\n\nSame JS evaluate method as linkedin-dm:\n\nconst active = document.querySelector('.msg-overlay-conversation-bubble--is-active .msg-form__contenteditable');\nif (active) { active.focus(); document.execCommand('insertText', false, '<message>'); }\n\nThen find and click Send.\n\nStep 7 — Update the sheet\n\nAfter sending:\n\ngog sheets update <SHEET_ID> \"Sheet1!J<ROW>:P<ROW>\" \\\n  --values-json '[[\"<new_status>\",\"<last_reply_date>\",\"<last_reply_preview>\",\"<updated_conversation_log>\",\"<next_action>\",\"<ISO_TIMESTAMP>\"]]' \\\n  --input USER_ENTERED"
      },
      {
        "title": "Mode 3 — Batch Review",
        "body": "User says: \"Who needs a follow-up?\" or \"Check my outreach\"\n\nLoad all rows from the sheet.\nFilter by status and time:\n\nSent older than 3 days → candidate for \"No Response\" or gentle follow-up\nReplied → needs a response\nFollow Up Sent older than 5 days → consider \"No Response\"\nCall Scheduled → check if call happened, update status\n\n\nPresent a table of candidates:\nName             Status    Last Updated    Suggested Action\nRishabh Nayan    Replied   2026-02-14      Reply to their message\nShorya Saini     Sent      2026-02-10      Follow-up nudge (4 days)\nShantam Mohata   Sent      2026-02-13      Too soon (today)\n\n\nUser picks who to action, then enter Mode 2 for each."
      },
      {
        "title": "Response Playbook",
        "body": "Use these as a guide — always adapt to the actual conversation:\n\nThey saidIntentYour move\"Sounds interesting, tell me more\"CuriousShort explanation + offer a specific demo slot\"How does it work?\"Exploring2-line description + invite to a 15-min call\"We already use [X]\"ObjectionAcknowledge, explain differentiation, offer demo\"Send me more details\"Soft interestShare a Loom/deck/link + follow up in 2 days\"Not relevant right now\"Soft noRespect it, leave door open: \"No worries, I'll ping you in a few months\"\"Who else is using it?\"Trust-buildingShare a relevant use case, offer intro to a user[No reply in 4 days]SilenceLight nudge: \"Hey [Name], just checking — any thoughts?\"[No reply in 8 days]ColdOne final message, then mark No Response"
      },
      {
        "title": "Anti-Detection Rules",
        "body": "Same rules as linkedin-dm:\n\nAlways go to /feed/ before navigating to a profile\nWait 2–4 seconds after loading feed\nMax 15–20 messages per session (combined sends across follow-ups)\nSpace out follow-ups: don't ping multiple people in rapid succession\nNatural delays between typing and sending (1–2 seconds)"
      },
      {
        "title": "gog Auth Setup",
        "body": "If gog auth list returns empty, the user needs to set up Google OAuth credentials:\n\nGo to console.cloud.google.com\nCreate a project (or select existing)\nEnable Google Sheets API (APIs & Services → Library)\nCreate OAuth credentials: APIs & Services → Credentials → Create → OAuth client ID → Desktop App\nDownload client_secret_<id>.json\nRun:\ngog auth credentials set /path/to/client_secret.json\ngog auth add your@gmail.com --services sheets\n\n\nA browser window will open — log in and grant access\nVerify: gog auth list\n\nFallback (no gog): All sheet reads/writes can be done manually via browser — open the sheet in the openclaw browser and update cells directly. Less automated but functional."
      },
      {
        "title": "Session Limits",
        "body": "Max 15–20 follow-up messages per session\nLog every send immediately to sheet (don't batch)\nIf gog is unavailable, log to local linkedin_followup_log.json and sync to sheet next session"
      }
    ],
    "body": "linkedin-followup\n\nManage ongoing LinkedIn conversations from a central Google Sheet CRM. Read threads, draft context-aware replies, send messages, and keep the sheet updated — all from one skill.\n\nPre-flight Checklist\n\nBefore doing anything:\n\nSheet ID — Confirm the CRM sheet ID (from linkedin-dm setup). Default: 1eEZDGcr1dIbSC782mNkxvD7pVrF8rOFySWCVZ1RXkhM, tab: Sheet1 (or Outreach if renamed).\ngog auth — Run gog auth list. If no tokens: see gog auth setup below.\nBrowser — Open the openclaw browser profile and confirm LinkedIn is logged in. Navigate to /feed/ first.\nMode — Identify which mode the user wants (see Modes).\nSheet Schema\n\nThe CRM sheet uses these columns (A–P):\n\nCol\tField\tNotes\nA\tDate Sent\tISO date\nB\tPerson Name\tFull name\nC\tRole / Title\t\nD\tCompany\t\nE\tLinkedIn URL\tProfile URL\nF\tRelationship Hook\tHook used in opener\nG\tOpener Sent\tMessage 1 text\nH\tPitch Sent\tMessage 2 text\nI\tCampaign\tBatch label\nJ\tStatus\tCurrent pipeline stage\nK\tNotes\tContext and history\nL\tLast Updated\tISO timestamp\nM\tLast Reply Date\tWhen they last replied\nN\tLast Reply (preview)\tFirst 200 chars of their last reply\nO\tConversation Log\tFull thread (see format below)\nP\tNext Action\tWhat to do next (agent or human)\n\nStatus values: Sent → Replied → Call Scheduled → Demo Done → Follow Up Sent → No Response → Closed Won → Closed Lost\n\nConversation Log format (column O):\n\n[2026-02-13 17:05 SENT] Hey Rishabh, we both had stints at CRED...\n[2026-02-13 17:05 SENT] I'm building an AI calling agent...\n[2026-02-15 09:30 RECEIVED] Hey! Sounds interesting, tell me more.\n[2026-02-15 09:45 SENT] Happy to show you a live demo — are you free Thursday?\n\n\nIf columns M–P don't exist yet, add them first:\n\ngog sheets update <SHEET_ID> \"Sheet1!M1:P1\" \\\n  --values-json '[[\"Last Reply Date\",\"Last Reply (preview)\",\"Conversation Log\",\"Next Action\"]]' \\\n  --input USER_ENTERED\n\nModes\nMode 1 — Quick Status Update\n\nUser says: \"Mark Rishabh as Replied\" or \"Rishabh got back to me, he's interested\"\n\nFind the row — Search the sheet for the person:\n\ngog sheets get <SHEET_ID> \"Sheet1!A:P\" --json\n\n\nMatch by name (col B) or LinkedIn URL (col E). Get the row number.\n\nUpdate status (col J) and last updated (col L):\n\ngog sheets update <SHEET_ID> \"Sheet1!J<ROW>:L<ROW>\" \\\n  --values-json '[[\"Replied\",\"\",\"<ISO_TIMESTAMP>\"]]' \\\n  --input USER_ENTERED\n\n\nIf the user provides reply content, also update:\n\nCol M: Last Reply Date\nCol N: Last Reply preview (first 200 chars)\nCol O: Append to Conversation Log\nCol P: Next Action (what should happen next)\n\nConfirm update to user.\n\nMode 2 — Full Follow-up (Read + Draft + Send)\n\nUser says: \"Follow up with Rishabh\" or \"Send a follow-up to everyone who replied\"\n\nStep 1 — Load the person's data from sheet\ngog sheets get <SHEET_ID> \"Sheet1!A:P\" --json\n\n\nFind their row. Load: Name, Company, Role, LinkedIn URL, Opener Sent, Pitch Sent, Status, Notes, Conversation Log, Next Action.\n\nStep 2 — Navigate to their LinkedIn profile\n\nAlways go to feed first (anti-detection):\n\nhttps://www.linkedin.com/feed/\n\n\nWait 2–4 seconds. Then navigate to their profile URL (col E).\n\nStep 3 — Open message thread and read conversation\n\nClick the Message button on their profile. Wait for the conversation bubble to load.\n\nScrape the full thread with JavaScript:\n\nconst events = Array.from(document.querySelectorAll('.msg-s-message-list__event'));\nconst messages = [];\nevents.forEach(el => {\n  const groups = el.querySelectorAll('.msg-s-event-listitem');\n  groups.forEach(g => {\n    const nameEl = g.closest('.msg-s-message-group')?.querySelector('.msg-s-message-group__profile-link');\n    const bodyEl = g.querySelector('.msg-s-event-listitem__body');\n    const timeEl = g.closest('.msg-s-message-group')?.querySelector('.msg-s-message-group__timestamp');\n    if (bodyEl?.textContent?.trim()) {\n      messages.push({\n        sender: nameEl?.textContent?.trim() || 'unknown',\n        time: timeEl?.textContent?.trim() || '',\n        text: bodyEl.textContent.trim()\n      });\n    }\n  });\n});\nreturn JSON.stringify(messages);\n\n\nIf the thread is empty or not loading, scroll up in the conversation bubble to load older messages.\n\nStep 4 — Analyse the conversation\n\nWith the full thread loaded + their profile data, determine:\n\nWhat did they say last? — Identify the most recent message from them.\nWhat's the intent? — Interested / wants more info / asked a question / cold / objection / not interested.\nWhat's the right next message? — See Response Playbook below.\nTone — Mirror their tone (casual vs formal, brief vs detailed).\nStep 5 — Draft the follow-up\n\nWrite a response that:\n\nDirectly addresses what they said last\nDoesn't re-pitch unless they asked for it\nMoves toward a specific action (demo, call, intro, forward to team)\nIs brief — 2–4 sentences max\nFeels human, not templated\n\nShow the draft to the user and ask for approval before sending:\n\nDraft reply to [Name]: [message]\n\nSend this? (y / edit / skip)\n\nStep 6 — Send the message\n\nSame JS evaluate method as linkedin-dm:\n\nconst active = document.querySelector('.msg-overlay-conversation-bubble--is-active .msg-form__contenteditable');\nif (active) { active.focus(); document.execCommand('insertText', false, '<message>'); }\n\n\nThen find and click Send.\n\nStep 7 — Update the sheet\n\nAfter sending:\n\ngog sheets update <SHEET_ID> \"Sheet1!J<ROW>:P<ROW>\" \\\n  --values-json '[[\"<new_status>\",\"<last_reply_date>\",\"<last_reply_preview>\",\"<updated_conversation_log>\",\"<next_action>\",\"<ISO_TIMESTAMP>\"]]' \\\n  --input USER_ENTERED\n\nMode 3 — Batch Review\n\nUser says: \"Who needs a follow-up?\" or \"Check my outreach\"\n\nLoad all rows from the sheet.\nFilter by status and time:\nSent older than 3 days → candidate for \"No Response\" or gentle follow-up\nReplied → needs a response\nFollow Up Sent older than 5 days → consider \"No Response\"\nCall Scheduled → check if call happened, update status\nPresent a table of candidates:\nName             Status    Last Updated    Suggested Action\nRishabh Nayan    Replied   2026-02-14      Reply to their message\nShorya Saini     Sent      2026-02-10      Follow-up nudge (4 days)\nShantam Mohata   Sent      2026-02-13      Too soon (today)\n\nUser picks who to action, then enter Mode 2 for each.\nResponse Playbook\n\nUse these as a guide — always adapt to the actual conversation:\n\nThey said\tIntent\tYour move\n\"Sounds interesting, tell me more\"\tCurious\tShort explanation + offer a specific demo slot\n\"How does it work?\"\tExploring\t2-line description + invite to a 15-min call\n\"We already use [X]\"\tObjection\tAcknowledge, explain differentiation, offer demo\n\"Send me more details\"\tSoft interest\tShare a Loom/deck/link + follow up in 2 days\n\"Not relevant right now\"\tSoft no\tRespect it, leave door open: \"No worries, I'll ping you in a few months\"\n\"Who else is using it?\"\tTrust-building\tShare a relevant use case, offer intro to a user\n[No reply in 4 days]\tSilence\tLight nudge: \"Hey [Name], just checking — any thoughts?\"\n[No reply in 8 days]\tCold\tOne final message, then mark No Response\nAnti-Detection Rules\n\nSame rules as linkedin-dm:\n\nAlways go to /feed/ before navigating to a profile\nWait 2–4 seconds after loading feed\nMax 15–20 messages per session (combined sends across follow-ups)\nSpace out follow-ups: don't ping multiple people in rapid succession\nNatural delays between typing and sending (1–2 seconds)\ngog Auth Setup\n\nIf gog auth list returns empty, the user needs to set up Google OAuth credentials:\n\nGo to console.cloud.google.com\nCreate a project (or select existing)\nEnable Google Sheets API (APIs & Services → Library)\nCreate OAuth credentials: APIs & Services → Credentials → Create → OAuth client ID → Desktop App\nDownload client_secret_<id>.json\nRun:\ngog auth credentials set /path/to/client_secret.json\ngog auth add your@gmail.com --services sheets\n\nA browser window will open — log in and grant access\nVerify: gog auth list\n\nFallback (no gog): All sheet reads/writes can be done manually via browser — open the sheet in the openclaw browser and update cells directly. Less automated but functional.\n\nSession Limits\nMax 15–20 follow-up messages per session\nLog every send immediately to sheet (don't batch)\nIf gog is unavailable, log to local linkedin_followup_log.json and sync to sheet next session"
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/10Madh/linkedin-followup",
    "publisherUrl": "https://clawhub.ai/10Madh/linkedin-followup",
    "owner": "10Madh",
    "version": "1.0.0",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/linkedin-followup",
    "downloadUrl": "https://openagent3.xyz/downloads/linkedin-followup",
    "agentUrl": "https://openagent3.xyz/skills/linkedin-followup/agent",
    "manifestUrl": "https://openagent3.xyz/skills/linkedin-followup/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/linkedin-followup/agent.md"
  }
}