MCPInstall

x-api

Read X/Twitter via API, post tweets with OAuth 1.0a, and draft X Articles through shitrat x. Check mentions, search, and ingest posts. Use app bearer tokens for read-only fetches. Use OAuth 1.0a user context for tweets. Use shitrat x for Articles.

Installs
40
Last 24h
—
Trending rank
—
Security
Not audited

Install

Works with every agent the skills CLI supports.

npx skills add https://github.com/joelhooks/joelclaw --skill x-api
  1. 01

    Install

    Run the command in your project. The CLI asks which agents to install for.

  2. 02

    Describe the task

    Ask your agent for something this skill covers. It loads x-api automatically when relevant.

  3. 03

    Review the result

    The agent follows the SKILL.md steps, scripts and references bundled with the skill.

SKILL.md

The instructions your agent reads when the skill is triggered.

X/Twitter API Skill

Read paths stay here. X Articles writes go through shitrat x. Tweets still use OAuth 1.0a until that lands on the same CLI.

Authentication

Recommended for read-only access: app bearer token

There is no stored x_bot_bearer_token secret right now. Derive the app bearer token from the X app consumer key + secret, then use that bearer token for read-only endpoints like tweet lookup.

python3 <<'PY'
import base64, json, subprocess
from urllib import request, parse


def lease(name: str) -> str:
    raw = subprocess.check_output(['secrets', 'lease', name], text=True)
    data = json.loads(raw)
    return data.get('secret') or data.get('result') or raw.strip()

ck = lease('x_consumer_key')
cs = lease('x_consumer_secret')
cred = base64.b64encode(f'{ck}:{cs}'.encode()).decode()

req = request.Request(
    'https://api.twitter.com/oauth2/token',
    data=parse.urlencode({'grant_type': 'client_credentials'}).encode(),
    headers={
        'Authorization': f'Basic {cred}',
        'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
    },
    method='POST',
)
with request.urlopen(req) as r:
    bearer = json.loads(r.read().decode())['access_token']

req2 = request.Request(
    'https://api.twitter.com/2/tweets/TWEET_ID',
    headers={'Authorization': f'Bearer {bearer}'},
)
with request.urlopen(req2) as r:
    print(r.read().decode())
PY

# Revoke only the exact lease ids acquired by this task; never all sessions’ leases.

Use this for:

  • reading a specific tweet/post
  • fetching public user metadata
  • recent search
  • full-archive search when the app has access
  • reply/context passes for source ingestion
  • other public read-only X v2 endpoints

Reply/context pass for ingestion

When ingesting an X post/article as a source, do a reply pass before writing the final note. The replies often contain the correction, missing caveat, source link, or better framing. Do not blindly archive the whole reply swamp; extract the high-signal replies and keep receipts.

Minimum pass:

  1. Fetch the root post with conversation_id, author_id, created_at, entities, public_metrics, referenced_tweets, note_tweet, and article when available.
  2. Search replies with conversation_id:ROOT_ID is:reply -is:retweet.
  3. Capture high-signal replies: author clarification, author thread continuation, cited source/link, strong objection, correction, implementation detail, or unusually crisp language.
  4. Store reply receipts with tweet_id, author handle/name, created time, URL, text basis, metrics, and why it matters.
  5. In the Brain/source note, separate the root quote from Reply signals so public claims do not blur root-author text with commenter interpretation.

For posts inside the recent-search window:

# After deriving bearer as above:
curl "https://api.x.com/2/tweets/search/recent?query=conversation_id%3AROOT_ID%20is%3Areply%20-is%3Aretweet&max_results=100&tweet.fields=author_id,conversation_id,created_at,entities,id,in_reply_to_user_id,note_tweet,public_metrics,referenced_tweets,text&expansions=author_id,referenced_tweets.id,referenced_tweets.id.author_id&user.fields=username,name,verified,verified_type" \
  -H "Authorization: Bearer $bearer"

For older posts, use Full-Archive Search when access allows it; otherwise fall back to browser inspection and mark the limitation in the verification note.

Full-Archive Search

The bot app can call Full-Archive Search if the access tier permits it. Do not use Recent Search for YTD/backfill research; it rejects older start_time values.

# After deriving bearer as above:
curl "https://api.x.com/2/tweets/search/all?query=from%3Athreepointone%20-is%3Areply&start_time=2026-01-01T00%3A00%3A00Z&end_time=2026-05-02T00%3A00%3A00Z&max_results=100&tweet.fields=created_at,public_metrics" \
  -H "Authorization: Bearer $bearer"

