An agent skill that searches X (Twitter) through the Grok Build CLI on your machine, then checks every post against X's public embed data. Posts that don't exist on X are dropped. The rest are rebuilt from X's copy, not Grok's.
It needs the Grok Build CLI, signed in to your xAI account. Grok runs the search in a locked-down, headless session, and the skill hands back structured JSON: author, time, text, likes, images and video, the quoted post, and the post being replied to.
- Searches X with Grok. Your agent writes a focused brief. Grok runs its X search tools under a search cap and returns matching posts.
- Checks every post. Each post is looked up by its ID. Posts that don't exist are moved to
rejected. The rest take their text, time and author from X. - Looks up known posts for free.
--post <url>skips Grok entirely. - Pulls media.
--download-media <dir>saves photos and video poster frames, so an agent that reads images can see them. - Reads X Articles and threads.
--expandhas Grok fetch the long-form article or thread behind a post intoexpanded_text. - Drops copied posts. A post whose text matches another account's post is moved to
rejected. - Cost. 4 to 12 cents per capped search in testing, 27 cents at most.
- Grok Build CLI, signed in (
grok login). Searches count toward your Grok plan's usage limits. - Python 3.8 or later. Standard library only, nothing to install.
- Tested on macOS with Grok Build 1.0.62. Linux and Windows are untested.
With the skills CLI, for Claude Code, Codex, Cursor and other agents:
npx skills add exgota/search-x-posts -gAs a Claude Code plugin:
/plugin marketplace add exgota/search-x-posts
/plugin install search-x-posts@search-x-postsBy hand: copy skills/search-x-posts/ into ~/.claude/skills/ (or your agent's skills folder).
Ask your agent in plain words: "check X for reactions to the GPT-6 launch", "what did @AnthropicAI post this week", "pull the image from this post". Or run the script yourself:
cd skills/search-x-posts
python3 scripts/search_x_posts.py "The 5 most-liked posts from the last 48 hours about the GPT-6 launch."
python3 scripts/search_x_posts.py --post https://x.com/user/status/1234567890 --download-media ./media
python3 scripts/search_x_posts.py --helpA post in the output, trimmed to the main fields:
{
"id": "1234567890",
"url": "https://x.com/user/status/1234567890",
"handle": "user",
"posted_at": "2026-09-24T18:59:24.000Z",
"text": "the post's text",
"likes": 42,
"media": [{"type": "photo", "url": "https://pbs.twimg.com/media/example.jpg?name=large", "file": "/path/to/media/1234567890_1.jpg"}],
"quoted_post": null,
"in_reply_to": {"id": "1234567000", "handle": "other", "url": "https://x.com/other/status/1234567000", "text": "the parent post"},
"verification": "verified"
}verification is verified, text_mismatch (the post is real but Grok's text differed; X's text is shown), unavailable (deleted, protected or age-restricted) or unchecked (X's embed endpoint was unreachable). SKILL.md explains the fields the agent acts on.
The skill never checks for updates. To update:
- Claude Code plugin:
/plugin marketplace update search-x-posts, then/plugin update search-x-posts@search-x-posts - Skills CLI:
npx skills update search-x-posts - By hand: copy the new
skills/search-x-posts/over the old one.
- Your brief goes to xAI, through Grok.
- The ID of every post Grok returns goes to X's embed endpoint. Media downloads come from X's media servers.
The script sends nothing else. It stores only media you ask to download and --stream-log output if you set it. What the Grok CLI itself sends and stores is up to Grok.
- The script checks that Grok is signed in (
grok models, no model call); signed out, Grok has no X tools, so the script stops with a message to rungrok login. It then startsgrok -pin a throwaway directory with isolation settings, as the skill's own agent (scripts/x_search_agent.md), so a default agent in your Grok config cannot change the search. Local tools are removed by name. Shell and file access are denied by permission rule. The process runs under Grok's strict kernel sandbox. Grok's loading of your Claude and Cursor configuration is switched off. - Grok searches X under a cap of 6 searches by default, 14 at most. The script counts searches in Grok's event stream and stops Grok if it goes more than 4 past the cap.
- Grok answers in a fixed JSON schema. If Grok answered without running a single X search, the answer is discarded and the search retried once.
- Every post is looked up on
cdn.syndication.twimg.com, the endpoint behind X's embedded posts, and rebuilt from X's data. Lookups retry with backoff when the endpoint rate-limits.
On Sep 24, 2026, a comparison of Grok's reasoning effort levels ran 24 searches over 4 tasks, with every returned post checked against X. The design was fixed before the runs. A run's score is the share of the best-known answer it returned.
| Effort | Mean score | Cost per call | Seconds per call |
|---|---|---|---|
| Low | 0.53 | $0.055 | 17 |
| Medium (default) | 0.67 | $0.110 | 52 |
| High | 0.50 | $0.040 | 35 |
Medium was the only level that used its search budget on a filtered query. When Grok's X tools worked, all 63 returned posts were real and their text matched. Invented posts came only from the 4 sessions where the X tools were missing, which is why the script now retries those. With 2 runs per task and level, only large differences are meaningful.
On Oct 19, 2026, a second test ran 4 briefs at 6 and 14 searches, with relevance graded by hand, plus two follow-ups. One run per cell, so read it as direction:
| Brief | Finding |
|---|---|
| One known post | Both caps found it. 6 used 1 search ($0.06); 14 spent 8 ($0.28). |
| Launch sweep | Both returned 15 posts, 14 on topic, and shared only 6: the post cap limited breadth. |
| Practitioner how-tos | 14 searches found about twice the relevant posts of 6. The substance sat in X Articles. |
| One account, one month | 40 posts cost $0.62 (1.5 cents each), all verified, across 21 of 30 days. |
SKILL.md turns this into flags per kind of brief. The sessions missing X tools that could be traced had a signed-out Grok, so the script now checks sign-in first.
- Unofficial endpoint.
cdn.syndication.twimg.comis undocumented and can change, rate-limit or disappear. If it becomes unreachable, posts come back markedunchecked, and the search itself still works. - Long posts. The embed data carries only the first 280 characters. In a search, the full text comes from Grok, with its opening checked against X. A lookup with
--postreturns the first 280 characters, andnotesays so. - Renamed accounts. Searching an old handle returns posts only up to the rename. Posts come back flagged
handle_changed_from, and searching the current handle works. - Video. Poster frames are downloaded. Video files are not; the MP4 URL is in the output.
- Expanded text is Grok's copy. X's embed data cannot check
expanded_text. - Grok CLI changes. The isolation flags and tool names match Grok Build 1.0.62. A later CLI version can rename them.
Not affiliated with xAI or X. This skill reads public posts through Grok and through X's public embed endpoint. Automated access to X is subject to X's terms of service; use it accordingly.
MIT. See LICENSE.