YominPost: a self-hosted AI social media studio

Social MediaAI ContentSelf-HostedMCPClaude CodeCursorPython

Open-source AI social media studio you host yourself: one material in, native posts per platform out, risk-checked before publishing. One uvx line, MCP ready.

View on GitHub →

YominPost in 75 seconds
Write once. Post natively everywhere. Don’t get flagged. YominPost is open source and self-hosted.One idea, five platforms, five rewrites: AI writers stop at a caption.Format router: one material becomes an X thread, a LinkedIn post, an Instagram carousel and a TikTok storyboard, each with a reason.QA self-critique: an illustrative score rising from 0.71 to 0.93 after one rewrite.Risk gate: a prompt leak, engagement bait and hashtag stuffing are flagged and fixed before publishing.Publish for real to 11 channels with tokens encrypted locally. TikTok, Xiaohongshu, Threads and Pinterest are simulated.Quickstart: one uvx line opens the studio, and claude mcp add connects Claude Code. Your agent drafts, you publish.

TL;DR: YominPost is an MIT-licensed, self-hosted AI social media studio. Give it one piece of material: notes, a URL, an announcement, a few image links. It picks the right format for each platform, writes a native post for each one, critiques its own drafts, checks them against the signals that get accounts restricted, and then schedules or publishes them through real OAuth connectors. If you have uv, it is one line and needs no API key: uvx --from git+https://github.com/mrlong0129/yominpost yominpost --open.

It is the largest of the open-source tools I have published so far. The two smaller ones, wechat-article-fetcher and agent-web-fetch, read the web for an agent. YominPost goes the other way: it writes for the web, and it is careful about it.

Why I built a social media studio

Posting one idea to X, LinkedIn, Instagram, TikTok and Telegram means rewriting it five times and guessing which shape each platform rewards. AI writers usually stop at "here is a caption". They don't choose the format, they don't check their own work, and they will happily leave prompt text or engagement bait in the post.

I learned how much that matters the hard way. A brand-new Instagram account I published to was blocked by Meta on its third day: API access blocked on every endpoint, and reconnecting did nothing. The cause was the posting, not the API: the first caption was the LLM prompt itself, the call to action said "comment and I'll DM you", every post linked to the same domain, and automated posting had started on day one. The write-up is in docs/PLATFORM_RISK.md (in Chinese), and it became the risk gate described below.

And hosted schedulers keep your tokens, drafts and analytics in someone else's cloud, with no safe way for Claude Code or Cursor to draft for you. I wanted the whole loop on my own machine: an agent able to help, a human pressing Publish.

How it works: the 8-slot engine

Every run goes through eight capability slots, each a separate stage in yominpost/stages/:

  1. Brand DNA: who is speaking, to whom, in what voice, distilled from your material.
  2. Trends: signals you pass in, folded into the brief.
  3. Ideation and calendar: topics, spread over a posting calendar.
  4. Format router: a rule-based router picks text, thread, image post, carousel or short video for each platform, and records the reasons, so you can see why LinkedIn got a text post and Instagram a carousel.
  5. Copy: hook, body, call to action and hashtags, written for that platform rather than truncated from another one.
  6. Visual: an SVG/JPG poster when the format calls for one.
  7. Video: a short-video storyboard plus an SRT subtitle file.
  8. QA self-critique: the draft is scored. If it misses the bar, the engine writes a critique, rewrites once, and keeps the better of the two versions.

In the web studio this is the Post Creating Loop: paste text, a URL or image links, and one draft per channel appears on an infinite canvas, where you refine any of them in a chat.

The words come from a driver: template (the default: offline, deterministic, no key), claude_code or codex (the local CLI you are already logged into), agy, or anthropic (the API). They form a fallback chain, so a failing driver never breaks a run. Generated copy follows the language of your material: English in, English out, or force it with --language en|zh.

The pre-publish risk gate