Notes:

Alternative: OAuth 1.0a User Context (for posting and account actions)

Tokens do not expire — no refresh dance needed.

Secrets (in agent-secrets)

  • x_consumer_key — API Key (OAuth 1.0a consumer key)
  • x_consumer_secret — API Key Secret (OAuth 1.0a consumer secret)
  • x_access_token — Access Token (OAuth 1.0a, format: numeric-alphanumeric)
  • x_access_token_secret — Access Token Secret (OAuth 1.0a)

@joelhooks / shitrat-joel app

Use these scoped secret names for Joel's personal X account so they don't collide with the @joelclaw bot app:

  • x_joelhooks_consumer_key
  • x_joelhooks_consumer_secret
  • x_joelhooks_bearer_token
  • x_joelhooks_access_token
  • x_joelhooks_access_token_secret

PIN OAuth note, 2026-06-28: https://api.x.com/oauth/authorize?... showed “There is no request token.” Regenerating with https://api.twitter.com/oauth/request_token and opening https://twitter.com/oauth/authorize?force_login=true&oauth_token=... worked for shitrat-joel → @joelhooks.

Auth verification, 2026-06-28: x_joelhooks_access_token + x_joelhooks_access_token_secret verified with GET https://api.twitter.com/2/users/me as @joelhooks / user id 12087242.

Bookmark caveat: GET /2/users/12087242/bookmarks returned 403 Unsupported Authentication with OAuth 1.0a. X requires OAuth 2.0 User Context / PKCE with bookmark.read, tweet.read, and users.read for bookmarks. Do not assume the saved OAuth 1.0a token can read bookmarks.

Signing requests

OAuth 1.0a requires cryptographic signing. Use requests-oauthlib (Python) or equivalent:

export CK=$(secrets lease x_consumer_key)
export CS=$(secrets lease x_consumer_secret)
export AT=$(secrets lease x_access_token)
export ATS=$(secrets lease x_access_token_secret)

uv run --with requests-oauthlib python3 << 'PYEOF'
import os
from requests_oauthlib import OAuth1Session

client = OAuth1Session(
    os.environ['CK'],
    client_secret=os.environ['CS'],
    resource_owner_key=os.environ['AT'],
    resource_owner_secret=os.environ['ATS'],
)

r = client.get("https://api.twitter.com/2/users/me")
print(r.json())
PYEOF

Revoke leases after use

# Revoke only the exact lease ids acquired by this task; never all sessions’ leases.

Account Info

  • Account: @joelclaw
  • User ID: 2022779096049311744
  • Scopes: Read and write (OAuth 1.0a app permissions)

@joelhooks Account Info

  • Account: @joelhooks
  • User ID: 12087242
  • App: shitrat-joel
  • OAuth 1.0a status: saved and verified for user-context actions that allow OAuth 1.0a
  • Bookmarks: not available through OAuth 1.0a; needs OAuth 2.0 PKCE user token with bookmark.read

Common Operations

Read-only lookups can use the app bearer-token flow above.

Posting, replying, following, deleting, and account-scoped actions require OAuth 1.0a signing. Use the Python pattern from Authentication section above, then:

Common API calls (inside OAuth1Session)

# Check mentions
r = client.get("https://api.twitter.com/2/users/2022779096049311744/mentions",
    params={"max_results": 10, "tweet.fields": "created_at,author_id,text",
            "expansions": "author_id", "user.fields": "username,name"})

# Get my timeline
r = client.get("https://api.twitter.com/2/users/2022779096049311744/tweets",
    params={"max_results": 10, "tweet.fields": "created_at,public_metrics"})

# Post a tweet
r = client.post("https://api.twitter.com/2/tweets", json={"text": "your tweet"})

# Reply to a tweet
r = client.post("https://api.twitter.com/2/tweets",
    json={"text": "@user reply", "reply": {"in_reply_to_tweet_id": "TWEET_ID"}})

# Search recent tweets
r = client.get("https://api.twitter.com/2/tweets/search/recent",
    params={"query": "joelclaw", "max_results": 10, "tweet.fields": "created_at,author_id,text"})

# Get user by username
r = client.get("https://api.twitter.com/2/users/by/username/USERNAME",
    params={"user.fields": "description,public_metrics"})

