- **Verified write ops:** `likeTweet`, `unlikeTweet`, `createBookmark`, `deleteBookmark`, `createRetweet`, `deleteRetweet`, `unblockUser`, `unfollowUser`, plus all 6 user/reply ops in standalone `pnpm dev x exec` runs after the 2026-04-19 fixture refresh. Aggregate `verify --write` still loses the create-side ops to cascade churn — see DOC.md "Verify quirk".
Resources
6Install
npx skillscat add imoonkey/openweb/src-sites-x Install via the SkillsCat registry.
SKILL.md
X (Twitter)
Overview
Social media and microblogging platform. Archetype: Social Media. GraphQL API with persisted query hashes, L3 adapter for dynamic hash resolution and request signing. REST v1.1/v2 endpoints for social graph and moderation actions.
Workflows
Browse timeline and interact
getHomeTimeline→ tweets →tweet_idlikeTweet(tweet_id)/createBookmark(tweet_id)/createRetweet(tweet_id)
Compose and manage tweets
createTweet(text)→rest_id(new tweet_id)reply(tweet_id, text)→ reply to a tweet →rest_iddeleteTweet(tweet_id)→ delete your own tweet (tweet_id from createTweetrest_idor getHomeTimeline)
Find and read a user's profile
getUserByScreenName(screen_name)→rest_id(userId),name,followers_countgetUserTweets(userId)→ user's tweets →tweet_idgetUserLikes(userId)→ user's liked tweets →tweet_idgetUserFollowers(userId)/getUserFollowing(userId)→ follower/followingrest_idlist
Manage social graph
getUserByScreenName(screen_name)→rest_idfollowUser(userId)/unfollowUser(userId)blockUser(userId)/unblockUser(userId)muteUser(userId)/unmuteUser(userId)
Search tweets
searchTweets(rawQuery)→ tweet results with cursor pagination
Get tweet with replies
getTweetDetail(focalTweetId)→ full tweet thread with replies
Moderate replies
getTweetDetail(focalTweetId)→ reply entries → replytweet_idhideReply(tweet_id)/unhideReply(tweet_id)— hide/show replies on your tweets
Direct messages
getUserByScreenName(screen_name)→rest_id(recipientId)sendDM(recipientId, text)→ DM event withmessageId— approved contacts only
Notifications and bookmarks
getNotifications→ mentions, likes, retweets, followsgetBookmarks→ your bookmarked tweets
Trending / Explore
getExplorePage→ trending topics, recommended content
Operations
| Operation | Intent | Key Input | Key Output | Notes |
|---|---|---|---|---|
| getHomeTimeline | home feed | count | tweets, cursors | entry point, paginated |
| getTweetDetail | tweet + replies | focalTweetId | tweet thread, reply entries | also serves as getThread |
| getUserByScreenName | user profile | screen_name | rest_id, name, bio, followers_count | entry point |
| searchTweets | search posts | rawQuery, product (Top/Latest) | tweet results, cursors | paginated |
| getUserTweets | user's tweets | userId ← getUserByScreenName rest_id | tweets, cursors | paginated |
| getUserFollowers | followers list | userId ← getUserByScreenName rest_id | user profiles, cursors | paginated |
| getUserFollowing | following list | userId ← getUserByScreenName rest_id | user profiles, cursors | paginated |
| getExplorePage | trending/explore | — | trending topics, timelines | entry point, also serves as getTrending |
| getUserLikes | user's liked tweets | userId ← getUserByScreenName rest_id | tweets, cursors | paginated |
| getBookmarks | your bookmarks | count | bookmarked tweets, cursors | paginated, own bookmarks only |
| getNotifications | notifications | count | mentions, likes, follows, retweets | paginated |
| createTweet | post a tweet | text | rest_id | write, CAUTION |
| deleteTweet | delete your tweet | tweet_id ← createTweet rest_id / getHomeTimeline | — | write, CAUTION |
| reply | reply to tweet | tweet_id ← getHomeTimeline / getTweetDetail, text | rest_id | write, CAUTION |
| likeTweet | like a tweet | tweet_id ← getHomeTimeline / searchTweets / getTweetDetail | — | write — verified PASS |
| unlikeTweet | unlike a tweet | tweet_id ← getHomeTimeline / searchTweets / getTweetDetail (or paired likeTweet) | — | write — verified PASS |
| createBookmark | bookmark tweet | tweet_id ← getHomeTimeline / searchTweets / getTweetDetail | — | write — verified PASS |
| deleteBookmark | remove bookmark | tweet_id ← getHomeTimeline / searchTweets / getTweetDetail (or paired createBookmark) | — | write — verified PASS |
| createRetweet | retweet | tweet_id ← getHomeTimeline / searchTweets / getTweetDetail | retweet rest_id | write — verified PASS |
| deleteRetweet | undo retweet | source_tweet_id ← getHomeTimeline / searchTweets / getTweetDetail (or paired createRetweet) | — | write — verified PASS |
| followUser | follow user | userId ← getUserByScreenName rest_id | user object | write, CAUTION — pair-order sensitive (see Known Limitations) |
| unfollowUser | unfollow user | userId ← getUserByScreenName rest_id (or paired followUser) | user object | write — verified PASS |
| blockUser | block user | userId ← getUserByScreenName rest_id | user object | write, CAUTION — pair-order sensitive (see Known Limitations) |
| unblockUser | unblock user | userId ← getUserByScreenName rest_id (or paired blockUser) | user object | write — verified PASS |
| muteUser | mute user | userId ← getUserByScreenName rest_id | user object | write, CAUTION — page-lifecycle issue (see Known Limitations) |
| unmuteUser | unmute user | userId ← getUserByScreenName rest_id (or paired muteUser) | user object | write, CAUTION — page-lifecycle issue (see Known Limitations) |
| hideReply | hide reply | tweet_id ← getTweetDetail reply entries (or pinned fixture id) | hidden: true | write — verified PASS via permanent fixture |
| unhideReply | unhide reply | tweet_id ← getTweetDetail reply entries (or pinned fixture id) | hidden: false | write — verified PASS via permanent fixture |
| sendDM | send DM | recipientId ← getUserByScreenName rest_id, text | messageId, DM event | write, CAUTION, approved contacts |
Quick Start
# Get home timeline
openweb x exec getHomeTimeline '{"count": 20}'
# Search tweets
openweb x exec searchTweets '{"rawQuery": "openai", "count": 20, "product": "Latest"}'
# Get user profile
openweb x exec getUserByScreenName '{"screen_name": "openai"}'
# Get tweet detail (also serves as getThread)
openweb x exec getTweetDetail '{"focalTweetId": "1234567890"}'
# Get user's followers (need userId from getUserByScreenName → rest_id)
openweb x exec getUserFollowers '{"userId": "4398626122", "count": 20}'
# Create a tweet
openweb x exec createTweet '{"text": "Hello from OpenWeb!"}'
# Reply to a tweet
openweb x exec reply '{"tweet_id": "1234567890", "text": "Great thread!"}'
# Follow a user
openweb x exec followUser '{"userId": "4398626122"}'
# Send a DM (approved contacts only)
openweb x exec sendDM '{"recipientId": "4398626122", "text": "Hey!"}'
# Get notifications
openweb x exec getNotifications '{"count": 20}'
# Get your bookmarks
openweb x exec getBookmarks '{"count": 20}'
# Get user's liked tweets
openweb x exec getUserLikes '{"userId": "4398626122", "count": 20}'Known Limitations
- Open
https://x.com/homein the managed Chrome (port 9222) before running write ops. The site declarespage_plan.entry_url=https://x.com/homewithwarm: true, but a runtime cascade can leave verify holding a stale browser handle if no x.com tab is already open at start. Pre-warming the tab also ensures cookies, ct0 CSRF, and the webpack signing module are hydrated. - Never use your own userId as a follow/block/mute target. Twitter returns 403 (
code 158/147/271 — "you can't <verb> yourself") which the runtime maps toneeds_login, triggering a 45 s cascade-timeout per op. Use a stable third-party account (e.g.@XDevelopersid2244994945) for testing. Destroy variants (unfollow/unblock/unmute) return 200 no-op even on self, masking the issue if you only check those. hideReply/unhideReplyrequire a cross-account reply. Twitter blocks moderating own replies on own thread (returns DRIFT —tweet_moderate_put: Doneonly fires for foreign replies). The pinned fixture id2046061970021847164is a reply by@QGuo219895on@iamoonkey/2045749343437619246— both fixtures hard-code this id;unhideReplychains viaorder: 19afterhideReply'sorder: 18. The transport is GraphQLModerateTweet/UnmoderateTweet(NOT the legacy RESTPUT /i/api/2/tweets/{id}/hidden, which has been removed and hangs 45 s). No re-seeding needed between runs as long as the parent reply isn't deleted by the alt account.- Verified write ops:
likeTweet,unlikeTweet,createBookmark,deleteBookmark,createRetweet,deleteRetweet,unblockUser,unfollowUser, plus all 6 user/reply ops in standalonepnpm dev x execruns after the 2026-04-19 fixture refresh. Aggregateverify --writestill loses the create-side ops to cascade churn — see DOC.md "Verify quirk".