DEV Community

Alex Towell
Alex Towell

Posted on • Edited on • Originally published at metafunctor.com

Crier: Cross-Post Your Content Everywhere

I've published crier to PyPI - a command-line tool for cross-posting content to multiple platforms simultaneously.

Like a town crier announcing news across the land, crier broadcasts your content to dev.to, Hashnode, Medium, Ghost, WordPress, Bluesky, Mastodon, Threads, Telegram, Discord, and more.

Quick Start

pip install crier
cd your-blog
crier init
Enter fullscreen mode Exit fullscreen mode

The init command walks you through setup: detecting content directories, configuring platforms with API keys.

The Workflow

  1. Your markdown posts with YAML front matter are the source of truth
  2. .crier/registry.yaml tracks what's published where
  3. crier audit shows what's missing or changed
  4. crier publish publishes content
# See what needs publishing
crier audit

# Publish to multiple platforms
crier publish post.md --to devto --to bluesky --to mastodon

# Bulk publish everything missing
crier audit --publish --yes
Enter fullscreen mode Exit fullscreen mode

LLM-Powered Auto-Rewrite

The star feature: short-form platforms like Bluesky (300 chars) and Mastodon (500 chars) need custom summaries. Crier generates these automatically using any OpenAI-compatible LLM:

# Auto-generate short-form content
crier publish post.md --to bluesky --to mastodon --auto-rewrite

# Bulk publish with auto-rewrite
crier audit --publish --auto-rewrite --yes
Enter fullscreen mode Exit fullscreen mode

Simplest setup: If you have OPENAI_API_KEY set, it just works (defaults to gpt-4o-mini).

Or use local models:

# ~/.config/crier/config.yaml
llm:
  base_url: http://localhost:11434/v1  # Ollama
  model: llama3
Enter fullscreen mode Exit fullscreen mode

The LLM generates platform-appropriate summaries that fit within character limits, with automatic retry if output is too long.

Supported Platforms

Platform Type Notes
dev.to Blog Full article support
Hashnode Blog Full article support
Medium Blog Publish/import mode
Ghost Blog Full article support
WordPress Blog Self-hosted or .com
Buttondown Newsletter Email subscribers
Bluesky Social Posts with link cards
Mastodon Social Toots with hashtags
Threads Social Short posts
LinkedIn Social Professional network
Twitter/X Social Copy-paste mode
Telegram Channel Bot posts
Discord Channel Webhook embeds

Bulk Operations with Filters

The audit command supports powerful filtering for targeted bulk operations:

# API platforms only (skip manual/import)
crier audit --publish --yes --only-api

# Long-form only (skip short-form social)
crier audit --publish --yes --long-form

# Random sample of 5 articles
crier audit --publish --yes --sample 5

# Filter by path and date
crier audit content/post --since 1m --only-api --publish --yes

# Combine filters
crier audit content/post --since 1w --only-api --long-form --sample 10 --publish --yes
Enter fullscreen mode Exit fullscreen mode
Filter Description
[PATH] Only scan specific directory
--since Only content from this date (1d, 1w, 1m, or YYYY-MM-DD)
--only-api Skip manual/import platforms
--long-form Skip short-form social platforms
--sample N Random sample of N items
--auto-rewrite Generate short-form content with LLM

Profiles

Group platforms into reusable profiles:

# ~/.config/crier/config.yaml
profiles:
  blogs: [devto, hashnode, medium]
  social: [bluesky, mastodon]
  everything: [blogs, social]  # Profiles can reference other profiles
Enter fullscreen mode Exit fullscreen mode

Then use: crier publish post.md --profile everything

Claude Code Integration

Crier is designed to work with Claude Code. Install the skill:

crier skill install
Enter fullscreen mode Exit fullscreen mode

Then just ask naturally:

  • "Cross-post my latest article to all platforms"
  • "What articles haven't been published to Bluesky?"
  • "Publish this post to Mastodon with a good announcement"

Claude automatically follows the workflow: audit, select, publish (with rewrites for short-form platforms).

Configuration

Global config (~/.config/crier/config.yaml): API keys, profiles, LLM settings

platforms:
  devto:
    api_key: your_key_here
  bluesky:
    api_key: "handle.bsky.social:app-password"
  twitter:
    api_key: manual  # Copy-paste mode

llm:
  api_key: sk-...  # Or set OPENAI_API_KEY env var
Enter fullscreen mode Exit fullscreen mode

Local config (.crier/config.yaml): Project settings

content_paths:
  - content
site_base_url: https://yoursite.com
default_profile: everything
Enter fullscreen mode Exit fullscreen mode

CLI Reference

# Setup
crier init                              # Interactive setup
crier config show                       # View configuration
crier doctor                            # Verify API keys

# Publishing
crier publish FILE --to PLATFORM        # Publish to platform(s)
crier publish FILE --auto-rewrite       # With LLM-generated short-form
crier audit                             # See what needs publishing
crier audit --publish --yes             # Bulk publish all missing
crier audit --publish --auto-rewrite    # Bulk publish with LLM rewrites

# Management
crier list PLATFORM                     # List your articles
crier status [FILE]                     # Show publication status

# Claude Code
crier skill install                     # Install the skill
Enter fullscreen mode Exit fullscreen mode

Links

Top comments (2)

Collapse
 
epenabella profile image
Rick Penabella

looks cool does it work already?

what's your plan with this?

Collapse
 
queelius profile image
Alex Towell

It works well enough for my use-cases.

What's my plan? I have a bunch of content, mostly on my personal blog (metafunctor.com), and I want to use crier to help me crosspost to various platforms. I've been using it, although I often find I need to add features to it to make it do what I want. To use, just pip install crier, and crier init --local inside of your hugo blog (I hope jekyll, etc work too). That creates a hidden .crier dir with a registry to keep track of what content from the blog has been posted. It can use an LLM to auto-rewrite longform to shortform (claude code skill itself can do this, too). It has a lot of bugs to work out, but feel free to try it and contribute or submit feature requests.