Read and post to X/Twitter via API. Check mentions, post tweets, search. Uses OAuth 2.0 user context with token refresh.
81
Does it follow best practices?
If you maintain this skill, you can automatically optimize it using the tessl CLI to improve its score:
npx tessl skill review --optimize ./path/to/skillValidation for skill structure
Basic X (Twitter) API access for the @joelclaw account until a proper CLI is built (ADR-0119).
OAuth 1.0a User Context. Tokens do not expire — no refresh dance needed.
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)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())
PYEOFsecrets revoke --allAll operations require OAuth 1.0a signing. Use the Python pattern from Authentication section above, then:
# 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")515f336
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.