Inspiration

If you've ever moderated a subreddit with any real traffic, you know the feeling. You open the mod queue, see 40 reported posts, and start clicking through them one by one. For every single item, you open the post in a new tab, read it, check which rule it might break, look up the user's history in another tab, decide what to do, write a removal message, add a mod note, and move on. That's 4-5 tabs and about 2-3 minutes per item. Multiply that by 40, and you've just burned two hours of your evening on unpaid work.

Now here's the worst part — while you were reviewing post #7, two other mods on your team were also reviewing post #7. Meanwhile, 37 other posts sat untouched. Nobody knows who's working on what. There's no coordination. It's just a flat list and a prayer.

We posted about this in r/ModSupport and r/modhelp while building Vigil, and the responses hit hard. u/MangoBbyyy said "not gonna lie the coordination lock thing alone would heal at least 40% of mod team beef. every subreddit with active reports has had that moment where 3 mods handle the same post while another 200 sit untouched." u/leveupchlce called it "unpaid group project chaos." These weren't hypotheticals — these were moderators describing their daily reality.

The timing felt right, too. Reddit just announced its $1M App Migration Program, pushing developers to move their bots onto Devvit. But in the comments, experienced developers like u/emily_in_boots and u/Watchful1 listed all the reasons they can't migrate — Redis-only storage, 512px height limits, no cross-sub communication. We looked at that list and thought: okay, but what if we stop trying to port old bot architectures and instead build something designed for these constraints? What would a mod tool look like if it was born on Devvit?

That's where Vigil started.

What it does

Vigil is a moderation command center that lives directly inside your subreddit feed as a custom post. No external servers, no browser extensions, no bot accounts — just pin it and your entire mod team has access.

Here's what happens when a moderator opens it:

The Queue shows every reported post and comment, automatically pulled in via Devvit triggers. Each item is pre-tagged with which subreddit rule it likely violates and a confidence score. Spam reports show up as "Rule 1: No Spam — 83%" so you know what you're looking at before you even click. Items are sorted by priority: escalated stuff first, then by report count, then oldest.

The Context Hub is the part that saves the most time. Click any queue item and the right panel shows you everything — the full post content, all report reasons, the triage classification, and the user's complete moderation history. No new tabs. No context switching. You read, decide, and act in one place.

Coordination Locks are the feature that gets people excited. When you click a queue item, every other moderator on the team instantly sees "🔒 Locked by u/yourname" on that item, with an Override button for emergencies. A heartbeat keeps the lock alive while you're reviewing. If you walk away or close your tab, the lock auto-expires after 90 seconds. This is the thing that's impossible with PRAW bots (no shared state), impossible with browser extensions (no Reddit-native UI), and impossible with AutoModerator (no interactivity).

Action Packs let you configure one-click enforcement per rule. Set it up once — removal reason, user notification message (with variables like {{username}} and {{post_title}}), post flair, mod log note — and every future removal for that rule is a single button press instead of a 5-step manual process.

Escalation lets junior mods flag borderline content for senior review with a note, instead of making a premature call. Escalated items jump to the top of the queue.

Insights tracks your team's KPIs — items reviewed, approval rate, removals, and a queue velocity metric that tells you if your queue is growing faster than you're clearing it.

And everything starts in Dry-Run Mode by default. All actions are simulated — stats update, history records, but zero live Reddit API calls are made. So new installs can't accidentally nuke real content.

How we built it

The whole thing is one TypeScript file. 2,707 lines, zero external dependencies, running entirely on Reddit's infrastructure. No external APIs, no webhooks, no servers to maintain.

Why one file? Because Devvit bundles everything into a single serverless worker anyway. Splitting into modules gives you no runtime benefit below ~3K lines, and it adds complexity for contributors trying to understand the app. Everything is organized into clearly labeled sections — config, models, services, triggers, forms, UI — with a table of contents in the file header.

Why Devvit-native instead of porting a bot? We read the Migration Program thread. Top developers described at length why they can't port their PRAW bots — they need Postgres, they need cross-sub communication, they need persistent processes. We decided to take the opposite approach. Instead of fighting the platform, we designed around it. Devvit gives you Redis, triggers, and custom posts? Great — we'll build the entire app on exactly those three things. The result is something that installs with one click and works for the whole team immediately. No server setup, no API keys, no per-moderator configuration.

