Skip to content

mtple/deso-ag

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

20 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

deso-ag

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.

Installation

npm install deso-ag

Or to use as a CLI globally:

npm install -g deso-ag

From Source

git clone https://github.com/mtple/deso-ag
cd deso-ag
pnpm install

Environment Variables

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-password

Without a key, the respective source/feature is skipped and everything else still works normally.

Commands

search [query]

Search for posts across networks.

deso-ag search "ethereum"
deso-ag search "AI" --sources nostr
deso-ag search --channel dev --sources farcaster

Multi-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"

trending

Get trending posts from all networks.

deso-ag trending
deso-ag trending --sources farcaster,lens
deso-ag trending --format json --limit 50

terms

Extract 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 output

channels

Browse popular Farcaster channels.

deso-ag channels
deso-ag channels --limit 50

Options

All 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

Output Formats

  • markdown - Human-readable with headers, author info, and engagement stats. Default for search.
  • summary - Condensed overview with post counts and top content. Default for trending.
  • 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.

Sort Orders

  • engagement - By score (likes + reposts*2 + replies). Best for discovering high-signal content. Default for trending.
  • recent - By timestamp descending. Best for monitoring.
  • relevance - Query-matching posts first, then by engagement. Default for search.

Agent Usage

deso-ag is designed for consumption by AI agents doing research across decentralized social networks.

Compact Output Format

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 10

Output 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": []
    }
  ]
}

Library Import

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';

Examples

# 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

Supported Networks

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.

Limitations

  • 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.

Development

pnpm build    # Build for production
pnpm test     # Run tests

Tech Stack

  • TypeScript
  • Commander.js for CLI
  • nostr-tools for Nostr protocol
  • Native fetch for HTTP requests

License

MIT

Author

Matt Lee

About

Decentralized social media content aggregator

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors