{"id":"linkedin-reply-handler","name":"linkedin-reply-handler","summary":"既存のLinkedInコメントに対して、そのURLから返信を下書きしてください。ユーザーが投稿のコメントに返信したい場合や、著者からの返信後にフォローアップしたい場合に使います。","body":"# LinkedIn Reply Handler\n\nDrafts a reply to a specific LinkedIn comment. Correctly handles LinkedIn's 2-level thread flattening: if you're replying to a reply, the Publora API needs the TOP-level comment URN as `parentComment`, not the reply's URN.\n\n## When to use\n\n- User pastes a LinkedIn comment URL (contains `?commentUrn=...`) and says \"reply to this\"\n- An author replied to the user's comment and the user wants to continue the thread\n- User wants to re-engage a conversation that's gone dormant\n\n## Input\n\nA LinkedIn URL containing `commentUrn=urn:li:comment:(activity:POST,COMMENT_ID)` — either the direct comment permalink or a feed URL with the query fragment.\n\n## Output\n\n- 1-2 reply drafts, 150-300 chars each\n- Reaction suggestion for the comment being replied to (always react before replying)\n- Thread context summary (who said what, when)\n- Approval card → on user \"post\", fires reaction + reply via Publora\n\n## Steps\n\n**Voice profile first (all drafts).** If `../../references/voice-profile.md` has `filled: yes`, load it and match the user's voice fingerprint, hard rules, and CTA/link style throughout. If it is not filled, mention once that `linkedin-humanizer --mode profile` can learn their voice from a few posts, then proceed with the generic voice rules.\n\n1. **Parse the URL.** `lib.url_parser.parse_linkedin_url` returns `post_urn`, `comment_id`, `comment_urn`.\n2. **Determine thread structure.** If `APIFY_TOKEN` is set, call `lib.ApifyClient.fetch_post_comments(post_id=post_urn, max_items=50, scrape_replies=True)` and locate the comment by `comment_id`. Otherwise ask the user to paste the relevant slice of the thread. Figure out whether the target is:\n   - a top-level comment (parentComment = this comment's URN when replying)\n   - a reply to a top-level comment (parentComment = the TOP comment's URN, not this reply's URN. LinkedIn flattens)\n3. **Read the full context.** Author post text, top-level comment text, any intermediate replies. Include the user's own prior comment if they're in the thread.\n4. **Draft the reply.** Follow the engagement templates in `references/reply-templates.md`. If the counterpart asked a question, answer it directly. If they pushed back, concede then sharpen.\n5. **Humanizer pass.** Strip em dashes, AI vocab, enforce varied sentence length.\n6. **Approval card.** Include thread preview (who said what in last 3 turns), the draft, reaction suggestion, and the parentComment URN we'll send.\n7. **On approval.** Call `lib.publish(kind=\"reply\", draft_text=<approved>, target_url=<comment_url>, post_urn=<urn>, platform_id=<id>, parent_comment=<top_level_comment_urn>, reaction_type=<chosen>)`. The wrapper handles Publora / manual / diy routing.\n\n## The flattening gotcha\n\nLinkedIn only nests replies two levels deep. Visually the thread looks like:\n\n```\nTop comment by Alice (id: 111)\n└─ Reply by Bob (id: 222)          ← parentComment: urn:li:comment:(activity:POST, 111)\n   └─ Reply by Carol (id: 333)     ← parentComment: STILL urn:li:comment:(activity:POST, 111)\n```\n\nCarol's reply doesn't nest under Bob's — it's pinned at level 2 to the same top comment. If you pass `urn:li:comment:(activity:POST, 222)` as parentComment, the API returns 400 on some paths or silently misplaces the reply.\n\n**Rule in this skill:** always use the TOP-level comment's URN as `parentComment`. If you're replying to a 2nd-level reply, we walk up the tree to find the top comment.\n\n## Templates (`references/reply-templates.md`)\n\n- **R1 Answer-Their-Question** — they asked, you answer plainly + one real detail\n- **R2 Concede-Then-Sharpen** — \"you're right on X, and the piece I'd push on is Y\"\n- **R3 Extend-Their-Thesis** — take their point one layer deeper with a new framing\n- **R4 Share-Lived-Experience** — \"we hit this last quarter — here's what broke\"\n- **R5 Ask-Back** — redirect with a sharper question when their position needs more context\n\n## Hard rules\n\nGlobal voice rules: see root `SKILL.md` §Voice rules. Additional skill-specific rules:\n\n- 150-300 chars. Replies are tighter than top-level comments.\n- React to the comment you're replying to, not to the parent post.\n- Never paste a canned \"thanks!\". Either respond with content or don't reply.\n- If the thread is older than 72 hours, consider a DM instead (use `linkedin-thread-monitor`).\n\n## Example\n\n> User: \"Reply to this: https://www.linkedin.com/feed/update/urn:li:activity:7449018753880834048?commentUrn=urn%3Ali%3Acomment%3A%28activity%3A7449018753880834048%2C7449758545140453376%29\"\n>\n> Skill: parses → post 7449018753880834048, comment 7449758545140453376. Fetches thread. Sees: post-author's post → Serge's comment (\"moat moved to taste\") → author's reply (\"How are you building that conviction muscle with your team?\"). Drafts R1 Answer-Their-Question variant. Shows approval card.\n>\n> User: \"post\"\n>\n> Skill: react APPRECIATION on the author's reply → pause 12s → post reply with parentComment set to Serge's original comment URN (the TOP level, not the author's reply).\n\n## Files\n\n- `SKILL.md` — this file\n- `references/reply-templates.md` — 5 reply templates with examples\n- `references/threading-rules.md` — LinkedIn's 2-level flattening explained with edge cases","author":"@sergebulaev","ownerProfile":null,"authorContacts":null,"sourceUrl":"https://github.com/sergebulaev/linkedin-skills/tree/main/.codex-marketplace/linkedin-skills/skills/linkedin-reply-handler","license":"MIT","category":"document","lang":"en","tokens":1340,"stars":0,"calls30d":0,"claimed":false,"visibility":"public","origin":"crawler","version":"0.1.0","createdAt":"2026-08-22","updatedAt":"2026-08-22","files":[{"path":"references/examples.md","size":742,"sha256":"a8eb8045f7acab59d6cc40b056923a6530b22a4fdd49704b7f61ff280e436336"},{"path":"references/reply-templates.md","size":2258,"sha256":"8b972b5d70fb1771adcf1a9aa491d2e349e16da11cb009f2849cb38395d28f20"},{"path":"references/threading-rules.md","size":2930,"sha256":"f4fd5974a5e9639bbd31bbc1af5e067aa24fc40f71441e2d325b50eefba504cf"}],"requires":{"mcp":[],"tools":[]},"safety":{"flags":[],"scannedAt":"2026-08-22","hasScripts":false,"networkEndpoints":["www.linkedin.com"]}}