Inspiration
On March 6, 2026, Reddit removed the subreddit-association lookup API. Within a day, r/ModSupport was full of the same posts: Saferbot broke, Hive Protect stopped working, modqueues piled up. I moderate a few subs and had been relying on that stack for ban-evasion — same scam-DM patterns, karma-farm-then-pivot accounts, affiliate rings — and suddenly there was nothing catching them before they hit the queue.
I spent about a week reading those threads and trying to figure out what could still work without that endpoint. The idea I landed on: opt-in federation between subs that already trust each other, threat data on each sub's own wiki (no central server), and only behavioral hashes in the feed — no usernames, no post text. I scoped it tight (four weeks, one demo path) and shipped Hive Restored as a Devvit app to see if that was enough.
What it does
Modqueue badge — from the mod menu on a flagged user: composite score, which signals fired, which peer subs saw similar behavior, plus ban / remove / mod-note checkboxes in one popover.
Wiki-backed threat feed — when your team bans someone, the app appends an opaque fingerprint to
r/<sub>/wiki/hive-threats; peer subs can pick it up on their next poll (~60s).Trust circle UI — mod-menu form to add/remove peer subs or apply a preset; no config files.
Shadow mode by default — new installs only alert. Auto ban/remove is per-signal opt-in.
Action log — peer changes and mod actions logged on the dashboard, with undo where it makes sense.
How we built it
Stack: Devvit Web (0.12.24), TypeScript, Hono, tRPC, React 19, Tailwind
CSS 4, Vite, Vitest, Zod, Redis (Devvit-managed). Cross-sub data goes through
Reddit's wiki API (context.reddit.getWikiPage / reddit.updateWikiPage) —
same primitive AutoMod configs use. No external host, no Worker, no extra
domain allowlist.
Flow. onCommentSubmit / onPostSubmit run a fingerprinter → composite
scorer in src/server/fingerprint/composite.ts matches against a Redis index
built from peer wikis. On ban, wikiPublisher.ts writes a hashed record to
this sub's wiki. A 2-minute cron in src/server/routes/scheduler.ts pulls
peer hive-threats pages via wikiSubscriber.ts, dedupes, updates the local
cache. UI is a Devvit form (modqueueBadge.ts) plus a React dashboard
(src/client/) over Hono/tRPC.
Why wikis instead of a coordinator. I started with a Cloudflare Worker (HMAC, KV, rate limits — ~600 LOC) and dropped it after r/Devvit confirmed wiki reads across subs are supported. Wikis are free on-platform, each sub owns its page, and mods can audit or delete their data without asking me.
Three signals (all in src/server/fingerprint/):
Posting-time entropy (
timeEntropy.ts) — 24-bin UTC histogram, Shannon entropy + KL vs a hand-tuned baseline → 64-bit hash. Night-shift humans can look weird here; that's why scoring needs the other signals.N-gram cadence SimHash (
ngramCadence.ts) — mask content words with␡CONTENT␡, top 32 bigrams/trigrams, SimHash → 128-bit hex. Catches similar "voice" across accounts even when usernames and topics change.Domain-history MinHash (
domainHistory.ts) — eTLD+1 from posted URLs, minus a 16-domain platform denylist, MinHash → base64 signature. Useful for affiliate-spam rings that keep the same monetized domains.
Privacy. Threat records are hashes + category + timestamp. No username, no comment body, no URL list in the payload. Wikis are world-readable, so these are correlation tokens for mods who opted into a trust circle — not anonymous identifiers.
Challenges we ran into
1. March 6 API break. I'd planned around the same association lookup Saferbot used. That disappeared a week into scaffolding, so I rewrote the pitch: federation + fingerprints instead of cloning the old API path.
2. Dropping the Cloudflare coordinator. Cut ~600 LOC of Worker code and
replaced it with wikiPublisher.ts + wikiSubscriber.ts (~150 LOC). Less
to deploy, no hosting bill, simpler story for Reddit review.
3. False positives vs catch rate. Any single signal alone is noisy (night
owl ≠ bot, hobbyist ≠ spam ring). I added a composite bonus when 2–3 signals
agree (+4/+8 in composite.ts), kept shadow mode as the default, and added
an explicit "mark false positive" path so FP rate is measurable in metrics.
Threshold tweaks live in composite.test.ts.
Accomplishments that we're proud of
- Ban in sub A → wiki record → sub B's cron picks it up → badge on next
matching post. Tested across
{TBD_TEST_SUBS}internal subs during the hackathon window. - Threat schema in
wikiPublisher.tsreally has no username/content fields — you can open the wiki page and check (demo video does this around 0:36). - 216 unit tests passing;
npm run deployruns typecheck, lint, and Vitest first. Coverage includes fingerprints, federation, trust graph, modqueue form, dashboard routes
What we learned
- I burned two days on the Worker before wikis were the obvious answer. The annoying part was scoring thresholds and what to put in the feed, not transport.
- Mods kept asking "can I install without it doing anything?" — shadow-by- default made that a non-issue.
- Cutting LLM stylometry, multi-language n-grams, and bulk historical scan on day 8 left time for bugs and copy instead of a half-finished fourth signal.
What's next for Hive-Restored
If I keep working on it after the hackathon:
- LLM stylometry (BYO key) — skipped for v1 because demo-day API keys are fragile; could be per-sub opt-in later.
- Bulk historical scan — "score everyone who posted in 90 days" needs Redis quota math I haven't done yet.
- Multi-language n-grams — English-only function-word lists today; pipeline is otherwise language-agnostic.
- Big trust circles (50+ subs) — not sure how wiki polling scales past ~30 peers; needs load tests.
- Mobile-friendly dashboard — desktop layout works; touch layout is mostly Tailwind rearranging.
Built With
- devvit
- javascript
- typescript
- vite
Log in or sign up for Devpost to join the conversation.