Skip to content
Back to skills

Tweet Digest

ASecurity

Account-based digest of recent tweets from tracked X/Twitter accounts. Sibling to fetch-tweets (keyword) and tweet-roundup (topic).

  • 12 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 21, 2026
ai-agentsgobashapi

Works with

  • cursor
  • cli
  • api

Security analysis

A100/100

Scanned October 21, 2026

npx -y skills add aeonfun/aeon-agent --skill tweet-digest --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Tweet Digest?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Tweet Digest
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/aeonfun-tweet-digest/badge)](https://www.skillsdirectory.com/skills/aeonfun-tweet-digest)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
type: Skill
name: Tweet Digest
category: basics
description: Account-based digest of recent tweets from tracked X/Twitter accounts. Sibling to fetch-tweets (keyword) and tweet-roundup (topic).
var: ""
tags: [social]
requires: [TWITTER_API_KEY, XAI_API_KEY?]
---
> **${var}** — Optional. If set, restrict to that single account (or topic filter). If empty, processes every account in `memory/topics/tracked-accounts.yml`.

This skill is the **account-based** sibling in the tweet-fetcher family:

| Skill | Axis | Input |
|---|---|---|
| `fetch-tweets` | keyword / query | `${var}` is the search query |
| `tweet-roundup` | topic | groups recent tweets by topic |
| `tweet-digest` (this) | **account** | reads a list of handles from `memory/topics/tracked-accounts.yml` |

Use this skill when you care about "what did *these specific people* post" rather than "what's anyone saying about X."

## Voice

If `soul/SOUL.md` and `soul/STYLE.md` are populated, read both and match the operator's voice for the per-tweet one-sentence takes. If they are empty templates or absent, write the takes in a clear, direct, neutral tone — no hedging, no editorializing beyond what the tweet itself says.

## Config

Reads `memory/topics/tracked-accounts.yml`. If the file is missing or `accounts: []`, log `TWEET_DIGEST_NO_CONFIG` and exit (no notification).

```yaml
# memory/topics/tracked-accounts.yml
accounts:
  - handle: vitalikbuterin
    why: ethereum core thinking
  - handle: balajis
    why: macro + tech narratives
  - handle: <handle>
    why: <one-line reason — used to give the digest grouping context>
```

The `why` field is optional but useful — it's the grouping/context label in step 2.

## Steps

Read `memory/MEMORY.md` for context and the last 2 days of `memory/logs/` to dedup recent tweets.

### 1. Fetch recent tweets per account

For each `handle` in the config (or just the one from `${var}` if set):

**Path A - twitterapi.io (primary).** `/user/last_tweets` returns structured tweet objects (exact engagement counts, real permalinks, parsed fields) in ~700ms - no fabrication risk. It has no server-side date filter, so keep the last 3 days client-side on `.createdAt`. Auth via `./secretcurl` with the literal `{TWITTER_API_KEY}` placeholder (never `$TWITTER_API_KEY`; see CLAUDE.md -> Network & Secrets):

```bash
SINCE=$(date -u -d '3 days ago' +%Y-%m-%d 2>/dev/null || date -u -v-3d +%Y-%m-%d)
HTTP=$(./secretcurl -m 30 -s -o /tmp/tw-td.json -w '%{http_code}' -G "https://api.twitterapi.io/twitter/user/last_tweets" \
  --data-urlencode "userName=$HANDLE" -H "X-API-Key: {TWITTER_API_KEY}")
echo "twitterapi http=$HTTP"
# on HTTP 200: last-3-day originals (createdAt is Twitter native format; strptime normalizes to a date), skip replies/RTs
jq -r --arg since "$SINCE" '
  .data.tweets[]
  | select((.isReply // false) | not)
  | (try (.createdAt | strptime("%a %b %d %H:%M:%S %z %Y") | strftime("%Y-%m-%d")) catch (.createdAt[0:10])) as $d
  | select($d >= $since)
  | [.author.userName, $d, .likeCount, .retweetCount, .replyCount, .url, .text] | @tsv' /tmp/tw-td.json
```

On `HTTP=200` with parsed rows, take the 5 most interesting or substantive tweets for that handle; paginate with `&cursor=<next_cursor>` only if you need older in-window tweets.

**Path B - xAI Grok `x_search` (fallback).** Only if a handle's Path A returned non-2xx, empty, or timed out (or `TWITTER_API_KEY` is unset). Call Grok's `x_search` **in-run** with `./secretcurl` (the literal `{XAI_API_KEY}` placeholder - never `$XAI_API_KEY`; see CLAUDE.md -> Network & Secrets). Capture the HTTP status and print `http=<code>` before parsing:

```bash
PROMPT="Search X for the latest tweets from ${HANDLE} in the last 3 days. Return the 5 most interesting or substantive tweets. For each: full text, date, direct link (https://x.com/${HANDLE}/status/ID). Skip retweets of others."
jq -n --arg p "$PROMPT" '{model:"grok-4-1-fast", input:[{role:"user",content:$p}], tools:[{type:"x_search"}]}' > /tmp/xai-td.json
HTTP=$(./secretcurl -m 60 -s -o /tmp/xai-td-out.json -w '%{http_code}' -X POST "https://api.x.ai/v1/responses" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer {XAI_API_KEY}" \
  -d @/tmp/xai-td.json)
echo "http=$HTTP"
```

Then parse `/tmp/xai-td-out.json` for the tweets. If neither `TWITTER_API_KEY` nor `XAI_API_KEY` is set, log `TWEET_DIGEST_NO_KEY: skill requires TWITTER_API_KEY or XAI_API_KEY` and exit (no notification). On a non-2xx `http`, a `--max-time` timeout, or a 200 with an empty body on both paths, record the real reason (`http-<code>` / `timeout` / `empty`) and skip that handle - never blame a "sandbox".

**Dedup:** grep the last 2 days of `memory/logs/` for `https://x.com/` URLs already reported. Drop any candidate URL that's already been seen.

### 2. Group by theme, not by account

Walk the candidate set across all accounts. Identify 2–4 themes (e.g. "L2 design decisions", "macro / rates", "AI model releases", "regulation"). Each tweet maps to one theme. A `why:` label from the config can seed theme naming when an account is a single-topic feed.

### 3. Write a one-sentence take per notable tweet

The take states **what the tweet says**, not your opinion of it. Voice per the Voice section above.

### 4. Format and notify

Send via `./notify` (under 4000 chars):

```
*Tweet Digest — ${today}*

*Theme: <theme>*
@handle: <one-sentence summary> — [link](url)
@handle: <one-sentence summary> — [link](url)

*Theme: <theme>*
...
```

### 5. Log

Append to `memory/logs/${today}.md` with the tweet URLs reported (so the next run can dedup). If no notable tweets found across all tracked accounts: log `TWEET_DIGEST_OK` and end (no notification).

## Fetching - in-run, no prefetch

Auth'd calls run **in-run** via `./secretcurl` with a literal `{ENV}` placeholder - twitterapi.io (`{TWITTER_API_KEY}`, primary) and X.AI Grok (`{XAI_API_KEY}`, fallback); see step 1 and CLAUDE.md -> Network & Secrets. There is **no** prefetch/cache step - the retired `.xai-cache/` + `scripts/prefetch-xai.sh` pattern no longer exists; do not reference it.

## Environment Variables

- `TWITTER_API_KEY` - primary. twitterapi.io key (`X-API-Key` header) for structured tweet fetches via `/user/last_tweets`.
- `XAI_API_KEY` - optional fallback. X.AI API key for Grok's `x_search` tool when twitterapi.io is unavailable.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.