How to Let Hermes Agent Post to Social Media
Add a hosted MCP server to ~/.hermes/config.yaml, install the Social by InstantDM skill, reload, list_accounts, then drafts only. Hermes cron must not publish_now.
Can Hermes Agent post to Instagram, LinkedIn, X and TikTok?
Yes, after you plug in a publisher. Hermes will not grow a Graph API out of the learning loop. Nous Research’s docs do not ship Instagram or LinkedIn publishers. You add a hosted MCP server under mcp_servers in ~/.hermes/config.yaml, put a scoped key in ~/.hermes/.env, install the skill so the model does not invent UTC, reload, call list_accounts, then save drafts. Cron may wake and write. Cron may not call publish_now.
I build Social by InstantDM. We sell the scheduler. Same MCP URL we give Claude and OpenClaw: https://social-api.instantdm.com/mcp. Swap the URL if you use someone else; the YAML shape stays. This page is the Hermes-shaped wiring — every command, every payload, every failure I have watched an always-on learner walk into.
hermes-agent.nousresearch.com. Notice it is a runtime with memory, cron and a learning loop. There is no social calendar and no OAuth button. Publishing is a separate API.
If you are mixing the Hermes LLM with Hermes Agent, stop. The models are fine-tunes. The agent is the Python process that calls tools. You can point the agent at Claude, GPT, a Hermes checkpoint, OpenRouter, or Nous Portal. Definition: What is Hermes Agent?. Comparison: OpenClaw vs Hermes. Protocol: MCP for social media.
What do you need before you edit any YAML?
- Hermes installed and
hermes doctorclean. Linux, macOS, WSL2:curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash, thensource ~/.bashrcandhermes setup. Windows PowerShell:iex (irm https://hermes-agent.nousresearch.com/install.ps1). Do not grant posting tools to a doctor that is already red. - A scheduler workspace with connected social accounts. social-app.instantdm.com. Official OAuth only. Instagram needs a professional account. One workspace per brand.
- A scoped API key with
accounts:read,posts:read,posts:write,media:write. Optionalanalytics:read. Leaveplatform:proxyoff. - Gateway running if you talk from Telegram (
hermes gateway). CLI-only users still need the env the process actually sees. - A SOUL.md that forbids
publish_nowunless you said “publish now.” Hermes’s learning loop will try to skill-ize a successful live post. SOUL is the constitution. Skills are statutes.
Hermes lives in YAML and cron. That is the appeal. It is also why a bad prompt in hermes cron create repeats every weekday at 08:00 until you notice.
How do you put the API key where the gateway can see it?
~/.hermes/.env:
SOCIAL_BY_IDM_API_KEY=sk_live_YOUR_KEY
No quotes unless the value itself contains spaces (it should not). No export keyword in .env. No trailing space. The file should not be in git. Mode:
chmod 600 ~/.hermes/.env
The gateway process must be restarted — or at least re-read env — after you add the line. A key in .env that the CLI sees and the gateway does not is the number-one “it asked me to paste the key in Telegram” bug. Telegram is not a secret store. If the key already landed in a chat, rotate it in the dashboard (Developer → API keys) and update .env.
Do not put the raw key in config.yaml if you can interpolate:
headers:
X-Api-Key: "${SOCIAL_BY_IDM_API_KEY}"
Some Hermes builds want Authorization: Bearer ${SOCIAL_BY_IDM_API_KEY} instead of X-Api-Key. Our server accepts both on the REST side and the MCP side. If tools/list is empty, try the other header before you rotate the key. Rotating a working key because the client sent the wrong header wastes a morning.
URL-only fallback, if a given Hermes build cannot set headers:
https://social-api.instantdm.com/mcp?key=sk_live_YOUR_KEY
Treat that URL as a secret. Prefer headers.
How do you add the MCP server in config.yaml?
~/.hermes/config.yaml:
mcp_servers:
social-by-idm:
url: "https://social-api.instantdm.com/mcp"
headers:
X-Api-Key: "${SOCIAL_BY_IDM_API_KEY}"
enabled: true
That is the whole block. Indentation matters. Tabs vs spaces matter. A duplicate mcp_servers: key later in the file silently wins or silently loses depending on the YAML library — grep the file once.
Then:
/reload-mcp
in the CLI session, or restart the gateway:
hermes gateway
Some versions ship hermes mcp install or hermes mcp add. If yours does, it writes the same YAML. Read the file after it runs. Do not assume the wizard picked Streamable HTTP; our server is remote Streamable HTTP, not a local stdio process. There is nothing to pip install for the publisher.
Ask:
What social tools do you have?
You want list_accounts, create_post, update_post, get_post, get_post_status, list_posts, delete_post, upload_media_from_url, create_upload_url, complete_upload, list_media, delete_media, get_analytics, list_platform_posts, delete_platform_post, platform_request — 16 tools, full REST parity. Product: /mcp.
Hermes docs. Notice MCP is a client feature: you point it at a URL. We are not in their tool catalog. You add social-by-idm yourself.
If your build supports an exclude list on MCP tools, exclude anything that publishes immediately from the cron profile. Otherwise default every write to draft: true in the prompt and in SOUL.md. Defense in depth.
How do you install the Social by InstantDM skill on Hermes?
hermes skills install github:instant-dm/agent-mode/skills/social-by-idm
GitHub source, not ClawHub. Hermes does not use ClawHub as its primary registry. The portable unit is the folder. We tell Hermes to clone the same SKILL.md OpenClaw gets from @sanjaykhanssk/social-by-idm. Install notes. Format: SKILL.md on OpenClaw and Hermes.
The skill tells Hermes:
- Stop if the API key is missing — do not hunt
.envfiles, do not readconfig.yamlinto a caption. list_accountsbefore any write.- Prefer
draft: trueunless you said “publish now.” - Put a timezone offset on
scheduledAt. - Call
get_post_statusafter publish — HTTP 200 is not “all five networks live.” - Never fake likes or duplicate the same caption+image across accounts.
It does not install a binary. It does not curl during install. If a lookalike skill runs shell in Prerequisites, abort.
If you migrated from OpenClaw, look in ~/.hermes/skills/openclaw-imports/. Two social skills will argue. Keep one. Pin the vendor skill:
# if your build has curator pin:
hermes curator pin social-by-idm
If the command does not exist yet on your version, the SOUL redundancy is the pin. Hermes’s loop will try to skill-ize “how we posted Tuesdays.” A publishing skill that drifts is how timezone offsets disappear.
What is the first prompt?
In CLI or Telegram:
List my connected accounts. Do not post.
You want real acc_… IDs, platforms, handles. If it asks you to paste a key in chat, you misconfigured env — and the skill should have refused to search disk. That refusal is load-bearing. Do not relax it.
Then:
Load the social-by-idm skill. Draft an X post and a LinkedIn post from these bullets: … Save as drafts. Do not publish.
Then you, in the calendar at social-app.instantdm.com. Hermes will try to be helpful and skip the review if SOUL.md is silent. Write it.
A list_accounts response the agent should read back:
{
"accounts": [
{ "accountId": "acc_8fK2qz", "platform": "instagram", "handle": "@acme", "displayName": "Acme Inc" },
{ "accountId": "acc_p1L9wd", "platform": "linkedin", "handle": "acme-inc", "displayName": "Acme Inc" },
{ "accountId": "acc_x7n2ab", "platform": "twitter", "handle": "@acme", "displayName": "Acme" }
]
}
Empty array: OAuth is not done. Empty tool list: YAML, header, or you forgot /reload-mcp. Wrong IDs: the agent hallucinated acc_instagram_1. Always copy from list_accounts.
socialbyidm.com/mcp. Notice the Streamable HTTP URL and the 16-tool list. Paste that URL into config.yaml. Do not invent a /sse path or a localhost port.
What does a create_post payload look like from Hermes?
Same JSON the OpenClaw path sends. Hermes is the client. We are the server.
Draft only:
{
"accountIds": ["acc_x7n2ab", "acc_p1L9wd"],
"content": "Dark mode is on by default for new workspaces. Existing users: Settings → Appearance.",
"draft": true
}
Scheduled with an offset — always an offset:
{
"accountIds": ["acc_x7n2ab"],
"content": "Dark mode is on by default for new workspaces.",
"scheduledAt": "2026-09-16T09:00:00+05:30"
}
One idea, three captions via platformContent:
{
"accountIds": ["acc_x7n2ab", "acc_p1L9wd", "acc_8fK2qz"],
"content": "Dark mode is on by default for new workspaces.",
"platformContent": {
"twitter": "Dark mode is the default for new workspaces. Existing users: Settings → Appearance.",
"linkedin": "We turned dark mode on by default for new workspaces.\n\nExisting users keep their current theme. The toggle is in Settings → Appearance.\n\nAgent tools did not change — this is a UI default.\n\nWhat else should default to on?",
"instagram": "Dark mode, on by default.\n\nSettings → Appearance for older workspaces."
},
"draft": true
}
Staggered times via platformSchedules:
{
"accountIds": ["acc_p1L9wd", "acc_8fK2qz", "acc_tk01"],
"content": "Dark mode is on by default for new workspaces.",
"scheduledAt": "2026-09-16T08:30:00-04:00",
"platformSchedules": {
"linkedin": "2026-09-16T08:30:00-04:00",
"instagram": "2026-09-16T11:00:00-04:00",
"tiktok": "2026-09-16T18:00:00-04:00"
}
}
Timezone rule, the one Hermes will get wrong without the skill: no offset = workspace timezone, not UTC. Workspace TZ lives in Settings → Timezone and defaults to UTC. A naive 2026-09-16T09:00:00 is 09:00 in that zone. A past or near-now stamp (≤30 seconds) publishes immediately. Put +05:30 or Z on every value, including every platformSchedules entry.
Instagram still needs media. Upload first:
{
"url": "https://cdn.example.com/dark-mode.png"
}
that is upload_media_from_url, which returns mediaId. Then:
{
"accountIds": ["acc_8fK2qz"],
"postType": "image",
"content": "Dark mode, on by default.",
"mediaIds": ["md_1a2b3c"],
"draft": true
}
Carousel: two or more images. One image + postType: "carousel" → 422 post_type_invalid. Local file: create_upload_url with filename and contentType, PUT the bytes to uploadUrl, then complete_upload. Drive preview links are not media.
REST check from the same machine, to separate Hermes bugs from key bugs:
curl "https://social-api.instantdm.com/v1/accounts" \
-H "X-Api-Key: $SOCIAL_BY_IDM_API_KEY"
If curl lists accounts and Hermes does not, /reload-mcp and check which user the gateway runs as.
How should Hermes cron look?
Native cron is why people try to make Hermes a social media manager. Keep the two clocks apart.
| Clock | Owner | Example |
|---|---|---|
| Agent wake | hermes cron | Weekdays 08:00 Asia/Kolkata: draft five posts |
| Network go-live | scheduledAt / platformSchedules | LinkedIn 08:30 America/New_York, IG 11:00, TikTok 18:00 |
A prompt that has survived contact with real brands:
Isolated session. Read SOUL.md. Research today’s niche sources. Produce five drafts (IG, LinkedIn, X, TikTok, Facebook) for this week’s remaining empty slots.
draft: true. Never publish_now. Deliver titles + post IDs to Telegram. Stop.
hermes cron create "0 8 * * 1-5" "Read SOUL.md. Draft five posts for empty slots this week. draft true. Never publish_now. Deliver IDs to Telegram." --name "weekday-drafts" --deliver telegram
--deliver telegram is the review surface. You open the calendar, or you reply with an approve-pack if you built one. Then the publisher clock starts. Always-on calendars.
What cron must not contain: “publish the week’s content,” “go live at 9,” “if the draft looks good just post it.” The model will decide it looks good. Isolated session matters — yesterday’s complaint about a customer should not become today’s LinkedIn caption.
If the VPS was down at 08:00, skip. Do not dump seven posts at 14:02. Catch-up policy belongs in the cron prompt: “If this run is more than 30 minutes late, skip and tell Telegram. Do not burst.”
Hermes also accepts intervals (every 2h) and natural language for cron. The schedule syntax is not the risk. The verb publish_now is the risk.
How do you know it actually posted?
get_post_status. Hermes likes to declare victory after HTTP 200. Status partial means Instagram made it and TikTok did not.
{
"postId": "pst_3kqz1a",
"status": "partial",
"ready": true,
"targets": [
{
"accountId": "acc_8fK2qz",
"platform": "instagram",
"status": "published",
"permalink": "https://www.instagram.com/p/…",
"error": null
},
{
"accountId": "acc_tk01",
"platform": "tiktok",
"status": "failed",
"permalink": null,
"error": "Photo must be JPEG ≤1920px and <10MB"
}
]
}
Tell Telegram the truth: “IG live, TikTok failed, reason: JPEG size.” Do not retry Instagram. Do not invent a permalink for TikTok.
Other states: draft, scheduled, publishing (ready: false while a carousel assembles), published, failed, canceled. Poll get_post_status after publishNow. Do not 50ms-loop it; 120 requests/minute per key, then 429 rate_limited.
update_post activates a draft when you pass scheduledAt or publishNow (response includes activated: true). A bare scheduledAt change moves all targets and clears platformSchedules. If you only wanted to nudge LinkedIn, send platformSchedules only.
LinkedIn personal delete cannot be done via API. delete_post will list it under manual. Hermes must not report “deleted everywhere” when the body says otherwise.
The 2026 app. After cron or a chat draft, this calendar is source of truth. If the row is missing, Hermes role-played a tool call. Check gateway logs for the actual JSON-RPC.
What are the 16 tools, with the scopes Hermes will need?
| Tool | Scope | When Hermes should call it |
|---|---|---|
list_accounts | accounts:read | First. Always. |
create_post | posts:write | After IDs exist. draft: true unless you said otherwise. |
update_post | posts:write | Activate a draft, reschedule, fix a caption. |
get_post | posts:read | Full object + targets. |
get_post_status | posts:read | After any live attempt. Partial is the real failure. |
list_posts | posts:read | ”What’s already queued this week?” |
delete_post | posts:write | Cancel a scheduled post. Check manual. |
upload_media_from_url | media:write | Public image/video URL → mediaId. |
create_upload_url | media:write | Local file, step 1. |
complete_upload | media:write | Local file, step 3 after PUT. |
list_media | media:read | Reuse an asset. |
delete_media | media:write | Cleanup. |
get_analytics | analytics:read | Friday note. Never invent numbers. |
list_platform_posts | posts:read | Native posts, including ones not created here. |
delete_platform_post | posts:write | Delete by platform id where the API allows. |
platform_request | platform:proxy | Opt-in proxy. Off on day one. X disabled. |
Eight platforms: Instagram, Facebook, X, LinkedIn, TikTok, Threads, Pinterest, YouTube. Instagram rejects text-only. Threads is 500 characters. Pinterest wants a board and a link. YouTube is video only with youtubeTitle. Full rules live in /docs.
A thread payload Hermes should not guess:
{
"accountIds": ["acc_x7n2ab"],
"postType": "thread",
"draft": true,
"thread": [
{ "text": "1/ Dark mode is the default for new workspaces." },
{ "text": "2/ Existing users keep their theme." },
{ "text": "3/ MCP tools unchanged — UI only." }
]
}
What goes wrong — 401, 403, empty tools, empty accounts, agent publishes anyway?
| Symptom | Likely cause | Fix |
|---|---|---|
| Empty tools after edit | Forgot /reload-mcp or gateway restart; YAML indent; enabled: false | Reload. Validate YAML. Confirm enabled: true. |
| Empty tools, YAML looks right | Header name (X-Api-Key vs Authorization: Bearer); key not in gateway env | Try the other header. hermes doctor. Restart gateway from a shell that has .env. |
| 401 | Key typo, revoked, space, quotes in .env | Recopy. No quotes. Rotate only if it leaked. |
| 403 | Missing scope (posts:write, accounts:read, media:write) | Add the scope. Do not mint a new key first. |
| Tools present, empty accounts | OAuth not connected; key is a different workspace | Dashboard → Accounts. Check workspace on the key. |
| Agent publishes anyway | Learning-loop homemade skill; SOUL silent; cron prompt | Pin vendor skill. draft: true. Rewrite cron. |
| Agent asks for the key in chat | .env not visible to the process | Fix env. Do not paste. Skill should refuse disk search. |
422 content_invalid | IG without media; caption too long; Threads > 500 | platformContent. Upload media first. |
422 post_type_invalid | Carousel with <2 images | Attach ≥2 or use image. |
| 404 | Hallucinated acc_ / pst_ / md_ | list_accounts / list_posts / list_media again. |
409 publishing | Delete mid-flight | Wait, retry. |
| 429 | >120 req/min | Stop the loop. |
| Wrong hour | Naive scheduledAt | Offset on every stamp. Workspace TZ ≠ UTC unless you set UTC. |
| Two skills fighting | openclaw-imports/ plus GitHub install | Keep one. Pin it. |
| Cron posted a stale stat | Memory had last week’s number; no get_analytics | SOUL: never invent metrics. Cron: drafts only. |
401 body:
{ "error": { "code": "unauthorized", "message": "Missing or invalid API key." } }
403 body:
{ "error": { "code": "forbidden", "message": "Key lacks posts:write." } }
Hermes will sometimes “improve” a failed draft by retrying with publishNow: true. That is a model instinct, not a server feature. SOUL.md plus the skill plus a cron prompt that names draft: true three times is not overkill.
How do you stop Hermes “improving” the publisher?
The learning loop is the product. It is also the way a timezone rule dies.
After a week of successful drafts, Hermes may write ~/.hermes/skills/how-we-schedule-acme.md that encodes this week’s caption style, this week’s 9am Eastern, and a missing offset. Next month the product changed. The homemade skill did not. If it ranks hotter than social-by-idm, drafts start going live at 03:00.
What to do:
- Pin
social-by-idm(hermes curator pinwhen available). - Put “never
publish_nowunless the human said publish now” in SOUL.md. SOUL survives compaction. MEMORY.md does not. - Let Hermes write helpers (“how we turn a changelog into five bullets”), not a second publisher.
- If you already have a homemade social skill, open it, grep for
publishNowand naive timestamps, then delete or pin-disable it.
OpenClaw users make the inverse mistake: no SOUL, five ClawHub skills, LinkedIn-voice on TikTok. Hermes users make this one: one excellent self-authored skill that slowly lies.
github.com/NousResearch/hermes-agent. Notice it is the runtime repo, MIT-licensed, not a scheduler. Stars measure curiosity. They do not measure whether your cron should publish_now.
How does this differ from OpenClaw?
Same 16 tools. Same payloads. Same “first call is list_accounts.” Different config and different personality.
| OpenClaw | Hermes | |
|---|---|---|
| Config | JSON, openclaw mcp add | YAML mcp_servers |
| Skill install | openclaw skills install @sanjaykhanssk/social-by-idm | hermes skills install github:instant-dm/agent-mode/skills/social-by-idm |
| Cron | Automations / heartbeat | Built-in cron with --deliver |
| Risk | Random ClawHub skill | Self-authored skill drift |
| iMessage | Yes | Not the headline |
| Learning loop | Weaker | The point |
You can point both at one key if you like chaos. Better: one agent has posts:write, the other drafts in a text file. OpenClaw posting guide. OpenClaw mcp add.
Claude / ChatGPT / Codex use the same server with different menus — schedule from Claude or ChatGPT. Hermes YAML is closer to Codex’s config.toml than to Claude’s connector dialog.
How do you migrate from OpenClaw without doubling the publisher?
hermes claw migrate --dry-run
hermes claw migrate
Dry-run first. It copies SOUL.md, memories, skills, allowlisted API keys. Multi-agent OpenClaw setups are not a full clone. MCP JSON does not become YAML by magic. Re-add:
mcp_servers:
social-by-idm:
url: "https://social-api.instantdm.com/mcp"
headers:
X-Api-Key: "${SOCIAL_BY_IDM_API_KEY}"
enabled: true
Imported skills land in ~/.hermes/skills/openclaw-imports/. If that folder contains a social skill and you also ran the GitHub install, delete one. Then /reload-mcp. Then the read-only prompt. Then a draft. Then look at the calendar.
Gateway bind: do not put Hermes on the public internet with a posting key. Same rule as OpenClaw’s port 18789. Tailscale, loopback, or a firewall you actually checked.
What should never be in a Hermes social setup?
publish_nowinsidehermes cron create- A homemade skill that omits offsets and drafts
- The API key in Telegram, Discord, or a gist
- Browser automation against Instagram web, or unofficial mobile APIs
- The same caption+image on three IG accounts
- Invented analytics (“we hit 10k likes”) that
get_analyticsdid not return platform:proxyon the weekday key- Two social skills, one of them from
openclaw-imports/
Freeze line, practiced once:
Freeze social. Do not create, schedule, or publish. Confirm the queue is untouched.
Put it in SOUL.md. When a caption is wrong on a live network, freeze first, argue later.
What does a local media upload look like when Hermes is the client?
Public URLs are upload_media_from_url. Local files are three steps. Hermes will try to skip PUT.
# already in config.yaml — reminder, not a second server
mcp_servers:
social-by-idm:
url: "https://social-api.instantdm.com/mcp"
headers:
X-Api-Key: "${SOCIAL_BY_IDM_API_KEY}"
enabled: true
Then the agent should:
- Call
create_upload_urlwithfilenameandcontentType(image/jpeg,video/mp4,application/pdf). - PUT bytes to the returned
uploadUrl. That PUT is HTTPS to object storage, not a second MCP call. - Call
complete_uploadon themediaId. - Call
create_postwithmediaIds,draft: true, andplatformContentif more than one network.
Prompt that forces the sequence:
Upload ./out/dark-mode.jpg via create_upload_url, PUT, complete_upload. Then draft an Instagram image post to acc_… with that mediaId. draft true. Do not publish. Return mediaId and postId.
If Hermes says “uploaded” but list_media shows pending, step 3 never happened. If create_post 404s the media, same. If Instagram 422 content_invalid, you attached nothing.
Windows note: the gateway’s cwd is not your Desktop. Use an absolute path or a URL. WSL2 and native Windows are different filesystems; a /mnt/c/... path the CLI sees may be invisible to a gateway running as a different user.
Platform limits the skill is reminding Hermes of, because the model will blow past them: Instagram 2,200 characters and media required; Threads 500; LinkedIn 3,000 and one media; TikTok JPEG ≤1920px; X 280 on the free tier; Pinterest board + link; YouTube youtubeTitle ≤ 100. platformContent exists so the LinkedIn essay does not become the X post.
How do you verify the whole path in five minutes?
hermes doctoris clean.~/.hermes/.envhasSOCIAL_BY_IDM_API_KEYand mode 600.config.yamlhas themcp_serversblock,enabled: true, URL exactlyhttps://social-api.instantdm.com/mcp./reload-mcpor gateway restart.- “What social tools do you have?” → 16 names.
- “List my connected accounts. Do not post.” → real
acc_IDs. - A draft prompt with
draft: true. - Calendar row exists. You read it. You schedule with an offset or you delete it.
- After any live publish:
get_post_status, includingpartial.
Done is a draft in the calendar, not a live post. Hermes is the learner. We are the last mile. I sell that last mile because OAuth, media validators and per-target status are a product, not a SKILL.md. Connect them, pin the skill, keep cron on drafts.
Product: /agents · /mcp · docs. OpenClaw sibling: How to let OpenClaw post. Skill install: Hermes skill.
Frequently asked questions
Can Hermes Agent post to Instagram and LinkedIn?
Yes, after you add a social MCP server. There is no first-party publisher in Nous's docs. Put the server under mcp_servers in ~/.hermes/config.yaml, set the API key in ~/.hermes/.env, reload, then ask it to list accounts.
What is the Hermes MCP config?
A YAML block with url, headers, and enabled: true. Hermes also supports hermes mcp install on some versions. If tools do not appear, you forgot /reload-mcp or the key is not in the environment the gateway process sees.
Can Hermes cron publish my week automatically?
It can wake and write. It should save drafts and deliver to Telegram. Putting publish_now in a cron prompt is how an always-on learner ships last week's hallucinated stat every weekday at 9.
How do you install the skill on Hermes?
hermes skills install github:instant-dm/agent-mode/skills/social-by-idm — then keep the MCP server anyway. The skill is policy; MCP is the tools.
What is the first prompt after connecting Hermes?
List my connected accounts. Do not post. That calls list_accounts and cannot go live. If Hermes asks you to paste a key in chat, the .env is not visible to the gateway process.
Why did Hermes post at the wrong hour?
scheduledAt had no timezone offset. No offset means workspace timezone, not UTC. Write 2026-09-16T09:00:00+05:30 or Z. Put the same offset on every platformSchedules value.
What does get_post_status partial mean on Hermes?
Some platforms published and others failed. HTTP 200 on create_post is not five green checkmarks. Read the per-target error before telling Telegram it is done.
Will Hermes rewrite the social skill on its own?
It might try. The learning loop skill-izes whatever worked once. Pin the vendor skill and put never-publish-now in SOUL.md so a homemade 'how we posted Tuesdays' file cannot override draft-first.
Can I migrate an OpenClaw social setup to Hermes?
Yes. hermes claw migrate --dry-run first. Skills land in ~/.hermes/skills/openclaw-imports/. Do not keep two competing social skills. Re-add MCP in config.yaml — JSON does not come along for the ride.
Which 16 tools should Hermes list?
list_accounts, create_post, update_post, get_post, get_post_status, list_posts, delete_post, upload_media_from_url, create_upload_url, complete_upload, list_media, delete_media, get_analytics, list_platform_posts, delete_platform_post, platform_request.