# Follow a user
my_id = "2022779096049311744"
r = client.post(f"https://api.twitter.com/2/users/{my_id}/following",
    json={"target_user_id": "TARGET_USER_ID"})

# Delete a tweet
r = client.delete("https://api.twitter.com/2/tweets/TWEET_ID")

X Articles (write)

Use the ShitRat CLI. Do not write /tmp X article scripts.

shitrat x me --account joelhooks
shitrat x article draft --title "The past blocked the future" --html-file ./post.html --cover ./banner.png --dry-run

Live create needs --yes and a remaining 24h cap slot. Failed creates count against a 10/day user cap. OAuth 1.0a cannot create articles. Skill: packages/cli/skills/shitrat-x/SKILL.md in shitrat-cli.

X Articles (Long-form Posts, ingest)

First try the v2 tweet lookup with tweet.fields=article. Some X Articles return article.title and article.plain_text directly in the tweet payload. Store that API payload as the source receipt when available.

If article.plain_text is missing, the tweet body is only a t.co link, or the article endpoint/browser auth blocks extraction, use agent-browser as the fallback:

agent-browser open "https://x.com/USERNAME/status/TWEET_ID"
agent-browser snapshot
agent-browser close

Use this for any tweet where article.title is present in the API response or the expanded_url points to x.com/i/article/... but the API does not include usable article text.

For capturing X posts/articles as discoveries, use joelclaw discover URL -c "context" — the discovery pipeline will handle enrichment. If the pipeline can't extract content (auth-gated), fall back to X API + reply/context pass + manual Brain/source note.

Rate Limits

  • Mentions: 180 requests / 15 min
  • Post tweet: 200 tweets / 15 min (app-level)
  • Search: 180 requests / 15 min
  • User lookup: 300 requests / 15 min

Rules

  • Never engage with shitcoin/scam mentions. Ignore them entirely.
  • Never post financial advice or token endorsements.
  • Joel approves all tweets before posting unless explicitly told otherwise.
  • Joel approves live X Article creates and publishes. --dry-run is free. --yes is a write.
  • Always revoke leases after use — don't leave secrets in memory.
  • OAuth 1.0a tokens don't expire — no refresh needed. If auth fails, tokens were regenerated in the developer portal.
  • OAuth 2.0 user tokens expire in about two hours. Refresh before a live article write if shitrat x me returns 401.

FAQ

What does the x-api skill do?

Read X/Twitter via API, post tweets with OAuth 1.0a, and draft X Articles through shitrat x. Check mentions, search, and ingest posts. Use app bearer tokens for read-only fetches. Use OAuth 1.0a user context for tweets. Use shitrat x for Articles.

How do I install x-api?

Run npx skills add https://github.com/joelhooks/joelclaw --skill x-api in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/x-api/ (personal) or .claude/skills/x-api/ (project).

Which AI agents can use x-api?

Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.

Is x-api safe to install?

No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.

Who maintains x-api?

It is published by joelhooks in joelhooks/joelclaw. It has 40 recorded installs.

More from joelhooks/joelclaw

View all →

contacts

joelhooks/joelclaw

Add, enrich, and manage contacts in Joel's Vault. Fire the Inngest enrichment pipeline for full multi-source dossiers, or create quick contacts manually. Use when: 'add a contact', 'enrich this person', 'who is X', 'VIP contact', 'update contact', or any task involving the Vault/Contacts directory.

cli-design

joelhooks/joelclaw

Design and build agent-first CLIs with HATEOAS JSON responses, context-protecting output, and self-documenting command trees. Use when creating new CLI tools, adding commands to existing CLIs such as joelclaw, or reviewing CLI design for agent-friendliness. Triggers on 'build a CLI', 'add a command', 'CLI design', 'agent-friendly output', or any task involving command-line tool creation.

docker-sandbox

joelhooks/joelclaw

Open the skill to read its SKILL.md instructions.

DevOps & Cloud103 installs

granola

joelhooks/joelclaw

Access and process Granola meeting notes and transcripts via the granola CLI (MCP-backed). Use when pulling meeting data, analyzing transcripts, backfilling meetings, or any task involving Granola meeting content.

k8s

joelhooks/joelclaw

Operate the joelclaw Kubernetes cluster — Talos Linux on Colima (Mac Mini). Deploy services, check health, debug pods, recover from restarts, add ports, manage Helm releases, inspect logs, fix networking. Triggers on: 'kubectl', 'pods', 'deploy to k8s', 'cluster health', 'restart pod', 'helm install', 'talosctl', 'colima', 'nodeport', 'flannel', 'port mapping', 'k8s down', 'cluster not working', 'add a port', 'PVC', 'storage', any k8s/Talos/Colima infrastructure task. Also triggers on service-specific deploy: 'deploy redis', 'redeploy inngest', 'livekit helm', 'pds not responding'.

