Decentralized Social Aggregator - A CLI tool and library for aggregating posts from decentralized social protocols.
Search and view content across Farcaster, Lens, Nostr, and Bluesky from your terminal or programmatically from your agent.
npm install deso-agOr to use as a CLI globally:
npm install -g deso-aggit clone https://github.com/mtple/deso-ag
cd deso-ag
pnpm install| Variable | Required | Default | Description |
|---|---|---|---|
NEYNAR_API_KEY |
For Farcaster | None — Farcaster is skipped | Neynar API key. Get one free at neynar.com |
BLUESKY_IDENTIFIER |
For Bluesky search | None — Bluesky search is skipped, trending still works | Your Bluesky handle (e.g. user.bsky.social) |
BLUESKY_APP_PASSWORD |
For Bluesky search | None — Bluesky search is skipped, trending still works | App password from bsky.app/settings/app-passwords |
Lens, Nostr, and Bluesky trending work without any keys. Bluesky search requires authentication.
Add keys to your shell profile so they persist across sessions:
# Add to ~/.zshrc or ~/.bashrc
export NEYNAR_API_KEY=your-key-here
export BLUESKY_IDENTIFIER=your-handle.bsky.social
export BLUESKY_APP_PASSWORD=your-app-passwordWithout a key, the respective source/feature is skipped and everything else still works normally.
Search for posts across networks.
deso-ag search "ethereum"
deso-ag search "AI" --sources nostr
deso-ag search --channel dev --sources farcasterMulti-word queries use AND semantics (all terms must match):
deso-ag search "AI crypto" # posts must contain both "AI" and "crypto"
deso-ag search "ethereum layer2"Get trending posts from all networks.
deso-ag trending
deso-ag trending --sources farcaster,lens
deso-ag trending --format json --limit 50Extract top discussion terms from posts via engagement-weighted frequency analysis.
deso-ag terms # top 3 terms per platform, last 24h
deso-ag terms -n 5 -s farcaster -t week # top 5, Farcaster only, last week
deso-ag terms -f json # machine-readable outputBrowse popular Farcaster channels.
deso-ag channels
deso-ag channels --limit 50All commands accept the following options (except where noted):
| Option | Description | Values | Default |
|---|---|---|---|
-s, --sources |
Networks to query | farcaster, lens, nostr, bluesky (comma-separated) |
farcaster,lens,nostr,bluesky (all) |
-t, --timeframe |
Time range for posts | 24h, 48h, week |
24h |
-c, --channel |
Filter by channel | Any channel ID (Farcaster only) | none |
-f, --format |
Output format | json, markdown, summary, compact |
markdown (search), summary (trending) |
-l, --limit |
Max posts per source | Any positive integer | 25 |
-o, --sort |
Sort order | engagement, recent, relevance |
relevance (search), engagement (trending) |
-n, --top |
Top terms per source | Any positive integer (terms command only) | 3 |
markdown- Human-readable with headers, author info, and engagement stats. Default forsearch.summary- Condensed overview with post counts and top content. Default fortrending.json- Raw JSON array of post objects. Good for piping to other tools.compact- Single JSON object with metadata envelope, engagement scores, and full content. Designed for AI agents.
engagement- By score (likes + reposts*2 + replies). Best for discovering high-signal content. Default fortrending.recent- By timestamp descending. Best for monitoring.relevance- Query-matching posts first, then by engagement. Default forsearch.
deso-ag is designed for consumption by AI agents doing research across decentralized social networks.
The compact format returns a single JSON object with a metadata envelope, pre-computed engagement scores, full untruncated content, and source health info:
deso-ag trending -f compact -l 10
deso-ag search "AI agents" -f compact -l 10Output shape:
{
"meta": {
"query": "AI agents",
"totalPosts": 42,
"sources": [
{"name": "farcaster", "count": 15},
{"name": "lens", "count": 12},
{"name": "nostr", "count": 15}
],
"timeframe": "24h",
"fetchedAt": "2025-01-01T00:00:00.000Z"
},
"posts": [
{
"id": "...",
"source": "farcaster",
"author": "dwr",
"content": "full untruncated content...",
"timestamp": "2025-01-01T00:00:00.000Z",
"url": "https://...",
"score": 523,
"engagement": {"likes": 400, "reposts": 50, "replies": 23},
"tags": []
}
]
}For agents that run in Node.js, import aggregate() directly instead of shelling out:
import { aggregate } from 'deso-ag';
const result = await aggregate({
sources: ['farcaster', 'lens', 'nostr', 'bluesky'],
timeframe: '24h',
query: 'AI agents',
limit: 20,
sort: 'relevance',
});
console.log(result.meta.totalPosts);
for (const post of result.posts) {
console.log(`[${post.source}] @${post.author.username}: ${post.content.slice(0, 100)}`);
}The terms() function extracts top discussion terms:
import { terms } from 'deso-ag';
const result = await terms({
sources: ['farcaster', 'nostr'],
timeframe: '24h',
limit: 20,
}, 5); // top 5 terms
for (const st of result.bySource) {
console.log(`${st.source}: ${st.terms.map(t => t.token).join(', ')}`);
}Individual fetchers and utilities are also exported:
import { fetchFarcaster, fetchLens, fetchNostr, fetchBluesky, computeEngagementScore, matchesQuery, extractTerms } from 'deso-ag';# Get a quick summary of trending content
deso-ag trending -f summary -l 20
# Agent-optimized compact output sorted by engagement
deso-ag trending -f compact -o engagement -l 10
# Search for AI discussions on Lens only
deso-ag search "AI" -s lens -f json
# Multi-word search with compact output
deso-ag search "AI crypto" -f compact -l 10
# Browse the /dev channel on Farcaster
deso-ag search --channel dev -s farcaster
# Export trending Nostr posts as JSON
deso-ag trending -s nostr -f json > nostr-trending.json
# Search Bluesky for discussions
deso-ag search "ethereum" -s bluesky -l 5
# Trending on Bluesky
deso-ag trending -s bluesky -f summary
# Sort search results by recency
deso-ag search "ethereum" -o recent -f json -l 5
# Top 5 terms across all networks this week
deso-ag terms -n 5 -t week
# Terms from Farcaster and Nostr as JSON
deso-ag terms -f json -s farcaster,nostr -l 10| Network | API | Auth |
|---|---|---|
| Farcaster | Neynar API - trending feed and full-text search | NEYNAR_API_KEY required |
| Lens | Lens V3 GraphQL API - server-side search, recent posts | None |
| Nostr | nostr.wine trending API + public relays (relay.damus.io, nos.lol, relay.snort.social) | None |
| Bluesky | AT Protocol API - public "What's Hot" feed for trending, authenticated search via app.bsky.feed.searchPosts |
None (trending), BLUESKY_IDENTIFIER + BLUESKY_APP_PASSWORD (search) |
All networks return engagement stats (likes, reposts, replies) and support timeframe filtering.
- Farcaster: Requires
NEYNAR_API_KEY. Without it, Farcaster is skipped. - Nostr: Relay responses can be slow or inconsistent depending on network conditions.
- Rate limits: All APIs have rate limits. For heavy usage, consider running your own infrastructure.
pnpm build # Build for production
pnpm test # Run tests- TypeScript
- Commander.js for CLI
- nostr-tools for Nostr protocol
- Native fetch for HTTP requests
MIT