Skip to content
AI & Agents
Skill

/x-research

Read X (Twitter) via xurl — search posts, fetch threads, read profiles, and read long-form articles

BOOST
From plugin
yoyo-evolve
1.9k14 skills
Install
$ npx -y skills add yologdev/yoyo-evolve --skill x-research --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/x-research

Context preview

The summary Claude sees to decide when to auto-load this skill.

Read X (Twitter) via xurl — search posts, fetch threads, read profiles, and read long-form articles

SKILL.md

x-research.SKILL.md
name: x-research
description: Read X (Twitter) via xurl — search posts, fetch threads, read profiles, and read long-form articles
tools: [bash, read_file]
origin: yoyo
status: active
score: 0.24
uses: 3
wins: 3
last_used: "2026-05-03T14:37:44Z"
last_evolved: null
parent_pattern_key: null
keywords: ["xurl", "twitter", "x.com", "tweet", "thread", "x-research"]

X Research

Read-only access to X (Twitter) through [xurl](https://github.com/deepfates/xurl). Use this when you need to know what people are saying on X about a topic, read a specific thread, check someone's recent posts, or read long-form X Articles.

When to Use

  • Researching what people on X are saying about a topic (an API, a tool, a trend)
  • Reading a specific thread or conversation for context
  • Checking a profile's recent posts (e.g., what has @someone been saying about Rust?)
  • Reading long-form X Articles
  • Gathering community sentiment before making a decision

When NOT to Use

  • **General web research** — use the `research` skill instead (curl + DuckDuckGo)
  • **Posting, liking, following, DMing** — this skill is read-only, always
  • **Bulk historical scraping** — the API has rate limits and this isn't an archival tool
  • **Real-time monitoring or streaming** — one-shot queries only
  • **Anything that modifies state on X** — never, under any circumstances

Prerequisites

Two auth modes are supported. Detect which one applies first, then use the `x_get` helper for **every** request — never call `xurl GET` or `curl` directly inline, or CI mode will silently fail (xurl has no `~/.xurl` on a runner).

# Auth mode detection — run this once at the top of the session:
if [ -n "$X_BEARER_TOKEN" ]; then
    AUTH_MODE=ci
elif command -v xurl &>/dev/null && [ -d "$HOME/.xurl" ]; then
    AUTH_MODE=local
else
    have_xurl=$(command -v xurl >/dev/null 2>&1 && echo yes || echo no)
    have_xurl_dir=$([ -d "$HOME/.xurl" ] && echo yes || echo no)
    have_token=$([ -n "$X_BEARER_TOKEN" ] && echo yes || echo no)
    echo "x-research: auth not configured; skill unavailable this session" >&2
    echo "  X_BEARER_TOKEN set: $have_token" >&2
    echo "  xurl on PATH:       $have_xurl" >&2
    echo "  ~/.xurl exists:     $have_xurl_dir" >&2
    exit 1
fi

**CI mode (`AUTH_MODE=ci`)** — `$X_BEARER_TOKEN` is set (provisioned by the CI workflow as a repo secret). Calls go through `curl` with an `Authorization: Bearer` header. Tokens come from the X developer portal as **App-only Bearer tokens**, which are read-only (cannot post, like, DM, or act as a user). Don't paste a user OAuth2 access token into this secret — `x_get` won't validate token type, but a user token would expose write capability the skill is not designed to use.

**Local mode (`AUTH_MODE=local`)** — `xurl` is on PATH and `~/.xurl/` exists from a prior `xurl auth oauth2` run. `xurl` handles auth from its credential store.

**Setup instructions for the human if both checks fail:**

Local: install `xurl` (`cargo install xurl`, see https://github.com/deepfates/xurl), then run `xurl auth oauth2` and follow the prompts.

CI: generate an App-only Bearer token at the X developer portal → add to repo Settings → Secrets and variables → Actions as `X_BEARER_TOKEN`.

**If neither auth mode is available, stop. Don't retry.** This is not a transient failure.

Auth-aware request helper

`x_get` is the only request entry point — checks HTTP status, surfaces auth/rate-limit failures explicitly, and exits non-zero on error so primitives don't silently parse error JSON as data:

x_get() {
    local path="$1"
    local body http_code
    if [ "$AUTH_MODE" = "ci" ]; then
        # -w writes the HTTP status to stdout after the body; split with tail -n1.
        local raw
        raw=$(curl -sS -w $'\n%{http_code}' \
                   -H "Authorization: Bearer $X_BEARER_TOKEN" \
                   "https://api.x.com${path}") || return $?
        http_code=$(printf '%s' "$raw" | tail -n1)
        body=$(printf '%s' "$raw" | sed '$d')
    else
        body=$(xurl GET "$path") || return $?
        # xurl exits non-zero on HTTP errors; assume 200 if we got here.
        http_code=200
    fi
    case "$http_code" in
        2*) printf '%s' "$body" ;;
        401|403) echo "x-research: HTTP $http_code on $path — token rejected (regenerate the auth)" >&2; return 2 ;;
        429)     echo "x-research: HTTP 429 on $path — rate limited" >&2; return 3 ;;
        *)       echo "x-research: HTTP $http_code on $path — unexpected; body: $body" >&2; return 4 ;;
    esac
}

**Never echo or log `$X_BEARER_TOKEN`.** Treat it like any other secret. Don't add `set -x` to scripts that run `x_get` — bash trace expands the `-H` arg verbatim.

Primitives

1. Search — find recent posts about a topic

# URL-encode the query (spaces → %20, # → %23, etc.)
QUERY=$(python3 -c "import urllib.parse; print(urllib.parse.quote('your search query'))")
x_get "/2/tweets/search/recent?query=${QUERY}&max_results=10&tweet.fields=created_at,author_id,public_metrics,text"

**Cost:** 1 request per call.

**What to show:** For each tweet — text, author_id, created_at, and engagement metrics (retweets, likes, replies).

**Tips:**

  • Keep `max_results` at 10 unless you specifically need more (max 100).
  • Use X search operators: `from:username`, `to:username`, `#hashtag`, `-is:retweet` for filtering.
  • The recent search endpoint only covers the last 7 days.

2. Thread — read a conversation

Given a tweet URL or ID, reconstruct the full conversation thread.

**Step 1:** Fetch the root tweet and its conversation_id:

TWEET_ID="1234567890"
x_get "/2/tweets/${TWEET_ID}?tweet.fields=conversation_id,author_id,created_at,text,public_metrics"

**Step 2:** Search for all replies in that conversation:

CONV_ID="..."  # from step 1 response
x_get "/2/tweets/search/recent?query=conversation_id:${CONV_ID}&max_results=50&tweet.fields=created_at,author_id,text,in_reply_to_user_id
Read more
Ships withyoyo-evolve

200 lines of Rust. Zero human code. One rule: evolve or die. yoyo reads its own source, picks what to improve, implements it, runs tests, and commits — every few hours, on its own. 180 days later: 158,000+ lines, 5,400+ tests, 94 source files.

Get the whole plugin

Other skills on yoyo-evolve.