Inspiration

Reddit moderation has always been reactive. AutoModerator, bots, and mod teams spend enormous energy cleaning up posts after they've already gone live — after users wasted time writing rule-breaking submissions, after feeds got cluttered, after mod queues piled up. We wanted to flip that entirely. What if bad posts never went live in the first place? PostPilot was born from that frustration — the idea that moderation should be architectural, not janitorial.

What it does

PostPilot is a proactive Reddit moderation portal built on Devvit. It deploys as a stickied interactive post directly inside your subreddit. Instead of using Reddit's native composer, users draft their submissions inside PostPilot's premium webview interface, which validates their content in real-time against subreddit-specific rules — title regex patterns, minimum body length, blacklisted keywords, account age, and karma thresholds — before anything ever reaches Reddit's servers.

If a user tries to bypass the portal and post natively anyway, an automated enforcer trigger fires instantly, removes the post, and replies with a pinned moderator comment directing them back to the portal.

Moderators get a private telemetry dashboard that tracks every approval, rejection, and enforcer bypass in real-time — all surfaced through a beautiful analytics hub visible only to the mod team.

How we built it

PostPilot runs on the Devvit platform using a standard Blocks + WebView postMessage architecture.

The frontend is a React application built with Vite, rendering inside a Devvit <webview> tag as a stickied custom post type. It features a split-pane composer: a live drafting panel with real-time rule validation checklist on the left, and a fast pure-regex Markdown preview on the right — no external dependencies.

The backend lives entirely in src/main.tsx, the single Devvit runner entry point. All client-server communication happens over a secure postMessage RPC bridge — the client sends typed requests (GET_RULES, GET_USER_STATUS, PUBLISH, GET_STATS) with unique request IDs, and the backend resolves them asynchronously using ui.webView.postMessage. Redis powers idempotency locking (preventing double-submits under flaky connections), whitelist tracking of portal-submitted posts, and the telemetry event counters.

The architecture is intentionally serverless-free — no Hono routers, no Node.js isolates, no external HTTP calls. Everything runs inside Reddit's sandboxed Devvit runner.

Challenges we ran into

The biggest challenge was an architecture migration mid-build. We initially built PostPilot using @devvit/web — a Hono-based serverless framework — which looked promising but caused persistent "Remote Bootstrap" failures on installation due to the platform runtime being unable to resolve @devvit/web/server module paths in the app registry.

Debugging this was painful. Local builds succeeded perfectly; the error only surfaced on the Reddit platform side during installation. We tried version bumps, cache-busting, and init --force without success. Ultimately, we made the call to fully migrate to the standard Blocks + WebView postMessage pattern — rebuilding the entire communication layer, stripping all Hono dependencies, and consolidating all backend logic into a single main.tsx runner.

A second challenge was stale platform-side configuration. Even after our code was clean, devvit.json still contained legacy "triggers" and "menu" endpoint declarations that caused the platform router to attempt HTTP proxying to server endpoints that no longer existed — resulting in cryptic fetch failed errors at runtime. Removing those declarations and letting Devvit.addTrigger() and Devvit.addMenuItem() register them in-process resolved it completely.

Accomplishments that we're proud of

  • Successfully migrated from a complex serverless Hono architecture to a clean, standard Devvit Blocks + WebView implementation — with zero functionality lost.
  • Built a fully working postMessage RPC layer with request ID-based async resolution, turning the browser message channel into a typed, promise-based API.
  • Shipped a premium webview UI with live Markdown preview, animated validation checklist, and a moderator telemetry hub — all under 172KB gzipped.
  • Implemented a bulletproof enforcer: any post submitted outside the portal is auto-removed within milliseconds and met with a pinned mod comment.
  • All client unit tests passing at 100% across validation logic, Markdown parsing, and keyword blacklist checks.

What we learned

  • The Devvit platform has two very distinct deployment models — the serverless @devvit/web path and the standard Blocks + postMessage path — and mixing them even accidentally in config files causes hard-to-debug runtime failures.
  • devvit.json trigger and menu declarations are for the serverless model only. In Blocks architecture, they must be registered purely in code.
  • The postMessage RPC pattern is remarkably powerful. With a thin request-ID-based wrapper, you get a fully typed, async, bidirectional communication layer between the sandboxed WebView and the Devvit runner — no HTTP, no auth tokens, no CORS.
  • Ship small, verify on the platform early. The biggest time loss came from building extensively before catching a platform-level deployment incompatibility.

What's next for Post-Pilot

  • Multi-subreddit support — a single PostPilot installation managing rules across a network of related communities.
  • AI-assisted rule suggestions — using Reddit's content graph to automatically recommend regex patterns and blacklists based on a subreddit's historical mod activity.
  • Scheduled portal posts — automatically re-deploy and re-sticky the portal post on a cadence, keeping it always at the top.
  • Rich flair workflows — let users select from a flair menu inside the portal itself, with per-flair rule sets (e.g., different title requirements for [Discussion] vs [Question]).
  • Mod team notifications — ping a mod via Reddit notification when the enforcer fires, with a direct link to the removed post for review.

Built With

Share this project:

Updates