Redis as the backbone. Since Devvit apps run as short-lived serverless functions (no persistent process), all shared state lives in Redis across 8 key namespaces — the queue, coordination locks, action pack templates, user moderation histories, aggregate stats, queue velocity events, and temporary form context bridges. Every Redis operation is wrapped in fault-tolerant helpers (safeRedisGet, safeRedisSet, safeRedisDel) that catch errors and return graceful defaults, so the dashboard never crashes from a transient storage hiccup.

Lazy lock garbage collection. This was a fun problem. What happens when a moderator acquires a lock and then just... closes their browser? You can't have a background cleanup job in serverless. Our solution: locks have a TTL, and expired locks are swept during the next queue read. A 20-second useInterval heartbeat extends the TTL while you're actively reviewing. If the heartbeat stops, the lock dies on its own. No deadlocks, no orphaned locks, no cleanup worker.

The triage engine is a zero-dependency keyword classifier. It parses your subreddit rules, tokenizes them (filtering 100+ English stop words), and matches against reported content using \b word-boundary regex so "spam" doesn't match "spasm." Title matches get 2x weight, body matches get 1x. Confidence is calculated as: min(98%, 35% + 12% × Σ(weight × matches)). It returns both a primary and secondary rule match, so mods can quickly spot content that straddles multiple rules.

Access control is checked on every render. We call context.reddit.getModerators() and if you're not a mod, you see a locked "Access Denied" screen. No moderation data is ever exposed to non-moderators.

Challenges we ran into

The 512px wall. Custom posts in Blocks are capped at 512 pixels tall. No scrolling. We needed to fit a queue list, a context panel, action buttons, user history, and analytics cards in that space. The solution was a tab-based layout with extreme information density — every pixel had to earn its place. On narrow screens, we stack panels vertically; on wide screens, they sit side-by-side. It's not luxurious, but it works, and we're genuinely proud of how much we packed in.

Devvit doesn't like undefined. In normal React, you can write {condition && <Component />}. In Devvit Blocks, undefined as a JSX child crashes the renderer. We had to audit all 2,700+ lines and convert every conditional render to strict ternary: {condition ? <Component /> : null}. Every. Single. One.

State types fight you. Devvit's useState only accepts JSONValue, which doesn't play nice with complex TypeScript interfaces. We wrote a useTypedState<T> helper that casts through unknown to preserve type safety at the call site while satisfying Devvit's runtime serialization.

Forms can't see state. Devvit's useForm hooks are defined at the module level, but the form submission handler needs to know which queue item you're escalating or which rule you're configuring. There's no closure over runtime state. We solved this with Redis as a context bridge — when you open a form, we write the current context to a temporary Redis key, and the form handler reads it back on submit.

Deleted content breaks everything. A post can be deleted between when it's reported and when a mod clicks "Remove." We built error detection for NOT_FOUND, 404, DELETED, THREAD_LOCKED, RATELIMIT, and FORBIDDEN responses, each with a specific user-facing message so the moderator knows exactly what happened.

Accomplishments that we're proud of

It's actually finished. 2,707 lines of production code with no TODOs, no FIXMEs, no placeholder UI, and no "coming soon" labels. Every Redis call has an error boundary. Every API call has a fallback. We shipped a complete product, not a prototype.

The coordination lock actually works. Open two browser windows. Click an item in one. The other shows "🔒 Locked by u/you" in real-time. This sounds simple but it's a distributed lock system running on platform Redis with heartbeat-based TTL extension in a serverless environment. Developers in the Migration Program thread said cross-mod coordination was impossible on Devvit. We built it.

Real moderators validated it. We didn't just build this in a vacuum. We posted in r/ModSupport (872 views, 10 comments), r/modhelp, and r/Devvit. u/ILOVEEEEPIZZA volunteered as a beta tester and joined r/vigil_engine_dev. The feedback was specific and enthusiastic:

"not gonna lie the coordination lock thing alone would heal at least 40% of mod team beef. every subreddit with active reports has had that moment where 3 mods handle the same post while another 200 sit untouched"u/MangoBbyyy

