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
The init command walks you through setup: detecting content directories, configuring platforms with API keys.
The Workflow
- Your markdown posts with YAML front matter are the source of truth
-
.crier/registry.yamltracks what's published where -
crier auditshows what's missing or changed -
crier publishpublishes 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
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
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
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 |
| 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
| 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
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
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
Local config (.crier/config.yaml): Project settings
content_paths:
- content
site_base_url: https://yoursite.com
default_profile: everything
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
Links
- PyPI: pypi.org/project/crier
- GitHub: github.com/queelius/crier
Top comments (2)
looks cool does it work already?
what's your plan with this?
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.