Skip to main content
ClaudeWave
Skill510 estrellas del repoactualizado today

Farcaster Digest

Farcaster Digest curates and ranks Farcaster casts by signal strength rather than raw engagement, clustering conversations into 2–3 narratives with conversation-shape headers and original insights per cast. Use this when you need a filtered, editorially refined summary of Farcaster activity around specific topics like prediction markets, AI agents, or mechanism design, with automatic deduplication across a rolling 7-day window and support for topic or channel filtering.

Instalar en Claude Code
Copiar
git clone --depth 1 https://github.com/aaronjmars/aeon /tmp/farcaster-digest && cp -r /tmp/farcaster-digest/skills/farcaster-digest ~/.claude/skills/farcaster-digest
Después abre una sesión nueva de Claude Code; el skill carga automáticamente.

SKILL.md

<!-- autoresearch: variation B — sharper output via cluster + signal score + insight extraction; folds in A's semantic/channel inputs and C's source-status footer + persistent dedup -->

> **${var}** — Topic filter or channel name (e.g. "prediction-markets", "base", "ai-agents"). If empty, uses default interest areas.

If `${var}` is set, focus curation on that topic or channel.

Read `memory/MEMORY.md` for current interests.
Read the last 2 days of `memory/logs/` for recency context.
Load persistent dedup state from `memory/state/farcaster-seen-hashes.json` (auto-created; safe to delete to reset dedup). The file starts as `{"hashes": [], "updated": null}` and stores cast hashes seen in the last 7 days — casts present here are skipped even if they re-appear in algorithmic feeds.

## Thesis

Curation is the biggest lever, not fetching. Raw engagement counts rank by popularity, not conversation. This skill ranks by a signal score, clusters casts into 2–3 sub-narratives, leads with a one-line conversation-shape header, and demands an original insight per cast — not a paraphrase of the cast text.

## Steps

### 1. Fetch casts from three complementary sources

For every endpoint, prefer `WebFetch` over curl (sandbox often blocks curl — see CLAUDE.md). Auth header: `x-api-key: $NEYNAR_API_KEY`.

**(a) Topic search — literal + semantic.**
Run each default topic query twice: once with `mode=literal` (default), once with `mode=semantic` to catch thematic matches the keyword query misses.

```
GET https://api.neynar.com/v2/farcaster/cast/search/?q=QUERY&sort_type=algorithmic&mode=literal&limit=20
GET https://api.neynar.com/v2/farcaster/cast/search/?q=QUERY&sort_type=algorithmic&mode=semantic&limit=20
```

Default topics (override with `${var}` or MEMORY.md interests):
- `"prediction markets" | "coordination markets" | polymarket | kalshi | futarchy`
- `"AI agents" | "autonomous agents" | agentic | "agent frameworks"`
- `hyperstitions | "mechanism design" | "network states" | "public goods"`

If `${var}` is set, replace all default topics with a single search on `${var}`.

**(b) Channel feed — high-signal channels.**
Sample recent casts from 3–4 channels relevant to Aeon's interests:

```
GET https://api.neynar.com/v2/farcaster/feed/channels?channel_ids=ai-agents,base,founders,ethereum&with_recasts=false&with_replies=false&limit=30
```

(If `${var}` looks like a channel slug, query that channel alone.)

**(c) Global trending — network-wide context.**
```
GET https://api.neynar.com/v2/farcaster/feed/trending?limit=25&time_window=24h
```

Record per-source status (`ok` | `fail` | `empty`) as you go — you'll emit it in the footer.

### 2. Filter and deduplicate

- Drop any cast whose `hash` is in `farcaster-seen-hashes.json`.
- Drop any cast older than 48h (use `timestamp` field).
- Drop casts whose `author.follower_count` is below 500 — removes most spam/fresh-acct noise.
- Drop near-duplicates (same author posting near-identical text within the window).
- Drop pure shilling: casts that are almost entirely `$TICKER` + a link and no commentary.

### 3. Score and rank

Compute a signal score for each surviving cast:

```
signal = reactions.likes_count + 2 × reactions.recasts_count + 0.5 × replies.count
```

Rationale: recasts signal endorsement (worth ~2 likes); replies signal controversy/noise (halved). Raw likes remain the base. Take the top 15 by signal score into the editorial pass.

**Engagement floor:** exclude anything with `signal < 10`. If fewer than 3 casts clear the floor, lower it to 5 rather than returning nothing.

### 4. Cluster into 2–3 sub-narratives

Read the top 15 and group them into **2 or 3 themed clusters**. Examples of good cluster labels:
- "prediction market volume chasing the election cycle"
- "agent frameworks debating memory vs. tools"
- "base mini-apps shipping faster than the analytics can track"

Avoid generic labels like "crypto news" or "AI". A cluster label should name a *conversation*, not a topic.

From each cluster, select the 2–3 casts that best represent the argument — diversity of voices over highest-engagement if they overlap.

Target total: **5–8 casts across clusters**.

### 5. Format the digest

Keep under 4000 chars. Lead with a one-line conversation-shape header describing what's happening on Farcaster today, then one block per cluster.

```
farcaster digest — ${today}
shape: <one line, ≤20 words, what's the conversation today>

—— <cluster 1 label> ——

@username — "cast text here (truncate >240 chars)"
↳ 142 likes · 31 recasts · 18 replies | warpcast.com/username/0xabc123
insight: <one line, ≤25 words, something a reader couldn't get from the cast text alone>

@username2 — "..."
↳ ... | warpcast.com/...
insight: ...

—— <cluster 2 label> ——

...

sources: search=ok trending=ok channels=ok | new casts: 7 | seen-cache: 142 hashes
```

**Insight discipline:** prefer casts where the `insight:` line adds something — implication, counter-argument, context the cast assumes, or a connection to another cast in the digest — over casts where the best you can write is a paraphrase. When choosing between casts of similar signal, pick the one that yields a non-paraphrase insight.

### 6. Send via `./notify`

Pass the formatted digest to `./notify "<digest>"`.

### 7. Persist state and log

- Append every included cast's hash to `memory/state/farcaster-seen-hashes.json`. Prune entries older than 7 days before writing.
- Log to `memory/logs/${today}.md` under `### farcaster-digest` with: search queries used, source-status line, cluster labels chosen, cast count included, and any notable edge cases (e.g. engagement-floor lowered).

## Empty vs error

- **Empty run (`FARCASTER_DIGEST_OK`):** sources succeeded, but nothing cleared the engagement floor or all surviving casts were already in the seen cache. Notify: `farcaster digest: quiet day — <N> casts fetched, 0 passed signal floor`. Log the source-status line.
- **Error run (`FARCASTER_DIGEST_ERROR`):** every source retu