Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Read this skill when you need to use X (Twitter). Don't have to open a browser tab.
.claude/skills/kunanonj-aside-x-twitter/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-04 | ✗→✓ | ▲ Improved | 196% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 126% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 496% | 0% |
| case-12 | ✗→✓ | ▲ Improved | 63% | 0% |
| case-16 | ✗→✓ | ▲ Improved | 262% | 0% |
Use the twitter global in the REPL tool. It allows you to control the X/Twitter website with API interface- no tab open needed.
js// Auth check const me = await twitter.getMe(); console.log(me); // → { id, screenName, name, description, followersCount, ... } // Timeline (Following tab, chronological) const timeline = await twitter.getTimeline({ count: 20 }); console.log(timeline.tweets.map(t => `@${t.author.screenName}: ${t.text.slice(0, 80)}`)); // Search const results = await twitter.search('AI agents', { count: 20, product: 'Latest' }); console.log(results.tweets); // Get a specific tweet const tweet = await twitter.getTweet('1234567890'); console.log(tweet); // Get the visible same-author thread from a tweet page const thread = await twitter.getTweetThread('1234567890'); console.log(thread.tweets); // Get user profile const user = await twitter.getUser('steipete'); console.log(user); // Post a tweet const posted = await twitter.tweet('Hello from Aside!'); console.log(posted.id); // Reply to a tweet const reply = await twitter.reply('1234567890', 'Great thread!'); // Interactions await twitter.like('1234567890'); await twitter.retweet('1234567890'); await twitter.bookmark('1234567890'); // Follow/unfollow (requires user ID, not handle) await twitter.follow('123456'); await twitter.unfollow('123456'); // DMs const inbox = await twitter.getDmInbox(); console.log(inbox.conversations); const history = await twitter.getDmConversation('123-456'); console.log(history.messages); await twitter.sendDm('123456', 'Hello!'); // Block/Mute await twitter.block('123456'); await twitter.mute('123456'); // Notifications const notifs = await twitter.getNotifications({ count: 10 }); console.log(notifs.notifications);
twitter.getMe(): Promise<XUser>Get the authenticated user's profile.
twitter.getUser(screenName: string): Promise<XUser>Get a user profile by screen name (handle, without @).
twitter.getTweet(tweetId: string): Promise<XTweet>Get a single tweet by ID.
twitter.getTweetThread(tweetId: string): Promise<XTimelineResponse>Get the focal tweet plus visible same-author replies in the thread. Use this for X status pages when the user asks what the current page/thread is about.
twitter.getTimeline(opts?): Promise<XTimelineResponse>Get home timeline (Following tab, chronological).
opts.count — Number of tweets (default 20).opts.cursor — Pagination cursor from previous response's nextCursor.twitter.search(query: string, opts?): Promise<XTimelineResponse>Search tweets.
query — Search query (supports X search operators like from:user, to:user, since:2026-01-01).opts.count — Number of results (default 20).opts.product — 'Latest' (default), 'Top', 'People', 'Photos', 'Videos'.opts.cursor — Pagination cursor.twitter.getUserTweets(screenName: string, opts?): Promise<XTimelineResponse>Get a user's tweets by screen name.
opts.count — Number of tweets (default 20).opts.cursor — Pagination cursor.twitter.getBookmarks(opts?): Promise<XTimelineResponse>Get bookmarked tweets.
twitter.tweet(text: string, opts?): Promise<XTweet>Post a new tweet. Returns the created tweet.
opts.mediaIds — Array of media IDs (from media upload) to attach.twitter.reply(tweetId: string, text: string, opts?): Promise<XTweet>Reply to a tweet. Returns the reply.
twitter.deleteTweet(tweetId: string): Promise<void>twitter.like(tweetId: string): Promise<void>twitter.unlike(tweetId: string): Promise<void>twitter.retweet(tweetId: string): Promise<void>twitter.unretweet(tweetId: string): Promise<void>twitter.bookmark(tweetId: string): Promise<void>twitter.unbookmark(tweetId: string): Promise<void>twitter.follow(userId: string): Promise<void>Follow by user ID. Get user ID from twitter.getUser(screenName).id.
twitter.unfollow(userId: string): Promise<void>Unfollow by user ID.
twitter.getDmInbox(): Promise<XDmInbox>Get DM inbox (list of conversations with last message preview).
twitter.getDmConversation(conversationId: string, opts?): Promise<XDmHistory>Get messages in a DM conversation. Conversation ID format: "{lowerUserId}-{higherUserId}".
opts.maxId — Pagination cursor for older messages (from nextCursor).twitter.sendDm(userId: string, text: string, opts?): Promise<any>Send a DM to a user by their user ID. Conversation ID is auto-constructed.
opts.mediaId — Attach media (from media upload).opts.replyToId — Reply to a specific message.twitter.block(userId: string): Promise<void>twitter.unblock(userId: string): Promise<void>twitter.mute(userId: string): Promise<void>twitter.unmute(userId: string): Promise<void>twitter.getNotifications(opts?): Promise<{ notifications: XNotification[]; nextCursor?: string }>Get recent notifications.
opts.count — Number of notifications (default 20).opts.cursor — Pagination cursor.tsinterface XUser { id: string; screenName: string; name: string; description: string; followersCount: number; followingCount: number; tweetCount: number; profileImageUrl: string; isBlueVerified: boolean; } interface XTweet { id: string; text: string; author: XUser; createdAt: Date; likes: number; retweets: number; replies: number; bookmarks: number; views: number; media: XMedia[]; inReplyToId?: string; quotedTweet?: XTweet; } interface XMedia { type: 'photo' | 'video' | 'animated_gif'; url: string; width: number; height: number; } interface XTimelineResponse { tweets: XTweet[]; nextCursor?: string; // pass as opts.cursor for next page } interface XDmMessage { id: string; text: string; senderId: string; recipientId: string; createdAt: Date; mediaUrl?: string; } interface XDmConversation { conversationId: string; participants: string[]; // user IDs lastMessage?: XDmMessage; } interface XDmInbox { conversations: XDmConversation[] } interface XDmHistory { messages: XDmMessage[]; nextCursor?: string } interface XNotification { id: string; type: string; timestamp: Date; message: string; raw: any; }
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-04 | fail→pass | 4,629 | 2,241 | -52% | 1 | 1 | 0% | 747 | 2,213 | +196% | 0 | 0 | — |
case-06 | fail→pass | 5,565 | 7,977 | +43% | 1 | 1 | 0% | 1,126 | 2,550 | +126% | 0 | 0 | — |
case-22 | pass→pass | 5,067 | 5,571 | +10% | 1 | 1 | 0% | 1,076 | 2,900 | +170% | 0 | 0 | — |
case-05 | fail→fail | 7,493 | 5,973 | -20% | 1 | 1 | 0% | 1,396 | 2,207 | +58% | 0 | 0 | — |
case-01 | fail→fail | 4,534 | 4,323 | -5% | 1 | 1 | 0% | 682 | 2,104 | +209% | 0 | 0 | — |
case-02 | fail→fail | 2,729 | 4,476 | +64% | 1 | 1 | 0% | 379 | 2,142 | +465% | 0 | 0 | — |
case-03 | fail→fail | 3,371 | 4,339 | +29% | 1 | 1 | 0% | 556 | 2,085 | +275% | 0 | 0 | — |
case-07 | fail→fail | 7,164 | 7,570 | +6% | 1 | 1 | 0% | 1,351 | 2,277 | +69% | 0 | 0 | — |
case-08 | pass→fail | 8,722 | 6,547 | -25% | 1 | 1 | 0% | 1,756 | 2,354 | +34% | 0 | 0 | — |
case-09 | fail→fail | 20,430 | 8,355 | -59% | 1 | 1 | 0% | 3,639 | 2,608 | -28% | 0 | 0 | — |
case-10 | fail→pass | 2,542 | 3,093 | +22% | 1 | 1 | 0% | 349 | 2,079 | +496% | 0 | 0 | — |
case-11 | fail→fail | 6,074 | 7,590 | +25% | 1 | 1 | 0% | 1,263 | 2,369 | +88% | 0 | 0 | — |
case-12 | fail→pass | 6,185 | 1,410 | -77% | 1 | 1 | 0% | 1,273 | 2,073 | +63% | 0 | 0 | — |
case-13 | fail→fail | 7,914 | 6,255 | -21% | 1 | 1 | 0% | 352 | 2,108 | +499% | 0 | 0 | — |
case-14 | pass→pass | 6,786 | 3,178 | -53% | 1 | 1 | 0% | 1,501 | 2,455 | +64% | 0 | 0 | — |
case-15 | fail→fail | 9,029 | 4,218 | -53% | 1 | 1 | 0% | 1,686 | 2,102 | +25% | 0 | 0 | — |
case-16 | fail→pass | 3,777 | 7,097 | +88% | 1 | 1 | 0% | 680 | 2,463 | +262% | 0 | 0 | — |
case-17 | pass→fail | 7,441 | 5,363 | -28% | 1 | 1 | 0% | 798 | 2,193 | +175% | 0 | 0 | — |
case-18 | fail→pass | 4,147 | 4,384 | +6% | 1 | 1 | 0% | 864 | 2,147 | +148% | 0 | 0 | — |
case-19 | fail→fail | 6,695 | 5,324 | -20% | 1 | 1 | 0% | 1,454 | 2,216 | +52% | 0 | 0 | — |
case-20 | pass→pass | 15,836 | 6,294 | -60% | 1 | 1 | 0% | 3,102 | 3,266 | +5% | 0 | 0 | — |
case-21 | pass→pass | 10,832 | 6,197 | -43% | 1 | 1 | 0% | 2,536 | 3,340 | +32% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 10 counted toward the lift figure. The other 12 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +18 percentage points is the difference between those two pass rates over the 10 comparable cases. 3 cases got worse with the skill loaded, and they are included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.