Before anything goes out, each post passes a gate built from the reasons AI-assisted accounts actually get restricted:

  • Prompt leak: instructions or scaffolding left in the text, such as "Write a post about…" or "Here is a post".
  • Engagement bait: "Comment GUIDE and I'll DM you", "tag 3 friends". Meta demotes this and escalates against repeat use.
  • Hashtag and link limits per platform.
  • Duplicates: near-identical text, or the same domain posted again and again.
  • Cadence caps: a 24-hour ceiling, a minimum gap between posts, and a warm-up period for new channels. The Instagram defaults, for example, are at most 2 posts a day, 180 minutes apart, and 1 a day for the first 14 days.
  • Auto-freeze: when a platform error looks like a block rather than an expired token, the channel is frozen (72 hours by default). Publishing, health probes and syncing all stop until a person looks. It never retries its way deeper into trouble.

The same check is exposed as the check_post MCP tool. The gate lowers the risk; it cannot promise a platform will never act on an account.

Publishing for real

Real connectors, using OAuth2 + PKCE, tokens or webhooks: X, LinkedIn, Reddit, Facebook Page, Instagram, YouTube Shorts, Discord, Mastodon (with zero-config app registration), Telegram, Bluesky and Webhook. Tokens are Fernet-encrypted on your machine. A scheduler fires due posts on time and never double-posts. There is a calendar, a queue with retry, an asset library, a topic bank, and per-channel health with native signals such as karma, strikes and account status.

It is FastAPI, SQLite and vanilla JavaScript, with no build step. Data lives in ~/.yominpost/. URL fetching is SSRF-guarded, backups run daily, and a public deployment refuses to start without an operator access key.

Quickstart

You only need uv. No install, no config:

# 1) Start the studio (web UI on http://127.0.0.1:8300, data in ~/.yominpost/)
uvx --from git+https://github.com/mrlong0129/yominpost yominpost --open

# 2) Or generate posts straight from the terminal
uvx --from git+https://github.com/mrlong0129/yominpost yominpost run \
  --brand "Acme" --source "Acme turns one long-form idea into ten platform-native posts." \
  --platform x --platform linkedin --platform tiktok --topics 3

Add --json to run for machine-readable output. For model-written copy, set YOMINPOST_PROVIDER=claude_code, codex or anthropic (with ANTHROPIC_API_KEY). To connect real channels, register your own OAuth apps as described in docs/REGISTER_APPS.md, or paste the client IDs once on the Settings page.

Let Claude Code or Cursor draft your posts

Claude Code, one line:

claude mcp add yominpost -- uvx --from git+https://github.com/mrlong0129/yominpost yominpost-mcp

Cursor: the same server in ~/.cursor/mcp.json, or in the project's .cursor/mcp.json.

{
  "mcpServers": {
    "yominpost": {
      "command": "uvx",
      "args": ["--from", "git+https://github.com/mrlong0129/yominpost", "yominpost-mcp"]
    }
  }
}

The agent gets five tools:

  • generate_posts: runs the 8-slot engine and returns per-platform hook, body, CTA and hashtags, the format decision and its reasons, the QA score and issues, and poster and SRT paths.
  • check_post: the risk lint. ok=false means don't publish it as is.
  • save_draft: saves a draft in your local workspace, aimed at your connected channels.
  • list_posts and list_platforms: look around.

There is deliberately no publish tool. The agent drafts and checks. You open the studio, read the drafts, and press Publish, because publishing goes out under your real accounts and cannot be undone.

Or install the skill, which teaches Claude Code or Cursor the same playbook, even without the package:

# Claude Code
mkdir -p ~/.claude/skills/yominpost && curl -fsSL https://raw.githubusercontent.com/mrlong0129/yominpost/main/skill/SKILL.md -o ~/.claude/skills/yominpost/SKILL.md
# Cursor
mkdir -p ~/.cursor/skills/yominpost && curl -fsSL https://raw.githubusercontent.com/mrlong0129/yominpost/main/skill/SKILL.md -o ~/.cursor/skills/yominpost/SKILL.md

