Skip to content

indicaindependent/bsky-campaign-engine

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

12 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

πŸ“‘ Bluesky Campaign Engine

Automated Bluesky campaign scheduling β€” AT Protocol + Cloudflare D1 + thread chaining

Bluesky Cloudflare Workers License: MIT


What Is This

A production-grade campaign scheduling engine for Bluesky. Schedule multi-post thread campaigns with images, facets (links/mentions/tags), and precise timing β€” all running serverless on Cloudflare's edge.

Built and battle-tested running real investigative journalism campaigns on Bluesky.


Features

  • 🧡 Thread Chaining β€” proper reply chains with root/parent URI tracking
  • πŸ–ΌοΈ Image Embedding β€” automatic image upload + blob attachment
  • 🏷️ Facet Support β€” links, mentions, hashtags auto-detected and encoded
  • ⏱️ D1-Based Scheduling β€” fire at precise times via CF Cron
  • πŸ”’ Fire-Once Lock β€” D1 state prevents double-posting
  • πŸ“¦ Campaign Archive β€” completed campaigns archived, never deleted
  • 🌐 REST API β€” inject campaigns via /inject, check status via /status

Architecture

POST /inject (campaign payload)
        β”‚
        β–Ό
schedule-worker (D1: schedule-db)
        β”‚
CF Cron Trigger (every minute check)
        β”‚
        β–Ό
bsky-worker ──► AT Protocol API ──► Bluesky
        β”‚
        └── Update D1 (post URIs, CIDs, status)

Campaign Payload Format

{
  "campaign_id": "my-campaign-001",
  "handle": "yourhandle.bsky.social",
  "posts": [
    {
      "post_index": 0,
      "text": "🧡 THREAD: My investigation into X...",
      "image_url": "https://example.com/image.jpg",
      "scheduled_at": "2026-05-02T14:00:00Z"
    },
    {
      "post_index": 1,
      "text": "1/ Here's what we found...",
      "scheduled_at": "2026-05-02T14:05:00Z"
    }
  ]
}

Self-Hosting

git clone https://github.com/indicaindependent/bsky-campaign-engine
cd bsky-campaign-engine

cp wrangler.toml.example wrangler.toml

wrangler d1 create campaign-db
wrangler secret put BSKY_APP_PASS
wrangler secret put WORKER_SECRET

wrangler deploy

Grapheme Safety

All posts are validated against Bluesky's 300-character limit (JS length, not byte count). Flag emoji = 4 chars. Hard ceiling enforced before posting.


License

MIT


Battle-tested on real investigative campaigns | Built by Indica Independent

About

πŸ“‘ Automated Bluesky campaign scheduling engine β€” AT Protocol + Cloudflare D1 + thread chaining

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors