Search Twitter/X for recent tweets matching keywords and engagement thresholds. Returns raw tweet data as JSON — the calling agent handles scoring, formatting, and delivery.
curl -s -G "https://api.x.com/2/tweets/search/recent" \
--data-urlencode 'query=("AI agent" OR "agentic AI") (lang:en) -is:reply -is:retweet' \
--data-urlencode "max_results=30" \
--data-urlencode "start_time=$(date -u -v-24H +%Y-%m-%dT%H:%M:%SZ)" \
--data-urlencode "tweet.fields=created_at,public_metrics,author_id" \
--data-urlencode "user.fields=username,name" \
--data-urlencode "expansions=author_id" \
--data-urlencode "sort_order=relevancy" \
-H "Authorization: Bearer $TWITTER_BEARER_TOKEN" | jq .
The caller provides these. Use defaults when not specified.
| Parameter | Default | Description |
|---|---|---|
| ----------- | --------- | ------------- |
| keywords | (required) | Search terms, combined with OR |
| languages | ["en"] | Language codes for lang: filter |
| min_likes | 0 | Minimum like count (filtered after fetch) |
| min_retweets | 0 | Minimum retweet count (filtered after fetch) |
| lookback_hours | 24 | Time window |
| max_results | 30 | Tweets to return (after filtering) |
| exclude_replies | true | Add -is:reply to query |
| exclude_retweets | true | Add -is:retweet to query |
Verify $TWITTER_BEARER_TOKEN is set:
test -n "$TWITTER_BEARER_TOKEN" && echo "OK" || echo "MISSING"
If missing, tell the user:
hermes config set TWITTER_BEARER_TOKEN Combine keywords with OR. Wrap multi-word phrases in quotes:
("keyword one" OR "keyword two" OR single) -is:reply -is:retweet
Add language filter: (lang:en OR lang:fr)
Available on pay-per-use: lang:, -is:reply, -is:retweet, from:, has:links, has:media
NOT available on pay-per-use: min_faves, min_retweets, since, until, -filter:replies — use API params and post-fetch filtering instead.
Use start_time as an API parameter for the time window:
curl -s -G "https://api.x.com/2/tweets/search/recent" \
--data-urlencode "query=QUERY_HERE" \
--data-urlencode "max_results=50" \
--data-urlencode "start_time=ISO_TIMESTAMP" \
--data-urlencode "tweet.fields=created_at,public_metrics,author_id" \
--data-urlencode "user.fields=username,name" \
--data-urlencode "expansions=author_id" \
--data-urlencode "sort_order=relevancy" \
-H "Authorization: Bearer $TWITTER_BEARER_TOKEN"
Generate start_time:
date -u -d "$N hours ago" +%Y-%m-%dT%H:%M:%SZdate -u -v-${N}H +%Y-%m-%dT%H:%M:%SZFetch 3x max_results to have enough after engagement filtering.
Parse with jq — see references/twitter-api.md for full response schema.
... | jq '[
.data[] as $t |
(.includes.users[] | select(.id == $t.author_id)) as $u |
{
id: $t.id,
text: $t.text,
author: $u.username,
author_name: $u.name,
likes: $t.public_metrics.like_count,
retweets: $t.public_metrics.retweet_count,
replies: $t.public_metrics.reply_count,
views: $t.public_metrics.impression_count,
created_at: $t.created_at,
url: ("https://x.com/" + $u.username + "/status/" + $t.id)
}
] | sort_by(-.likes)'
Filter by engagement:
... | jq --argjson ml 50 --argjson mr 5 '[.[] | select(.likes >= $ml and .retweets >= $mr)]'
Trim to max_results: | .[:30]
Return the filtered array as JSON. Do not score, summarize, or format — just the raw tweet objects.
[], not an error. Some queries have no matches.2026-04-28T00:00:00Zmin_faves/min_retweets operators are not available on pay-per-use.After fetching, confirm:
共 1 个版本