Skip to content

haileyok/dontshowmethis

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

dontshowmethis

An AI-powered Bluesky content moderation system that automatically labels replies to monitored accounts using LLM-based content analysis.

Overview

This project monitors Bluesky posts in real-time via Jetstream and uses an LLM (via any OpenAI-compatible completions API) to classify replies to watched accounts. It automatically applies labels such as "bad-faith", "off-topic", and "funny" to help users filter and moderate content.

The system supports multiple AI providers including LM Studio (local), OpenAI, Claude (Anthropic), and any other OpenAI-compatible API.

The system consists of two components:

  1. Go Consumer - Monitors the Jetstream firehose and analyzes replies using an LLM
  2. Skyware Labeler - TypeScript server that manages and emits content labels

Architecture

Jetstream → Go Consumer → Completions API (LLM) → Labeler Service → Bluesky
  1. The Go consumer subscribes to Jetstream and monitors replies to specified accounts
  2. When a reply is detected, it fetches the parent post and sends both to your completions API
  3. The LLM classifies the reply based on the system prompt
  4. Labels are emitted via the Skyware labeler service
  5. Labels are propagated to Bluesky's labeling system

Prerequisites

  • An OpenAI-compatible completions API endpoint:
  • A Bluesky account for the labeler

Installation

Clone the repository

git clone https://github.com/haileyok/dontshowmethis.git
cd dontshowmethis

Install Go dependencies

go mod download

Install labeler dependencies

cd labeler
yarn install
cd ..

Configuration

Copy the example environment file and configure it:

cp .env.example .env

Environment Variables

For the Go Consumer:

  • PDS_URL - Your Bluesky PDS URL (e.g., https://bsky.social)
  • ACCOUNT_HANDLE - Your Bluesky account handle
  • ACCOUNT_PASSWORD - Your Bluesky account password
  • WATCHED_OPS - Comma-separated list of DIDs to monitor for replies and emit labels for
  • WATCHED_LOG_OPS - Comma-separated list of DIDs to monitor for replies but not emit labels for. Will use SQLite to keep a log
  • LOGGED_LABELS - Comma-separated list of labels that will be logged to the SQLite database
  • JETSTREAM_URL - Jetstream WebSocket URL (default: wss://jetstream2.us-west.bsky.network/subscribe)
  • LABELER_URL - URL of your labeler service (e.g., http://localhost:3000)
  • LABELER_KEY - Authentication key for the labeler API
  • COMPLETIONS_API_HOST - Completions API host (e.g., http://localhost:1234 for LM Studio, https://api.openai.com for OpenAI, https://api.anthropic.com for Claude)
  • COMPLETIONS_ENDPOINT_OVERRIDE - (Optional) Override the API endpoint path. Required for Claude (/v1/messages). Defaults to /v1/chat/completions if not specified
  • COMPLETIONS_API_KEY - (Optional) API key for providers that require authentication (OpenAI, Claude, etc.)
  • COMPLETIONS_API_KEY_TYPE - (Optional) API key authentication type. Either bearer (for OpenAI) or x-api-key (for Claude)
  • MODEL_NAME - Model name to use (default: google/gemma-3-27b)
  • LOG_DB_NAME - The name of the SQLite db to log to
  • LOG_NO_LABELS - (Optional) When enabled, logs posts with no labels as "no-labels" to the database (does not emit labels)

For the Skyware Labeler:

  • SKYWARE_DID - Your labeler's DID
  • SKYWARE_SIG_KEY - Your labeler's signing key
  • EMIT_LABEL_KEY - Secret key for the emit label API (must match LABELER_KEY above)

Running the Services

1. Start your Completions API

The system supports multiple AI providers. Configure the appropriate environment variables based on your provider:

Using LM Studio (Local):

  1. Open LM Studio
  2. Load a compatible model (recommended: google/gemma-3-27b or similar)
  3. Start the local server (usually runs on http://localhost:1234)
  4. Configure:
    COMPLETIONS_API_HOST=http://localhost:1234
    MODEL_NAME=google/gemma-3-27b
    # No API key required for local LM Studio

Using OpenAI: Configure the following in your .env:

COMPLETIONS_API_HOST=https://api.openai.com
COMPLETIONS_API_KEY=sk-proj-...
COMPLETIONS_API_KEY_TYPE=bearer
MODEL_NAME=gpt-4o-mini  # or gpt-4o, gpt-3.5-turbo, etc.
# COMPLETIONS_ENDPOINT_OVERRIDE not needed (uses default /v1/chat/completions)

Using Claude (Anthropic): Configure the following in your .env:

COMPLETIONS_API_HOST=https://api.anthropic.com
COMPLETIONS_ENDPOINT_OVERRIDE=/v1/messages
COMPLETIONS_API_KEY=sk-ant-...
COMPLETIONS_API_KEY_TYPE=x-api-key
MODEL_NAME=claude-3-5-sonnet-20241022  # or other Claude models

Using other OpenAI-compatible APIs: Most providers use the same configuration as OpenAI (bearer token auth):

COMPLETIONS_API_HOST=https://your-provider-api.com
COMPLETIONS_API_KEY=your-api-key
COMPLETIONS_API_KEY_TYPE=bearer
MODEL_NAME=provider-model-name

2. Start the Labeler Service

cd labeler
npm start

The labeler will start two servers:

  • Port 14831: Skyware labeler server
  • Port 3000: Label emission API

3. Start the Go Consumer

go run .

Or build and run:

go build -o dontshowmethis
./dontshowmethis

Usage

Once running, the system will:

  1. Connect to Jetstream and monitor the firehose
  2. Watch for replies to accounts specified in WATCHED_OPS
  3. Automatically analyze and label qualifying replies
  4. Log all actions to stdout

Finding Account DIDs

To monitor specific accounts, you need their DIDs. You can find a DID by:

curl "https://bsky.social/xrpc/com.atproto.identity.resolveHandle?handle=username.bsky.social"

Add the returned DID to your WATCHED_OPS environment variable.

How Content Classification Works

The system uses a structured prompt to classify content. See lmstudio.go:147 for the system prompt.

Development

Project Structure

.
├── main.go              # CLI setup and consumer initialization
├── handle_post.go       # Post handling and labeling logic
├── lmstudio.go         # Completions API client and content classification
├── sets/
│   └── domains.go      # Political domain list (currently unused)
├── labeler/
│   ├── index.ts        # Skyware labeler service
│   └── package.json    # Labeler dependencies
├── .env.example        # Example environment configuration
└── README.md           # This file

Adding New Labels

  1. Add the label constant in main.go:

    const LabelNewLabel = "new-label"
  2. Add it to the labeler's allowed labels in labeler/index.ts:

    const LABELS: Record<string, boolean> = {
      'bad-faith': true,
      'off-topic': true,
      'funny': true,
      'new-label': true,  // Add here
    }
  3. Update the LLM schema in lmstudio.go to include the new classification

  4. Update the handling logic in handle_post.go to emit the new label

License

MIT

Acknowledgments

About

Personalized Bluesky moderation making use of labelers and online/offline LLMs

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •