Back to Blog

One SKILL.md, Every Agent: How to Give Any AI Agent the Ability to Post to X

@brankopetric0010 min read
One SKILL.md, Every Agent: How to Give Any AI Agent the Ability to Post to X

One SKILL.md, Every Agent: How to Give Any AI Agent the Ability to Post to X

Short answer: One markdown file with a small YAML header, dropped into a skills directory, teaches more than 30 different AI agents to post to X. You write it once. Claude Code, Codex CLI, Cursor, Gemini CLI, GitHub Copilot and OpenClaw all read the same format without modification.

The qualifier: a skill is instructions, not a connection. The file below tells your agent how to post. The actual posting happens through the OpenTweet REST API, which holds your X connection, so there is no X developer account and no OAuth app in the loop.

The 30-Second Version

Three things:

  1. The file. Copy the SKILL.md further down this page.
  2. The directory. Save it as post-to-x/SKILL.md inside your agent's skills folder. For Claude Code that is .claude/skills/.
  3. The key. export OPENTWEET_API_KEY=ot_your_key from your developer page.

Then say: "Draft a tweet about the release and schedule it for 9am tomorrow." Your agent finds the skill, reads it, and calls the API.

What SKILL.md Is (And Why It Matters More Than MCP Here)

The SKILL.md spec was published at agentskills.io on December 18, 2025 as an open, vendor-neutral format. It is deliberately unglamorous: a markdown file, a name, a description, and a body. The description is the routing layer. The agent reads it to decide whether the skill is relevant to what you just asked, and only then loads the body into context.

That design is why adoption moved so fast. There is no SDK, no runtime and no protocol handshake to implement. Supporting skills means "read markdown files from a directory," which is a weekend of work for an agent vendor. By March 2026 more than 30 tools were reading the same files, and Google's Antigravity shipped support in January 2026.

For anyone trying to make an agent do a specific job, that is the whole point. Write one file, and every agent that follows the convention can do the job. No per-agent plugin, no per-agent config schema.

Which agents read SKILL.md today

As of September 2026, the format is read by, among others:

Category Agents
Terminal agents Claude Code, Codex CLI, Gemini CLI, OpenCode, Amp, Goose
Editors and IDEs Cursor, GitHub Copilot, Google Antigravity, Trae, Roo Code, Junie, Kiro
Autonomous frameworks OpenClaw, Hermes Agent, OpenHands, Letta

If your agent is not on that list, check its docs for a skills directory before assuming it is unsupported. The count keeps moving. For a fuller breakdown of which agents can actually publish to X versus which can only draft, see which AI agents can post to X in 2026.

Skill vs MCP: when to use which

They solve different halves of the same problem.

You want Use
One tightly scoped job with your own rules attached A SKILL.md
Typed tools, structured arguments, live data back An MCP server
Posting policy: voice, cadence, never-publish-directly A SKILL.md
The full surface: threads, evergreen, articles, analytics MCP, currently 43 tools
Something that also works in a shell script or CI The REST API directly

The honest recommendation: if you only want your agent to post and schedule, the skill is enough and it is 40 lines. If you want the agent to read analytics before deciding what to post, you want MCP. Running both is fine, and it is what I do. The MCP server supplies the tools, the skill supplies the rules.

One thing to be clear about, because other pages get this wrong: OpenTweet does not publish a skills-marketplace package, and there is no npx one-liner that installs an OpenTweet skill. Any page telling you to run one is inventing it. The file below is the artifact. Copy it.

The Skill, In Full

Save this as SKILL.md inside a folder named post-to-x.

---
name: post-to-x
description: Post, schedule, and thread on X (Twitter) through the OpenTweet API. Use when the user asks to tweet, post to X, schedule a post, or announce something on Twitter.
---

# Post to X

Post through the OpenTweet REST API. The key is in the OPENTWEET_API_KEY
environment variable. Base URL: https://opentweet.io

## Check first, always

curl -s https://opentweet.io/api/v1/me \
  -H "Authorization: Bearer $OPENTWEET_API_KEY"

Confirm subscription.has_access is true and limits.remaining_posts_today
is above zero before scheduling or publishing.

## Schedule a tweet (preferred default)

