This repository has no description
README.md

Skeets That You Misunderstood #

AT Protocol feed generator ranking posts by controversy using Wilson score intervals.

This is an experiment and not made to be used for real. It's only posts that make you go huh.

I can tell it works because it's all posts from The Onion, about US politics and gay p*rn.

What It Does #

Subscribes to the Bluesky firehose, tracks likes/unlikes, and serves ranked feeds via AT Protocol.

Feeds:

  • controversial — Daily controversy rankings
  • controversial-weekly — Weekly controversy rankings

Quickstart #

1. Prerequisites #

  • Bluesky account
  • Go 1.26+
  • Domain you control (for DID) (for dev, https://srv.us suffices)

2. Create Feed Records #

Create records in your Bluesky repo:

# Publish feeds (requires BSKY_HANDLE and BSKY_PASSWORD)
BSKY_HANDLE=your.handle BSKY_PASSWORD=your-pass go run ./cmd/tools/publish

This creates app.bsky.feed.generator/controversial and controversial-weekly records.

3. Configure #

cp .env.example .env
# Edit .env with:
# FEEDGEN_HOSTNAME=feeds.yourdomain.com
# FEEDGEN_SERVICE_DID=did:web:feeds.yourdomain.com
# FEEDGEN_PUBLISHER_DID=your-did

4. Run #

go run ./cmd/feed

5. Test #

# Get feed
curl "http://localhost:3000/xrpc/app.bsky.feed.getFeedSkeleton?feed=at://did:plc:you/app.bsky.feed.generator/controversial&limit=10" | jq .

# Health check
curl http://localhost:3000/xrpc/_health

# Metrics
curl http://localhost:3000/debug/metrics | jq .

Architecture #

All state is held in memory. A periodic checkpoint (every 10s, plus on shutdown) atomically persists to disk for crash recovery.

graph LR
    B[Bluesky Firehose] -->|events| S[Subscriber]
    S -->|inc| L[In-Memory Counters]
    S -->|update scores| SC[ScoreStore]
    L -->|checkpoint| CK[checkpoint.gob]
    D[Deleted Set] -->|checkpoint| CK
    P[Post Index] -->|checkpoint| CK
    SC -->|rank| F[Feed Handler]
    F -->|serve| B2[Bluesky PDS]
    CK -.->|restart: load| L
    CK -.->|restart: load| SC

Data Flow #

sequenceDiagram
    participant B as Bluesky Firehose
    participant S as Subscriber
    participant L as Memory Counters
    participant SC as ScoreStore
    participant CK as Checkpoint (every 10s)
    participant FH as Feed Handler
    participant PDS as Bluesky PDS

    B->>S: Like/Unlike/Post events
    S->>L: IncLikes(uri) — atomic map increment
    S->>SC: UpdateScoreWithCounts(uri, likes, unlikes)
    L-->>CK: Snapshot maps → persist.go
    CK->>CK: tempfile + rename (atomic commit)
    PDS->>FH: GET /xrpc/app.bsky.feed.getFeedSkeleton
    FH->>SC: Top(limit, window)
    SC-->>FH: []ScoredPost sorted
    FH-->>PDS: Feed skeleton (URIs only)
    PDS-->>User: Hydrated feed

Configuration #

Variable Description Default
FEEDGEN_PORT HTTP port 3000
FEEDGEN_HOSTNAME Public hostname example.com
FEEDGEN_SERVICE_DID Service DID did:web:$HOSTNAME
FEEDGEN_PUBLISHER_DID Your Bluesky DID did:example:alice
FEEDGEN_DATA_DIR Checkpoint storage dir ./data
FEEDGEN_SUBSCRIPTION_ENDPOINT Firehose URL wss://relay1...
FEEDGEN_LOGGER_LEVEL Log level (0=INFO) 0

Project Structure #

cmd/
  feed/          # Main feed generator
  tools/
    publish/     # Publish feed records
    unpublish/   # Unpublish feed records
cursorstore/     # Firehose cursor tracking (in-memory)
likesstore/      # Like/unlike counters (in-memory)
deletestore/     # Deleted post tracking (in-memory)
scorestore/      # Wilson score + in-memory sorted indexes
persist/         # Atomic checkpoint save/load
subscriber/      # Firehose consumer
xrpc/            # AT Protocol XRPC handlers

Commands #

# Run feed generator
go run ./cmd/feed

# Publish feeds to Bluesky
BSKY_HANDLE=your.handle BSKY_PASSWORD=pass go run ./cmd/tools/publish

# Unpublish feeds
BSKY_HANDLE=your.handle BSKY_PASSWORD=pass go run ./cmd/tools/unpublish

# Run tests
go test ./...

# Build binary
go build -o feedgen ./cmd/feed