ihateposting
v0.6.0
Published
Post to 14 social platforms from your terminal, your CI, or your AI agent.
Maintainers
Readme
ihateposting
Post to 14 social platforms from your terminal, your CI, or your AI agent.
Bluesky · X · LinkedIn · Facebook · Instagram · Threads · Pinterest · TikTok · YouTube · Mastodon · Telegram · Discord · Tumblr · Slack
npm install -g ihateposting
ihateposting login <key> # key from Settings → Developers
ihateposting post "hello" --to bluesky,mastodonRequires an iHatePosting account. Zero dependencies.
Drafts are the default
post saves a draft unless you say otherwise. Publishing to a real audience
takes an explicit --now, and there is no flag that makes it implicit.
ihateposting post "text" --to linkedin # draft
ihateposting post "text" --to linkedin --at "2026-09-01 9:00 AM" # scheduled
ihateposting post "text" --to linkedin --now # publishedTimes are in your account's timezone, the same one the web app uses.
Check before you spend a post
ihateposting post "…" --to x,youtube --now --check--check creates nothing. It runs the same validation the publisher runs
immediately before sending, so what it says is what will really happen —
character counts (X weights links and CJK differently), missing media,
required fields, accounts that are signed out, and your own plan's limits
(an ended trial, a monthly allowance that is full). Exit code 1 means
something would have stopped the post.
Give it the same flags you are about to post with — --now or --at,
--media and any --option. Without them it checks a draft, and a draft is
never capped.
Commands
| | |
|---|---|
| login <key> / logout | store or forget a key on this machine |
| whoami | which account this key belongs to |
| accounts | connected accounts, their handles and state |
| platforms | per-platform limits, required fields, media rules |
| boards | Pinterest board ids for --option pinterest.boardId (--account <id> picks the account) |
| posts | your posts, newest first, and their status |
| upload <file> | put an image or video in your media library; prints its id |
| post "text" --to <list> | draft, schedule, or publish |
| skill | write the AI agent skill into this project |
accounts, platforms, boards and posts take --json.
posts takes filters: --status (draft, scheduled, published, partial or
failed), --from 2026-12-01 and --to 2026-12-31 (scheduled dates,
inclusive), and --limit (default 50, at most 200).
upload takes --alt "a cat" for alt text, which several networks publish,
and --json to print the whole asset instead of just its id. Attach uploads
to a post with --media <ids>, comma separated:
id=$(ihateposting upload photo.jpg --alt "Launch day")
ihateposting post "We shipped" --to bluesky,linkedin --media "$id"--to accepts platform names or the account ids from accounts. A name fans
out to every connected account on that platform; use an id to pick one of two
accounts on the same platform.
Platform settings
Some platforms need a setting before they will post: YouTube asks whether a
video is made for kids, Pinterest needs a board. Pass each with
--option <platform>.<key>=<value>, repeated as often as needed, and give
--check the same ones:
ihateposting boards # Pinterest board ids
ihateposting post "New video" --to youtube,pinterest --media "$id" --at "2026-09-01 9:00 AM" \
--option youtube.ytMadeForKids=no --option pinterest.boardId=549755885175000000true and false are switches, '["a","b"]' is a list, and anything else is
sent as text (numbers too, unless platforms --json lists that key as a
number). platforms names what each platform requires. post refuses a flag
it does not know rather than ignoring it, so a setting typed as its own flag
never goes missing quietly.
In CI
There is nothing to log into. Set the key as an environment variable:
export IHATEPOSTING_API_KEY="pk_live_…"
ihateposting post "$MESSAGE" --to linkedin --nowThe environment variable wins over a key stored by login, so a build
machine can never silently post as whoever last used it.
IHATEPOSTING_API_URL overrides the API base if you are self-hosting.
AI agents
ihateposting skillWrites .claude/skills/ihateposting/SKILL.md into the current project. Your
agent then knows how to list accounts, validate a post, schedule one — and
that it must not publish without being asked. Print it instead with
ihateposting skill --print.
For editors that speak MCP, there is a server too: see Settings → Developers,
or ihateposting-mcp.
Where the key lives
~/.ihateposting/config.json, created 0600. logout deletes it.
Keys are created and revoked in Settings → Developers.
MIT