"honestly the coordination lock feature alone sounds like it could prevent half the passive aggressive mod team moments on this site... lowkey impressed somebody finally tried to make moderation feel less like unpaid group project chaos"u/leveupchlce

5.75x faster than native tools. In testing with 40+ realistic items, we hit ~2.3 items/minute versus ~0.4 with the native mod queue. That's about 53 minutes saved per 20-item session. The auto-advance flow (next item loads automatically after you action one) is a bigger deal than we expected.

It's published and live. Vigil v0.0.16 is published to the Reddit App Directory and testable at r/vigil_engine_dev. This isn't a demo repo — it's a real app you can install today.

What we learned

The biggest lesson was about designing for constraints instead of fighting them. We spent the first day frustrated by the 512px height limit and the lack of scrolling. By the second day, we realized the constraint was actually making us build a better interface — denser, faster, no wasted space. We wouldn't have built the tabbed layout or the auto-advance flow if we'd had unlimited pixels to play with.

We learned that concurrency in serverless is a different animal. There's no persistent process, no WebSocket, no event loop. Every interaction is a fresh render cycle. Shared state has to flow through Redis, and locks have to be "soft" (TTL-based with override) rather than "hard" (mutex-style). A hard lock deadlocks when a mod walks away. A soft lock expires and self-heals. That insight changed our entire architecture.

And honestly? Reading the Migration Program thread changed our perspective on what we were building. The veteran Devvit developers are waiting for the platform to become more capable before they migrate. But we realized that building natively — accepting the constraints and designing around them — produces a fundamentally different kind of app. Vigil couldn't exist as a ported PRAW bot. It was designed for Devvit's strengths: shared Redis, event triggers, custom post rendering, and zero-config team installs.

What's next for Vigil

Devvit Web Migration. The Blocks framework is being deprecated on June 30, 2026. We're planning a full UI migration to Devvit Web (Vite + React in a webview), which will unlock real scrolling, richer data visualization, and a proper mobile experience. The great news is our Redis logic, trigger handlers, and Action Pack engine are completely modular — the UI is the only part that needs to change.

Gemini-Powered Triage. Our keyword matcher works, but it's dumb. It can't tell sarcasm from sincerity or satire from hate speech. We want to plug in the Gemini API via Firebase AI Logic to run semantic classification. Instead of "likely Rule 1," imagine "This post appears sarcastic rather than genuinely toxic — recommend Approve with monitoring."

Filter API Integration. Reddit admin u/pl00h confirmed a filter API is coming to Devvit. Once it's available, Vigil can intercept content before it goes live — shifting from reactive ("review after reports") to proactive ("catch before the community sees it"). That's the real endgame.

Automated Action Rules. Let moderators define thresholds: "if confidence > 90% for Rule 1, auto-remove." High-confidence items get handled automatically; edge cases get routed to human review. This turns Vigil into the middle layer between AutoModerator (fully automated, zero judgment) and manual review (fully human, zero automation).

Built With

Share this project:

Updates

posted an update

Community Response

Within hours of posting about Vigil in r/ModSupport, r/modhelp, and r/Devvit:

  • 7 unique community members engaged with the project
  • u/ILOVEEEEPIZZA volunteered as a beta tester and joined r/vigil_engine_dev
  • u/YellowAdventurous366 independently tested the app and offered to feature it in r/devvitstore
  • u/MangoBbyyy said the coordination lock "would heal at least 40% of mod team beef"
  • u/leveupchlce called it the first tool that "tried to make moderation feel less like unpaid group project chaos"

The app is published as v0.0.16 and testable live at r/vigil_engine_dev.

Log in or sign up for Devpost to join the conversation.

posted an update

u/ILOVEEEEPIZZA — Volunteered as a beta tester from r/ModSupport, joined r/vigil_engine_dev and tested coordination locks directly.

u/YellowAdventurous366 — Independently discovered Vigil, tested the app, offered to feature it in r/devvitstore, and joined r/vigil_engine_dev as a mod to interact with the dashboard. Provided organic community validation within hours of submission.

Log in or sign up for Devpost to join the conversation.