Inspiration
Moderating a large subreddit is death by a thousand tabs. To act on one bad post, a mod jumps between the modqueue, the user's history, the modlog, the rules wiki, AutoMod config, and modmail — and the moment they remove or ban something, the item vanishes and they lose their place.
On top of that, large image-heavy subs (r/gaming, r/movies, r/aww) drown in reposts and low-effort spam that exact-match filters and keyword AutoMod rules can't catch.
We wanted the "Cursor for mod work" — a copilot a mod can just talk to:
- "Find reposts from the last day."
- "Scan the last 48h for rule violations and remove the clear ones."
- "Write me an AutoMod rule for this spam domain."
It reads the subreddit, reasons, and acts — with the mod approving every change.
What it does
ModPilot is a chat-based moderation copilot embedded in Reddit as a Devvit web-view.
A mod opens it and gives natural-language instructions; the agent reads subreddit state and takes moderation actions on their behalf, with:
- A mandatory confirmation sentence on every mutation
- A per-action approval gate
- An optional opt-in auto mode
Under the hood, it's a Gemini function-calling agent with 29 tools across three classes:
Read — posts, users, comments, modlog, modqueue, modmail, mod notes, subreddit rules, and AutoMod config
Analyze — three AI capabilities:
- Repost detection:
- Every new post is fingerprinted into two independent 768-dim Gemini embeddings:
- One for title + body
- One for a Gemini Vision description of the image
- Each post is matched against a sliding window of recent posts
- Final score =
max(textSim, imageSim) - This catches:
- Copied images with fresh titles
- Copied text on new images
- Matches get:
- An auto-comment linking the original
- A report to the modqueue
- Rule-violation scanning:
- Pulls the subreddit's real rules
- Batch-judges recent posts (or the modqueue) against all rules in one Gemini JSON call
- Returns:
- Clear violations
- The cited rule
- Confidence
- Reasoning
- AutoModerator integration:
- Reads live AutoMod YAML
- Explains or audits existing rules
- Writes new rules
- Validates locally against the exact AutoMod schema before writing so invalid YAML never reaches Reddit
Mutate — remove/approve/lock posts, remove/approve comments, ban/unban users, add mod notes, reply to modmail, create subreddit rules, and write AutoMod config — all gated behind approval
How we built it
Devvit Web (
@devvit/web)- A Hono server on Node 22
- Bundled by Vite into the server bundle
- Vanilla-JS web-view chat client
- No client framework
- Polls a Redis-backed event stream
- Uses a typewriter animation so buffered responses feel like real streaming
Gemini
gemini-2.5-flashfor:- Chat
- Function calling
- Rule classification in JSON mode
gemini-embedding-2(768-dim) for repost fingerprints- Flash Vision for image descriptions
Redis (per-install)
- Sessions
- Chat event log
- Repost fingerprints and flags
- Not-a-repost whitelist
- Approval / interrupt state machine
Triggers + Scheduler
onPostCreatefingerprints posts- Scheduled jobs:
- Daily cleanup
- 30-minute resweep
- Stale-flag reconciliation
The agent loop
- Turn-based loop
- Hard runaway ceiling
- Cooperative stop button
- History compaction:
- Old tool payloads are stubbed to keep prompts small
- Reliability guards:
- No-op guard
- Malformed-call retry
- Don't-quit-on-failure guard
AutoMod schema validator
schema.tsparse.tsvalidate.ts- Ported from Reddit's open-source AutoModerator engine so writes are checked against the real grammar before hitting the wiki
Challenges we ran into
The opaque HTTP 415
- Invalid AutoMod syntax returned a bare HTTP 415 with no useful message
- We initially misdiagnosed it as a permissions issue
- Logs showed:
- Valid rules saved correctly
- Only malformed YAML failed
- Reddit validates AutoMod YAML server-side, but the real error gets lost in transport
- Fix:
- Port AutoMod's real schema locally
- Validate before writing
- Feed precise errors back into the agent loop for self-correction
Blended embeddings hid reposts
- A single combined vector buried both:
- Copied-image cases
- Copied-text cases
- Splitting into two independent vectors and scoring with
max(textSim, imageSim)fixed it
The agent gave up too easily
- One failed tool call often caused the model to apologize and terminate
- We added a bounded retry guard so it:
- Re-evaluates failures
- Tries corrected calls
- Still respects moderator rejection as final
Devvit web-view constraints
confirm()is blocked inside sandboxed iframes- Our first delete-confirmation silently no-op'd
- Playtest posts are tied to builds and disappear between sessions
- Both caused major debugging detours before we understood platform constraints
Faking token streaming
- Devvit fetch responses are buffered
- The client polls instead of using SSE
- We moved the streaming illusion client-side using a
requestAnimationFrametypewriter effect
Accomplishments that we're proud of
A genuinely agentic moderation tool:
- One chat box
- 29 tools
- Read-before-write enforced
- Every mutation gated by a human-readable confirmation
Multimodal repost detection that survives:
- Crops
- Caption rewrites
- Text swaps
A faithful AutoMod validator built from Reddit's own engine
- ModPilot can write AutoMod rules and verify correctness before Reddit ever sees them
A resilient agent loop with:
- Stop button
- Turn ceiling
- History compaction
- Three behavioral guards:
- No-op guard
- Malformed-call guard
- Don't-quit-on-failure guard
A polished moderation UI with:
- Session history
- Manual and auto approval modes
- Load skeletons
- Dependency-free client JS
What we learned
Validate before you call
- The 415 saga taught us to model external API rules locally so the agent can fail fast with useful errors instead of guessing against opaque server failures
Agent reliability is mostly guardrails
- The model was already capable
- The biggest wins came from loop design:
- When to retry
- When to stop
- When to nudge
- When to escalate
Read platform constraints early
- Sandboxed iframe behavior and ephemeral playtest posts cost real debugging time because we assumed normal web defaults
Separate signals beat one blended signal
- Independence plus a max-score strategy dramatically improved repost detection quality
What's next for ModPilot
A full AutoMod simulator
- Beyond schema validation, proposed rules will run against real sample posts to show exactly what they would catch and miss before deployment
Comment-aware rule scanning
- Extend moderation analysis to comment threads, not just posts
Smarter behavioral moderation
- Exclude the app's own posts from repost detection
- Add ban-evasion and alt-account detection to replace deprecated third-party autoban tools
Natural-language workflows
- Mods define recurring automations like:
- "Every morning, triage the modqueue and summarize"
- Scheduled and executed unattended
A learning loop
- When moderators override ModPilot, the system remembers it
- Suggestions adapt over time to each subreddit's moderation norms
Built With
- automoderator-schema-(ported-from-reddit-archive/reddit)
- cosine-similarity
- css
- devvit-(@devvit/web)
- devvit-redis
- devvit-scheduler
- devvit-settings/secrets
- devvit-triggers
- devvit-web
- eslint
- esm
- gemini-2.5-flash
- gemini-embedding-2-(768-dim-embeddings)
- gemini-function-calling
- gemini-json/structured-output-mode
- gemini-vision
- git
- google-gemini-api
- hono
- html
- http-fetch
- multimodal-ai
- node.js-22
- reddit-developer-platform
- rest/polling
- typescript
- vanilla-javascript
- vector-embeddings
- vite
- yaml
Log in or sign up for Devpost to join the conversation.