curl -X POST https://opentweet.io/api/v1/posts \
  -H "Authorization: Bearer $OPENTWEET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text": "Tweet text here",
       "scheduled_date": "2026-09-10T09:00:00Z",
       "platforms": ["x"]}'

## Publish immediately (ask the user first)

curl -X POST https://opentweet.io/api/v1/posts \
  -H "Authorization: Bearer $OPENTWEET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text": "Tweet text here", "publish_now": true,
       "platforms": ["x"]}'

## Post a thread

curl -X POST https://opentweet.io/api/v1/posts \
  -H "Authorization: Bearer $OPENTWEET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text": "First tweet", "is_thread": true,
       "thread_tweets": ["Second tweet", "Third tweet"],
       "scheduled_date": "2026-09-10T09:00:00Z"}'

## Rules

- 280 characters per tweet. Count before sending, do not truncate silently.
- Never send publish_now and scheduled_date in the same request.
- scheduled_date is ISO 8601 and must be in the future.
- Always show the drafted text to the user and wait for approval
  before publishing. Publishing to X cannot be undone.
- Default to scheduled_date. Only use publish_now when asked for it.
- Omitting "platforms" does not mean X only. It hands targeting to the
  user's cross-post setting. Send ["x"] when the user asked for X only.
- Report the id from the response. It is a 24-character hex string.
  If you cannot show one, the call did not happen.
- A published post returns status "posted" and a url field. Use that
  url. Never construct an X URL yourself.
- 403 means no subscription or no connected X account. 429 means a rate
  or daily limit was hit. Report the error. Do not retry blindly.
- Rate limits: 60 requests per minute on Pro, 300 on Advanced.

Frontmatter

Two fields carry all the weight. name must match the folder name. description is the only part the agent reads before deciding to load the skill, so it should contain the words a user would actually say: "tweet," "post to X," "schedule," "Twitter." A vague description means the skill never fires.

The body: what the agent needs to know

Everything else is context that gets loaded once the skill is selected. Four things belong in it:

  • The endpoint and the auth header. POST /api/v1/posts with Authorization: Bearer $OPENTWEET_API_KEY. Note the path: it is /api/v1/posts, not /tweets.
  • The fields. text is required. Add scheduled_date to schedule, publish_now: true to send now, platforms to pin the networks, is_thread plus thread_tweets for threads.
  • The limits. 280 characters per tweet. Dates must be ISO 8601 and in the future. 60 requests per minute on Pro, 300 on Advanced.
  • The failure modes. A 403 means no active subscription or no connected X account. A 429 means a rate limit, a daily post limit, or the separate daily cap on posts containing links. Telling the agent what these codes mean is the difference between a useful error message and a retry loop.

The ## Rules section is the real payload. It is where posting policy lives, and it is the reason to write a skill instead of just handing the agent an API doc. Extend it with your own voice guidelines, banned topics, or a hard "never publish on a Friday" rule.

Where to put the file

Agent Path
Claude Code, project .claude/skills/post-to-x/SKILL.md
Claude Code, everywhere ~/.claude/skills/post-to-x/SKILL.md
Cross-vendor convention .agents/skills/post-to-x/SKILL.md in the project root

Agents that follow the shared convention read .agents/skills/ from the project root, which is what makes the file portable. Some vendors also keep a home-directory location for globally available skills. Check your agent's docs for the exact global path rather than guessing, because that is the one detail that still varies between them.

Installing It in Six Agents

Claude Code. Create .claude/skills/post-to-x/SKILL.md, export OPENTWEET_API_KEY, and ask it to tweet. Full walkthrough with both paths on the Claude Code Twitter skill page.

Codex CLI. Drop the file in the project's skills directory and start a session from the project root so it is discovered.

Cursor. Project-local skills folder. Cursor loads skills for the workspace you have open, so put it in the repo you post from.

Gemini CLI. Same shared convention, project root. Confirm the skill loaded by asking "which skills do you have?" before you trust it with a live post.

Google Antigravity. Added skill support in January 2026 and reads the same file.

OpenClaw. Skills go in OpenClaw's skills directory alongside its other capabilities. OpenTweet ships a much larger OpenClaw skill covering evergreen, articles, DM campaigns and analytics, described in the OpenClaw posting guide.

