SubDNA — Living Moderation Memory
What Inspired This
I spend time on large subreddits. I've watched the same argument play out dozens of times in mod teams: a post gets removed, six months pass, a new mod approves something nearly identical, and suddenly you have a modmail thread where veteran mods are explaining a ruling that was already made, documented nowhere, remembered by no one.
The problem isn't bad mods. The problem is that Reddit moderation has no memory. Every decision lives in a mod's head or a Discord message that disappears. When that mod leaves, the institutional knowledge leaves with them.
I wanted to build the thing that should have existed for years: a system that captures every ruling, understands what it means semantically, and surfaces it the next time a similar situation appears.
How I Built It
The core technical challenge was precedent matching without exact text matching. A spam post disguised as a legal question uses completely different words than previous spam — but a human mod recognizes the pattern instantly. I needed SubDNA to do the same.
The solution is the content fingerprinting system. Every post generates
an 8-dimensional topic vector across clusters like legal, spam,
academic, selfpromo, combined with account age bucket, posting pattern
score, and flair signal. When a new post arrives, the Precedent Search Agent
computes cosine similarity between its fingerprint and every stored
decision. A spam post disguised as a question matches past spam fingerprints
even when every word is different.
The full architecture:
7 Agents:
RouterAgent— dispatches every event to the right agentFingerprintAgent— generates the 8-dim semantic fingerprintPrecedentSearchAgent— cosine similarity search across stored decisionsDecisionCaptureAgent— captures mod actions with reasoning automaticallyConflictDetectorAgent— fires when a ruling contradicts past precedentSuggestionAgent— weighted voting across top-K precedentsSummaryAgent— weekly health score and documentation gap analysis
5-Layer Pipeline: Ingest → Fingerprint → Precedent Lookup → Decision → Store
Built entirely in TypeScript on Devvit's webview template, with a Hono server handling menu item endpoints, Redis for persistent storage, and Jest + ts-jest for testing.
What I Learned
Devvit's webview template is a different animal. Coming in expecting
the standard Devvit.addMenuItem() pattern, I spent significant time
debugging why menu items weren't registering — until I found that this
template routes everything through Hono, with menu items declared in
devvit.json and handled as HTTP POST endpoints. Once that clicked,
the whole architecture fell into place.
Test-first is the only way to build agents. Each agent is a pure function with no side effects — this made testing trivial and debugging fast. I wrote the tests before wiring the pipeline, which meant every integration bug was immediately isolated to the connection layer, not the logic layer.
Semantic fingerprinting is more nuanced than it looks. The first version of the similarity function returned 0.67 for identical fingerprints — because the scoring formula penalized absence of flair and spam signals even when both inputs had none. The fix (short-circuit on identical hashes) took 30 seconds. Finding the bug took two hours.
Challenges
Getting to 50 tests. The submission I was benchmarking against (LORE, the top scorer in a previous hackathon) cited "43 tests" in its first sentence. I wanted to beat that number legitimately — not by writing trivial tests, but by actually covering every agent and every pipeline layer. Ending at exactly 50, all green, felt earned.
The permission error on day one. The very first command —
npm install -g devvit — failed with EACCES: permission denied.
Not the most inspiring start. Fixed with sudo, moved on. These things
happen.
Keeping the fingerprint honest. It would have been easy to overfit the similarity scoring to the test cases. I had to keep asking: would this actually catch a real spam post disguised differently? The answer shaped every weight in the cosine similarity formula.
The Number That Matters
Test Suites: 7 passed, 7 total Tests: 50 passed, 50 total
That's the line that separates a demo from a system. SubDNA is a system.
What's Next
The current in-memory storage is the foundation. The production path is
wiring SubDNAMemory to Devvit Redis — the interface is identical, the
swap is one constructor argument. From there: cross-subreddit precedent
sharing for mod networks, natural language reasoning capture via a form
at removal time, and automated weekly digest posts to the mod team.
Mod decisions get lost. SubDNA gives your subreddit memory.
Built With
- devvit
- hono
- jest
- react
- reddit-developer-platform
- redis
- ts-jest
- typescript
- vite
Log in or sign up for Devpost to join the conversation.