DevOps & Cloud95 installs

joel-writing-style

joelhooks/joelclaw

Joel's writing voice and style guide for joelclaw.com content. Use when writing, editing, or reviewing any blog post, essay, book chapter, or prose content for joelclaw.com. Also use when asked to 'write like Joel,' 'match Joel's voice,' 'draft a post,' 'write content for the blog,' or 'review this for voice.' This skill captures Joel's specific writing patterns derived from 90,000 words of published content spanning 2012–2026. Cross-reference with copy-editing and copywriting skills for marketing-specific copy.

Docs & Writing82 installs

Popular backend & apis skills

View category →

find-skills

vercel-labs/skills

Helps users discover and install agent skills when they ask questions like "how do I do X", "find a skill for X", "is there a skill that can...", or express interest in extending capabilities. This skill should be used when the user is looking for functionality that might exist as an installable skill.

OfficialBackend & APIs4.1M installs

entra-app-registration

microsoft/azure-skills

Guides Microsoft Entra ID app registration, OAuth 2.0 authentication, and MSAL integration. USE FOR: create app registration, register Azure AD app, configure OAuth, set up authentication, add API permissions, generate service principal, MSAL example, console app auth, Entra ID setup, Azure AD authentication. DO NOT USE FOR: Key Vault secrets (use azure-keyvault-expiration-audit), general Azure resource security guidance.

OfficialBackend & APIs566.7K installs

This skill should be used when the user wants to "write agent code", "build an agent with ADK", "add a tool", "create a callback", "define an agent", "use state management" — in a project that needs ADK (Agent Development Kit) API patterns and code examples. It provides a quick reference for agent types, tool definitions, orchestration patterns, callbacks, state management, the graph Workflow API, and reference recipes to study. Do NOT use for scaffolding (use google-agents-cli-scaffold) or deployment (use google-agents-cli-deploy).

Backend & APIs514.8K installs

embedded-captions

heygen-com/hyperframes

Add captions or subtitles to an existing single-subject talking-head video without editing the footage. Use for plain verbatim captions, cinematic captions embedded behind the subject, VFX captions, “炸/特效/酷炫字幕,” or a named identity from the 35-style catalog. Route by visual identity, not by backend engine. The quiet anchor rail is the default; embed every word only when the user explicitly wants a fully cinematic treatment. The workflow runs locally end to end, including transcription and subject matting; split multi-shot footage before applying it.

Backend & APIs453.3K installs

entra-agent-id

microsoft/azure-skills

Provision Microsoft Entra Agent Identity Blueprints, BlueprintPrincipals, and per-instance Agent Identities via Microsoft Graph, and configure OAuth 2.0 token exchange (fmipath, OBO, cross-tenant) including the Microsoft Entra SDK for AgentID sidecar. USE FOR: Agent Identity Blueprint, BlueprintPrincipal, agent OAuth, fmipath token exchange, agent OBO, Workload Identity Federation for agents, polyglot agent auth, Microsoft.Identity.Web.AgentIdentities. DO NOT USE FOR: standard Entra app registration (use entra-app-registration), Microsoft Foundry agent authoring (use microsoft-foundry).

OfficialBackend & APIs336.6K installs

neon

neondatabase/agent-skills

Overview of Neon, a complete set of cloud backend primitives around Lakebase Postgres: Auth, Object Storage, Functions, the AI Gateway, and Realtime. Start here to choose Neon for undecided login, files, APIs, and LLM calls, set up the CLI or MCP server, and follow the branch-first workflow. Use when building an app or backend on Neon, or when "Neon" or "Lakebase Postgres" is mentioned. Child skill neon-postgres wins for an existing DATABASEURL, SQL, schema, inspect, or search. Child skill neon-auth wins for login, users, sessions, identity routing, and Managed Better Auth setup. Child skill neon-realtime wins for live queries in reactive apps and agents. Also use for object storage, S3, buckets, serverless functions, function triggers, cron, AI gateway, LLM calls, realtime, logs, Loki, Grafana, observability, postgres, database, backend, Claimable Neon, neon.new, or a no-signup database.

Backend & APIs237.1K installs