In every case, verify before you trust it. Ask the agent to run the GET /api/v1/me call from the skill. If it returns your handle and your remaining daily posts, the skill loaded and the key works. If it returns 403, the key is wrong or no X account is connected.

Making It Safe

Publishing to X is irreversible. Deleting a tweet is not the same as never having sent it. Three rules keep an agent from embarrassing you:

  1. Default to scheduled_date, not publish_now. A scheduled post sits in a queue you can look at. A published one is already public. The skill above encodes this as an explicit rule, which matters more than you would think, because agents copy whichever example is closest to the request.
  2. Keep a human in the loop for the send. "Show me the draft and wait" is one line in the rules section and it removes the entire class of failure where the agent posts a half-finished thought.
  3. Never hardcode the ot_ key in the file. Use $OPENTWEET_API_KEY. Skills get committed to repos and pasted into issues. Keys in markdown end up on GitHub.

One more, less obvious: be explicit about platforms. Leaving it out does not mean "X only," it hands targeting to whatever cross-post setting your account has. If you have Bluesky connected and the agent omits the field, the post goes to both. Sending "platforms": ["x"] is always honored exactly.

When You Outgrow the Skill

A skill is a good fit for one job. Once you want the agent to do several, the markdown starts fighting you, because every additional endpoint is more context loaded on every invocation.

That is the point to switch to the MCP server. It exposes 43 typed tools: threads up to 25 tweets, batch scheduling up to 50 posts at once, the evergreen recycling queue, X Articles from markdown, best-posting-time analysis, content gaps, multi-account targeting and engagement analytics. The agent gets structured arguments and structured responses instead of parsing curl output.

Setup is one command in most clients. See the MCP server docs or how to give an MCP agent a Twitter tool. If you are wiring this into a framework rather than a chat client, tweeting from the OpenAI Agents SDK covers the same API from code.

Frequently Asked Questions

What is a SKILL.md file and how do I write one?

A plain markdown file with a YAML frontmatter block containing name and description. The agent reads the description to decide when the skill applies, then loads the body as instructions. Write the job in the frontmatter, the exact commands and rules in the body. No build step, no code.

Is there a skill that lets any AI agent post to Twitter?

Yes, and it is the file in this post. Because the format is read unmodified across more than 30 agents, one file covers Claude Code, Codex CLI, Cursor, Gemini CLI, OpenClaw and the rest. Paste it, set OPENTWEET_API_KEY, ask your agent to post.

Do I need an X developer account?

No. The skill calls OpenTweet, which holds the X connection. You connect X once in the dashboard. No developer application, no OAuth app, no per-post X API billing.

How much does it cost?

OpenTweet Pro is 11.99 per month and includes API access, which is what the skill uses. There is a 7-day free trial. Creating drafts through the API is free; scheduling and publishing need an active subscription.

Why does my agent ignore the skill?

Almost always the description. If it does not contain the words you actually say, the agent never routes to it. Make sure "tweet," "post to X," "schedule" and "Twitter" all appear in it. Second most common cause: the file is in a project-local directory and you started the agent from a different folder.

Can the skill post threads?

Yes. is_thread: true plus a thread_tweets array, up to 25 tweets, each under 280 characters. The example above includes it.

Get Started

  1. Sign up for OpenTweet (7-day free trial, no credit card) and connect your X account.
  2. Get your API key. It starts with ot_.
  3. Copy the SKILL.md above into post-to-x/SKILL.md in your agent's skills directory.
  4. export OPENTWEET_API_KEY=ot_your_key
  5. Ask your agent to draft and schedule a post. Check the id it reports back.
  6. For the full walkthrough with per-agent detail, read how to write a SKILL.md that posts to X.

Pricing on the pricing page. The endpoint reference the skill is built on is in the quickstart.

The OpenTweet MCP server is open-source and available on npm. Learn more at opentweet.io/mcp.

Start Scheduling Your X Posts Today

Join hundreds of creators using OpenTweet to stay consistent, save time, and grow their audience.

7-day free trial
Only $11.99/mo
Cancel anytime

Post to X from your code or AI agent

No X developer account, no OAuth. Connect once and post through a REST API or MCP server.