syndicate-article
Syndicates blog posts to developer and crypto communities with optimized hooks.
Install
mkdir -p .claude/skills/syndicate-article-dawsonblock && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/16097" && unzip -o skill.zip -d .claude/skills/syndicate-article-dawsonblock && rm skill.zipInstalls to .claude/skills/syndicate-article-dawsonblock
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Cross-post articles to Dev.to and Farcaster with hook-driven copy and click-optimized metadataKey capabilities
- →Cross-post articles to Dev.to
- →Cross-post articles to Farcaster
- →Extract hook-driven copy from articles
- →Generate click-optimized metadata for Dev.to
- →Build canonical URLs for SEO attribution
How it works
It extracts content from an article, cleans it for syndication, generates channel-specific hooks and metadata, and posts to Dev.to and Farcaster with canonical URLs.
Inputs & outputs
When to use syndicate-article
- →Cross-posting blog articles
- →Syndicating tech content
- →Improving article reach
About this skill
${var} — Filename of a specific article to syndicate (e.g.
repo-article-2026-04-16.md). If empty, syndicates the most recently written article.
Cross-post Aeon articles to Dev.to (developer audience) and Farcaster (crypto-native audience) for organic discovery. Articles are published with a canonical URL pointing back to the GitHub Pages gallery, preserving SEO attribution.
Each channel is opt-in — set the relevant secrets and it activates. If neither is configured, the skill logs a skip and exits silently.
Thesis: The biggest lever in syndication is not "did we post" but "will anyone click." Generic "New post: X\n\nURL" casts and body-only Dev.to articles waste the channel's attention budget. This skill extracts a real hook from the article, adds a cover image and description for Dev.to, and refuses to post if no hook exists.
Prerequisites
DEVTO_API_KEY— Dev.to API key. Generate at https://dev.to/settings/extensions (scroll to "DEV Community API Keys").NEYNAR_API_KEY+NEYNAR_SIGNER_UUID— Neynar credentials for Farcaster posting. Get an API key at neynar.com and create a managed signer to obtain the signer UUID.
If none of DEVTO_API_KEY or NEYNAR_SIGNER_UUID are set, the skill logs a skip and exits silently — no error, no notification.
Steps
1. Channel check
if [ -z "$DEVTO_API_KEY" ] && [ -z "$NEYNAR_SIGNER_UUID" ]; then
echo "SYNDICATE_SKIP: no syndication channels configured"
exit 0
fi
Log SYNDICATE_SKIP: no syndication channels configured to memory/logs/${today}.md and stop. Do NOT send any notification.
2. Select the article
- If
${var}is set, usearticles/${var}. - Otherwise, most recently modified
.mdinarticles/(excludefeed.xml,.gitkeep):ls -t articles/*.md 2>/dev/null | grep -v -E '(feed\.xml|\.gitkeep)$' | head -1 - If no articles exist, log
SYNDICATE_SKIP: no articles foundand stop.
3. Dedup check
Search the last 7 days of memory/logs/ for:
SYNDICATED:lines containing this filename → Dev.to already postedFARCAST:lines containing this filename → Farcaster already queued/posted
Track per-channel. If both already posted, log SYNDICATE_SKIP: already syndicated {filename} to all channels and stop. Otherwise proceed with only the missing channels.
4. Parse the article
- Title: first
# Heading. If Jekyll frontmattertitle:exists, use that. - Body (raw): everything after the first heading (or after frontmatter).
- Date: regex
([0-9]{4}-[0-9]{2}-[0-9]{2})on filename. - Slug: filename prefix before the date, trailing hyphens stripped.
- Cover image (
cover_url): if Jekyll frontmatter hasimage:orcover:, use that; otherwise firstin the body whereurlstarts withhttp. If none found, leave empty. - Description (
meta_description): first paragraph of the body after the title — stripped of markdown, trimmed to 140 chars, ending on a word boundary. Used for Dev.todescriptionand Farcaster hook fallback.
5. Clean the body for syndication
Produce body_clean from the raw body:
- Remove any Jekyll liquid tags (
{% ... %},{{ ... }}) — they render as literal text on Dev.to. - Rewrite relative links/images: any
](/foo)or](foo.md)→ absolutehttps://aaronjmars.github.io/aeon/foo(strip.mdwhere present). Preserve anchor fragments. - Strip the first
# Headingline (Dev.to shows the title separately — double-heading looks amateur). - Trim leading/trailing whitespace.
Keep the pre-cleaned body around as a source for step 6's hook extraction.
6. Extract the Farcaster hook (quality gate)
Farcaster's feed rewards specificity. "New post: Title\nURL" produces near-zero engagement. Extract a real hook from the article:
Hook candidates (try in order, stop at first that passes):
- Explicit TL;DR — if the article has a
## TL;DR,## Summary, or**TL;DR:**block, use its first sentence. - First claim paragraph — the first paragraph of the body that is NOT:
- A question title (ends with
?and <60 chars) - Boilerplate ("In this article...", "Today we'll...", "This post covers...")
- A frontmatter echo (repeats the title)
- A code block, table, list, or image
- Shorter than 40 chars or longer than 400 chars
- A question title (ends with
- Strongest line — scan the first 800 chars of the body for the most specific sentence: contains a number, a proper noun, OR a concrete claim verb ("shipped", "found", "broke", "dropped", "crossed", "beat"). Use that line.
Trim the chosen hook to 240 chars, ending on a word boundary. This leaves ~60 chars for the URL within Farcaster's 320-char limit.
Quality gate: If none of the three strategies produce a hook ≥40 chars, set hook_found=false. Skip the Farcaster step entirely and log FARCAST_SKIP: no hook extractable from {filename}. Do not fall back to "New post: X" — a weak cast is worse than no cast (burns attention, trains followers to scroll past).
7. Build the canonical URL
https://aaronjmars.github.io/aeon/articles/YYYY/MM/DD/<slug>/
Where <slug> matches update-gallery's Jekyll post filename convention: title lowercased, spaces → hyphens, non-alphanumerics stripped, truncated to 50 chars.
8. Dev.to post (if enabled + not already syndicated)
a. Derive tags (max 4, Dev.to hard limit) from the filename slug:
repo-article,article→ai, github, automation, agentstoken-report,token-alert,defi-overview,defi-monitor→crypto, defi, blockchain, tradingchangelog,push-recap,shiplog→opensource, devops, changelog, githubdigest,rss-digest,hacker-news→news, tech, ai, digestdeep-research,research-brief,paper-pick→research, ai, machinelearning, paperstechnical-explainer→tutorial, ai, explainer, programming- Everything else →
ai, automation, agents, programming
b. Write the payload to .pending-devto/<slug>-<date>.json (always use the post-process path; WebFetch cannot reliably pass api-key headers from the sandbox):
mkdir -p .pending-devto/
Payload:
{
"article": {
"title": "<extracted title>",
"body_markdown": "<body_clean>",
"published": true,
"tags": ["tag1", "tag2", "tag3", "tag4"],
"canonical_url": "<canonical_url>",
"description": "<meta_description>",
"main_image": "<cover_url or empty>",
"series": "Aeon"
}
}
Omit main_image from the JSON entirely if cover_url is empty (Dev.to rejects empty-string URLs). Omit description if <20 chars (better to let Dev.to auto-excerpt than feed it garbage).
c. scripts/postprocess-devto.sh POSTs to https://dev.to/api/articles and records the URL on success.
d. Record in memory/logs/${today}.md:
SYNDICATED: {filename} → {canonical_url} (queued for Dev.to, see postprocess log for dev.to URL)
(The Dev.to URL is only known after the postprocess run — the log line matches filename for dedup; a future reconciliation skill or manual check picks up the live URL.)
9. Farcaster cast (if enabled + hook_found + not already syndicated)
a. Build the cast text (320-byte Farcaster limit):
<hook>
<canonical_url>
No "New post:" prefix, no emoji, no hashtags — the hook IS the value. Verify total byte length ≤ 310 (leave 10 bytes buffer for embed unfurl metadata). If over, trim the hook further on a word boundary.
b. Write the payload to .pending-farcaster/<slug>-<date>.json — do NOT include NEYNAR_SIGNER_UUID:
{
"text": "<cast text>",
"embeds": [{"url": "<canonical_url>"}]
}
Use mkdir -p .pending-farcaster/ first.
c. scripts/postprocess-farcaster.sh reads each payload, injects NEYNAR_SIGNER_UUID from env, POSTs to https://api.neynar.com/v2/farcaster/cast with x-api-key: $NEYNAR_API_KEY, removes on success.
d. Record in memory/logs/${today}.md:
FARCAST: {filename} → queued (hook: "{first 60 chars of hook}...")
10. Notification
Send via ./notify only if at least one channel was actually queued (not skipped). Match operator voice — direct, concrete, no hype.
If both Dev.to + Farcaster queued:
Syndicated "{title}"
Dev.to: queued with cover image and description.
Farcaster: hook ready — "{first 80 chars of hook}..."
Canonical: {canonical_url}
If only Dev.to (Farcaster skipped on quality gate or missing secret):
Syndicated "{title}" to Dev.to
Farcaster skipped ({reason: no hook extractable / not configured}).
Canonical: {canonical_url}
If only Farcaster (Dev.to skipped or missing secret):
Cast queued for "{title}"
Hook: "{first 80 chars}..."
Canonical: {canonical_url}
If nothing queued (both already syndicated, or neither passed gates), do NOT notify.
Sandbox note
- Dev.to: Always writes to
.pending-devto/.scripts/postprocess-devto.shexecutes the actual API call after Claude finishes, outside the sandbox. Avoids the env-var-in-headers problem entirely. - Farcaster: Writes
.pending-farcaster/<slug>-<date>.json(no signer_uuid on disk);scripts/postprocess-farcaster.shinjects the signer UUID from env at post time and POSTs to Neynar.
Why the quality gate matters
Dropping weak casts is a feature, not a bug. Each low-effort cast trains followers to scroll past the next one — the compounding cost of "new post: X" over 100 posts is worse than posting 60 with hooks and skipping 40. If the article doesn't yield an extractable hook, that's signal the article needs a stronger opener; fix the article, don't launder the cast.
Output (summary block)
End with:
## Summary
- Article: {filename}
- Dev.to
---
*Content truncated.*
When not to use it
- →When no syndication channels (Dev.to or Farcaster) are configured
- →When no hook can be extracted from the article for Farcaster
- →When the article has already been syndicated to all configured channels
Prerequisites
Limitations
- →Requires DEVTO_API_KEY for Dev.to posting
- →Requires NEYNAR_API_KEY and NEYNAR_SIGNER_UUID for Farcaster posting
- →If no hook can be extracted, Farcaster posting is skipped
How it compares
This skill automates article syndication with a focus on engagement and SEO, using specific strategies to create compelling posts for each platform, unlike simple content duplication.
Compared to similar skills
syndicate-article side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| syndicate-article (this skill) | 0 | 2mo | Review | Intermediate |
| citedy-content-writer | 0 | 3mo | No flags | Intermediate |
| seo-optimizer | 33 | 8mo | No flags | Intermediate |
| seo-content-writer | 24 | 4mo | No flags | Beginner |
Try saying
Example prompts that trigger this skill in your AI assistant.
You might also like
citedy-content-writer
citedy
>
seo-optimizer
davila7
Search Engine Optimization specialist for content strategy, technical SEO, keyword research, and ranking improvements. Use when optimizing website content, improving search rankings, conducting keyword analysis, or implementing SEO best practices. Expert in on-page SEO, meta tags, schema markup, and Core Web Vitals.
seo-content-writer
sickn33
Writes SEO-optimized content based on provided keywords and topic briefs. Creates engaging, comprehensive content following best practices. Use PROACTIVELY for content creation tasks.
executing-marketing-campaigns
davila7
Plans, creates, and optimizes marketing campaigns including content strategy, social media, email, and analytics. Helps develop go-to-market strategies, campaign messaging, and performance measurement.
content-creation
anthropics
Draft marketing content across channels — blog posts, social media, email newsletters, landing pages, press releases, and case studies. Use when writing any marketing content, when you need channel-specific formatting, SEO-optimized copy, headline options, or calls to action.
social-content
davila7
When the user wants help creating, scheduling, or optimizing social media content for LinkedIn, Twitter/X, Instagram, TikTok, Facebook, or other platforms. Also use when the user mentions 'LinkedIn post,' 'Twitter thread,' 'social media,' 'content calendar,' 'social scheduling,' 'engagement,' or 'viral content.' This skill covers content creation, repurposing, and platform-specific strategies.