Coding-agent instructions, for using the tool or working on the repo, are in AGENTS.md.

Honest limitations

  • The web UI is in Chinese for now. Generated copy follows your material, so English in gives English out. An English UI is on the roadmap, and PRs are welcome.
  • The offline template driver is scaffold quality. It is good for trying the workflow and running the tests with zero keys. For copy you would actually post, use claude_code, codex or anthropic.
  • TikTok, Xiaohongshu, Threads and Pinterest are simulated. You can plan and draft for them, but they do not publish until their APIs are wired in.
  • The MCP server cannot publish, by design. An agent drafts, a person approves.
  • It is a single-user app you run yourself, not a SaaS. You bring your own OAuth apps, and you back up ~/.yominpost/, including the encryption key, or stored tokens cannot be decrypted.

When to use YominPost (and when not to)

It is for indie hackers, founders and solo marketers posting to three or more platforms, developers who want their agent to draft launch posts safely, small teams who want a Postiz or Buffer style workflow with an AI engine on their own server, and creators who write in both Chinese and English. Version 0.1.0 is the first public release. I wrote earlier, in Chinese, about turning this blog into a YominPost channel.

Pick something else if you need a hosted, multi-user team product, real TikTok, Xiaohongshu, Threads or Pinterest publishing today, or an English web UI right now.

FAQ

What is YominPost?

YominPost is an open-source (MIT), self-hosted AI social media studio. You give it one piece of material and it produces a platform-native post for each channel, scores and rewrites its own drafts, runs a pre-publish risk check, and schedules or publishes through real OAuth connectors. It is a Python app (FastAPI + SQLite) with a web UI, a CLI and an MCP server.

How do I turn one piece of content into posts for every platform?

Run uvx --from git+https://github.com/mrlong0129/yominpost yominpost --open and paste your material into the studio, or use the terminal: yominpost run --brand "Acme" --source "..." --platform x --platform linkedin --platform tiktok. The format router picks text, thread, image post, carousel or short video per platform and explains why, then writes each version natively.

Do I need an API key to use YominPost?

No. The default template driver runs offline and deterministically, so the whole flow and the test suite work with zero keys. Its output is a scaffold. For copy you would post, set YOMINPOST_PROVIDER to claude_code or codex (the CLI you are already logged into) or anthropic with ANTHROPIC_API_KEY.

How do I let Claude Code or Cursor draft social media posts?

Register the MCP server: claude mcp add yominpost -- uvx --from git+https://github.com/mrlong0129/yominpost yominpost-mcp, or add the same command to ~/.cursor/mcp.json for Cursor. The agent gets generate_posts, check_post, save_draft, list_posts and list_platforms. There is no publish tool on purpose: you review the drafts and press Publish in the studio.

Which platforms can YominPost publish to?

Real publishing works for X, LinkedIn, Reddit, Facebook Page, Instagram, YouTube Shorts, Discord, Mastodon, Telegram, Bluesky and Webhook. TikTok, Xiaohongshu, Threads and Pinterest use a simulated connector for now, so you can draft for them but they do not publish yet.

How does YominPost keep AI-written posts from getting an account flagged?

Every post passes a pre-publish risk gate: prompt-leak and engagement-bait detection, hashtag and link limits, duplicate detection, per-platform cadence caps with a warm-up period for new channels, and an automatic freeze (72 hours by default) when a platform error looks like a block. It lowers the risk; no tool can guarantee a platform will never act.

How is YominPost different from Postiz or Buffer?

It shares the connect, compose, schedule and publish backbone, and adds an AI engine that chooses formats and critiques itself, a risk gate built for AI-assisted posting, and an MCP server for coding agents. It is a single-user app you host yourself, with data and encrypted tokens in ~/.yominpost/, not a SaaS. The web UI is currently in Chinese.