USP – Write once in Markdown, post everywhere USP is a new open-source tool that lets users write content once in Markdown and publish it to multiple social media platforms including X, LinkedIn, Reddit, Telegram, Bluesky, Mastodon, Discord, Aegea, and Threads. The tool supports both raw posting and AI-rewritten versions tailored to each platform, and can be used via terminal, pipe, or GitHub Action. Write once in Markdown. Post everywhere. usp publishes one Markdown file to X, LinkedIn, Reddit, Telegram, Bluesky, Mastodon, Discord, Aegea, and Threads — each target posted as-is or rewritten by an LLM to fit the platform. One source, many platforms — images and threads preserved. With or without AI — raw text, or LLM-tailored per platform. Preview the generated text for every platform before anything goes live. Scriptable — terminal, pipe, or GitHub Action. Legend: ✅ supported, 🚧 WIP, ❌ not supported, — n/a. | Destination | Text | Images | Thread | API | Browser | Setup | |---|---|---|---|---|---|---| | Developer portal https://developer.x.com/en/portal/dashboard Developer apps https://www.linkedin.com/developers/apps OAuth apps https://www.reddit.com/prefs/apps Telegram https://telegram.org/ BotFather https://t.me/BotFather Bluesky https://bsky.app/ App passwords https://bsky.app/settings/app-passwords Mastodon https://mastodon.social/ New application https://mastodon.social/settings/applications/new Discord https://discord.com/ Aegea https://blogengine.me/ Threads https://www.threads.net/ Meta app https://developers.facebook.com/ Reddit posts via the OAuth submit endpoint self-posts , so local images are linked in the body rather than uploaded. Browser posting Playwright currently backs X; everything else is native API. curl -fsSL https://raw.githubusercontent.com/adamarutyunov/usp/main/install.sh | sh VERSION=v1.0.1 to pin The installer clones the repo, builds, and links usp globally, and pulls Playwright Chromium. Install Google Chrome for usp login . For a manual setup, see From Source from-source . usp setup provider/model, accounts, targets, prompts, defaults usp login x only for browser-backed platforms X today ; API platforms skip this usp publish ./post.md usp setup writes credentials to ~/.config/usp/social-auth/ and routing to ~/.usp.yml . usp publish ./post.md publish usp preview ./post.md generate + save per-platform text, no posting usp publish --input " Title\n\nBody" cat post.md | usp publish --stdin Without --target , usp opens an interactive tree to set each target to off , as-is raw Markdown , or LLM rewritten . The first publish offers to save that selection as the default. Pass --target platform/account/name repeatable to skip the tree. usp preview ./post.md writes one Markdown file per target into a sibling post.usp-preview/ folder e.g. post.usp-preview/x-main-default.md , with posts separated by a line of dashes: First tweet of the thread. ---------- Second tweet, with an image. alt ./chart.png Edit those files freely — rewrite text, move images, or add/remove dash lines to split or merge posts. The dash lines and post lengths are yours to manage; usp does not re-split edited previews. On the next usp publish ./post.md it finds the folder and offers to reuse your edited text or regenerate from source. Re-running usp preview overwrites the folder after a confirm . Markdown images keep their position — text around an image splits into separate posts in a thread: First post. alt ./chart.png Next post. Merged in order, later wins: ~/.config/usp/config.yml global ~/.usp.yml or ~/usp.config.yml project: accounts, targets, profiles ~/.config/usp/social-auth/ .yml credentials setup writes these --set key.path=value per-invocation override Auto-discovery only looks in your home directory — never the current working directory. Pass --config