Skip to content
cccskills
FreePublished on GitHub

crossposting

Convert Wasp blog articles from MDX, a Markdown format with components, into files for DEV.to and Medium. Create or update DEV.to drafts, prepare Medium content, and optionally upload local videos to YouTube.

OriginalShow the original description

Crosspost Wasp blog articles (MDX) to DEV.to and Medium.

Works withYouTube
See how to install

Good for

  • Prepare Wasp blog articles for DEV.to and Medium
  • Create DEV.to drafts or update existing articles
  • Prepare article sections and images for Medium
  • Upload local videos to YouTube for embedding

Files included (5)

  • SKILL.md4.4 KB
  • README.md709 B
  • scripts/convert-mdx.ts26.2 KB
  • scripts/medium-helpers.js2.7 KB
  • scripts/upload-youtube.ts14.1 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

MDX Conversion Script

Converts a Wasp blog MDX file to clean markdown, HTML, and Medium-ready chunks. Output is saved to .claude/skills/crossposting/scripts/output/.

npx tsx .claude/skills/crossposting/scripts/convert-mdx.ts <path-to-mdx-file> [--publish-devto] [--update-devto <id>] [--upload-videos]

Output files (always written):

  • <slug>.md — clean markdown (for DEV.to)
  • <slug>.html — HTML (for Medium preview/reference)
  • <slug>-medium-chunks.json — { title: string, chunks: string[] } pre-split at <h2> boundaries, pre-escaped for JS template literals

Flags:

  • --publish-devto — POST as draft to DEV.to (requires DEVTO_API_KEY)
  • --update-devto <id> — PUT to existing DEV.to article (requires DEVTO_API_KEY)
  • --upload-videos — upload local .mp4s to YouTube (unlisted), embed as {% youtube URL %} liquid tags

Env vars: DEVTO_API_KEY (from https://dev.to/settings/extensions), YOUTUBE_CLIENT_ID + YOUTUBE_CLIENT_SECRET (saved in 1password for the users).

Notes:

  • canonical_url is auto-generated from MDX filename → wasp.sh/blog/...
  • Without --upload-videos, local .mp4 videos become plain links

YouTube Setup (one-time, human steps)

  1. Create Google Cloud project → enable YouTube Data API v3 → create OAuth 2.0 Desktop credentials
  2. Add YOUTUBE_CLIENT_ID and YOUTUBE_CLIENT_SECRET to ~/.zshrc
  3. Run npx tsx .claude/skills/crossposting/scripts/upload-youtube.ts --auth → authorize in browser (select @wasplang channel if prompted)
  4. Refresh token stored in ~/.youtube-upload-tokens.json
  5. Check channel: npx tsx .claude/skills/crossposting/scripts/upload-youtube.ts --whoami. Wrong channel? Delete token file and re-auth.

Crossposting to Dev.to

Use --publish-devto or --update-devto <id> flags. Requires DEVTO_API_KEY.


Crossposting to Medium

Paste HTML into Medium's editor via Chrome DevTools MCP. The user must be logged in to Medium using email login (not google oauth) with info@wasp-lang.dev.

Steps

1. Convert the MDX article

Run the conversion script, if it hasn't been run yet (see usage above).

Images: Medium does not support webp. Convert webp images to jpg for later manual upload:

for f in static/img/<slug>/*.webp; do sips -s format jpeg "$f" --out ".claude/skills/crossposting/scripts/output/$(basename "${f%.webp}.jpg")"; done

2. Navigate to https://medium.com/new-story

The human user must login to Medium with the info@wasp-lang.dev email and get the OTP sent to your email.

3. Set the article title

Do NOT use the fill tool — it puts text into the body paragraph instead. Use evaluate_script with the setMediumTitle function from scripts/medium-helpers.js.

  1. Read setMediumTitle from scripts/medium-helpers.js.
  2. Replace TITLE_PLACEHOLDER with the actual title (escape backticks and ${ sequences).
  3. Call evaluate_script with the resulting function string.

Then press Enter to move cursor to the body area.

4. Paste the article body

IMPORTANT: Do NOT use document.execCommand — it bypasses Medium's internal state and causes save errors. Always use synthetic ClipboardEvent paste.

IMPORTANT: Chunks are already pre-escaped for JS template literals and pre-processed for Medium (YouTube URLs, image placeholders). Inline each chunk string directly into the pasteMediumChunk function body where HTML_CHUNK_PLACEHOLDER appears. Do NOT base64-encode, store chunks in page variables, or add any intermediate encoding steps.

  1. Read output/<slug>-medium-chunks.json — chunks are ready to paste as-is.
  2. Click the body paragraph to focus it.
  3. For each chunk, use evaluate_script with the pasteMediumChunk function from scripts/medium-helpers.js. Replace HTML_CHUNK_PLACEHOLDER directly with the chunk string content.
  4. Wait for "Saved" status after all chunks are pasted.

5. Verify

  • Snapshot the article to confirm it looks correct and shows "Draft" / "Saved"
  • Scroll through to confirm section order matches the original and make any necessary adjustments.

6. Before Publishing (human steps)

  • Replace [IMAGE: filename.jpg] markers with actual image uploads in Medium's editor
  • Add any YouTube embeds that didn't auto-embed (Medium auto-embeds standalone YouTube URLs in <p> tags)
  • Add the banner image and canonical URL
  • Review and publish from Medium's UI

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

geo-fundamentals

FreeSummary

Review content for citation in AI search answers. Use checklists covering clear definitions, sourced data, author information, FAQs, and structured data, then plan how to monitor citations, brand mentions, and AI-referred traffic.

  • Reviewing articles for citation in AI search answers
  • Organizing definitions, sources, and FAQs in content
  • Checking author details and structured data
wasp-lang/wasp18.8KUpdated Oct 17, 2026

notion-to-blog

FreeSummary

Transfer a Notion blog draft into an MDX file, a Markdown format with components, for the Wasp website. Preserve text formatting, download and optimize images, and prepare metadata and links according to blog conventions.

  • Move a Notion draft into the Wasp blog
  • Convert article images to WebP
  • Preserve headings, code blocks, and text formatting
wasp-lang/wasp18.8KUpdated Oct 17, 2026

social-content

FreeSummary

Create social posts and weekly content calendars tailored to each platform and audience. Repurpose existing articles, plan interactions with readers, and use performance metrics to refine topics, opening lines, formats, and posting times.

  • Plan a weekly social content calendar
  • Adapt blog articles into posts for multiple platforms
  • Write opening lines and post drafts
wasp-lang/wasp18.8KUpdated Oct 17, 2026

wasp-review

FreeSummary

Review code changes for correctness, readable names, clear interfaces, and design problems. Examine duplication, hidden assumptions, and unnecessary abstractions, then report actionable findings with file locations, explanations, and concrete suggestions for fixes.

  • Review pull request changes
  • Check names and function interfaces
  • Find duplication and unclear responsibilities
wasp-lang/wasp18.8KUpdated Oct 17, 2026

See all skills by wasp-lang

Report a problem with this skill