LinkedIn Reply Handler
Drafts 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.
When to use
- User pastes a LinkedIn comment URL (contains
?commentUrn=...) and says "reply to this"
- An author replied to the user's comment and the user wants to continue the thread
- User wants to re-engage a conversation that's gone dormant
Input
A LinkedIn URL containing commentUrn=urn:li:comment:(activity:POST,COMMENT_ID) — either the direct comment permalink or a feed URL with the query fragment.
Output
- 1-2 reply drafts, 150-300 chars each
- Reaction suggestion for the comment being replied to (always react before replying)
- Thread context summary (who said what, when)
- Approval card → on user "post", fires reaction + reply via Publora
Steps
- Parse the URL.
lib.url_parser.parse_linkedin_url returns post_urn, comment_id, comment_urn.
- 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:
- a top-level comment (parentComment = this comment's URN when replying)
- a reply to a top-level comment (parentComment = the TOP comment's URN, not this reply's URN. LinkedIn flattens)
- 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.
- 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.
- Humanizer pass. Strip em dashes, AI vocab, enforce varied sentence length.
- Approval card. Include thread preview (who said what in last 3 turns), the draft, reaction suggestion, and the parentComment URN we'll send.
- 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.
The flattening gotcha
LinkedIn only nests replies two levels deep. Visually the thread looks like:
Top comment by Alice (id: 111)
└─ Reply by Bob (id: 222) ← parentComment: urn:li:comment:(activity:POST, 111)
└─ Reply by Carol (id: 333) ← parentComment: STILL urn:li:comment:(activity:POST, 111)
Carol'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.
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.
Templates (references/reply-templates.md)
- R1 Answer-Their-Question — they asked, you answer plainly + one real detail
- R2 Concede-Then-Sharpen — "you're right on X, and the piece I'd push on is Y"
- R3 Extend-Their-Thesis — take their point one layer deeper with a new framing
- R4 Share-Lived-Experience — "we hit this last quarter — here's what broke"
- R5 Ask-Back — redirect with a sharper question when their position needs more context
Hard rules
Global voice rules: see root SKILL.md §Voice rules. Additional skill-specific rules:
- 150-300 chars. Replies are tighter than top-level comments.
- React to the comment you're replying to, not to the parent post.
- Never paste a canned "thanks!". Either respond with content or don't reply.
- If the thread is older than 72 hours, consider a DM instead (use
linkedin-thread-monitor).
Example
User: "Reply to this: https://www.linkedin.com/feed/update/urn:li:activity:7449018753880834048?commentUrn=urn%3Ali%3Acomment%3A%28activity%3A7449018753880834048%2C7449758545140453376%29"
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.
User: "post"
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).
Files
SKILL.md — this file
references/reply-templates.md — 5 reply templates with examples
references/threading-rules.md — LinkedIn's 2-level flattening explained with edge cases
Source: hashgraph-online/awesome-codex-plugins → plugins/sergebulaev/linkedin-skills/skills/linkedin-reply-handler/SKILL.md
1---2name: linkedin-reply-handler3description: Draft a reply to a specific existing LinkedIn comment from its URL. Use when the user wants to reply to a comment on any post, or follow up after an author replied to them. Parses the commentUrn, resolves the correct parentComment target (LinkedIn flattens threads to 2 levels), and posts via Publora on approval. Not for top-level comments (use linkedin-comment-drafter).4---567# LinkedIn Reply Handler89Drafts 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.1011## When to use1213- User pastes a LinkedIn comment URL (contains `?commentUrn=...`) and says "reply to this"14- An author replied to the user's comment and the user wants to continue the thread15- User wants to re-engage a conversation that's gone dormant1617## Input1819A LinkedIn URL containing `commentUrn=urn:li:comment:(activity:POST,COMMENT_ID)` — either the direct comment permalink or a feed URL with the query fragment.2021## Output2223- 1-2 reply drafts, 150-300 chars each24- Reaction suggestion for the comment being replied to (always react before replying)25- Thread context summary (who said what, when)26- Approval card → on user "post", fires reaction + reply via Publora2728## Steps29301. **Parse the URL.** `lib.url_parser.parse_linkedin_url` returns `post_urn`, `comment_id`, `comment_urn`.312. **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:32 - a top-level comment (parentComment = this comment's URN when replying)33 - a reply to a top-level comment (parentComment = the TOP comment's URN, not this reply's URN. LinkedIn flattens)343. **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.354. **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.365. **Humanizer pass.** Strip em dashes, AI vocab, enforce varied sentence length.376. **Approval card.** Include thread preview (who said what in last 3 turns), the draft, reaction suggestion, and the parentComment URN we'll send.387. **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.3940## The flattening gotcha4142LinkedIn only nests replies two levels deep. Visually the thread looks like:4344```45Top comment by Alice (id: 111)46└─ Reply by Bob (id: 222) ← parentComment: urn:li:comment:(activity:POST, 111)47 └─ Reply by Carol (id: 333) ← parentComment: STILL urn:li:comment:(activity:POST, 111)48```4950Carol'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.5152**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.5354## Templates (`references/reply-templates.md`)5556- **R1 Answer-Their-Question** — they asked, you answer plainly + one real detail57- **R2 Concede-Then-Sharpen** — "you're right on X, and the piece I'd push on is Y"58- **R3 Extend-Their-Thesis** — take their point one layer deeper with a new framing59- **R4 Share-Lived-Experience** — "we hit this last quarter — here's what broke"60- **R5 Ask-Back** — redirect with a sharper question when their position needs more context6162## Hard rules6364Global voice rules: see root `SKILL.md` §Voice rules. Additional skill-specific rules:6566- 150-300 chars. Replies are tighter than top-level comments.67- React to the comment you're replying to, not to the parent post.68- Never paste a canned "thanks!". Either respond with content or don't reply.69- If the thread is older than 72 hours, consider a DM instead (use `linkedin-thread-monitor`).7071## Example7273> User: "Reply to this: https://www.linkedin.com/feed/update/urn:li:activity:7449018753880834048?commentUrn=urn%3Ali%3Acomment%3A%28activity%3A7449018753880834048%2C7449758545140453376%29"74>75> 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.76>77> User: "post"78>79> 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).8081## Files8283- `SKILL.md` — this file84- `references/reply-templates.md` — 5 reply templates with examples85- `references/threading-rules.md` — LinkedIn's 2-level flattening explained with edge cases8687---8889**Source:** [`hashgraph-online/awesome-codex-plugins`](https://github.com/hashgraph-online/awesome-codex-plugins) → `plugins/sergebulaev/linkedin-skills/skills/linkedin-reply-handler/SKILL.md`