DEV Community

Cover image for DevRel Has a Skim Problem
Tushar Pamnani
Tushar Pamnani

Posted on

DevRel Has a Skim Problem

Every DevRel engineer has said "I'll get to the Discord backlog this week."

The backlog isn't the problem. The skim is.

The Skim

Here's what the first forty minutes of a DevRel morning actually look like, if you're honest about it.

Open Discord. Scroll past the "gm" messages. Open GitHub issues, sorted by newest, because that's the only sort that exists. Open the PR queue. Open notifications across three repos and two orgs. Squint at a hundred messages to find the three that matter.

Each pass through that pile is the same three questions, asked silently, a hundred times:

  • Is this a setup bug, or one developer having a bad morning?
  • Have I already seen this exact question four times today, in four different channels?
  • Does this need me right now, or would replying just add noise to a thread that's already resolving itself?

The first two questions are pattern matching. Any reasonably attentive person gets good at them after a few weeks. The third one is judgment, and it's the actual job - it's the reason a human is doing this instead of a keyword filter.

The skim is where the hours go. But the hours aren't even the worst part. The skim is where the failures happen: the blocked developer who asked once, got no answer, and quietly churned. The champion moment - someone shipping something real on your stack, unprompted - that nobody on the team ever saw, so nobody thanked them, so they never became an advocate. The same install bug, reported five times in five different channels by five different people, each one treated as a fresh mystery because nobody connected them.

None of that shows up in a report. It shows up six months later as "engagement is down" and nobody can point to why.

I don't think the fix is to skim faster. Faster skimming just means you miss things with more confidence. I think the fix is to stop skimming and start triaging - but that only works if the tooling is built for triage, and right now, it isn't.

Why Current Tools Miss It

I spent a while looking at what exists before I decided to build anything. Almost everything on the market falls into one of two shapes, and both of them make the skim worse in different ways.

The chatbot

It auto-replies to everything that looks like a question. On paper this sounds like relief. In practice it turns your community into a support desk with a friendly avatar, and it teaches every developer in your server that the fast response is a machine, not a person - which quietly devalues the moments when a human does show up.

But the surface problem - "it replies to things" - isn't the real problem. The real problem is what a reply-everything system can never do: it has no memory of the developer who's been stuck for three weeks, no visibility into the six other people asking the same question in the last hour, no sense of whether this deserves an answer, a doc fix, or an escalation to whoever owns that part of the SDK. It responds to everything because it was never built to decide what matters. It's just the skim, wearing a confident voice. Confidence isn't triage.

The dashboard

It counts messages, charts sentiment, graphs engagement over time and leaves the skim exactly where it was, except now it's illustrated. You get a beautiful chart of the problem and the same unopened backlog underneath it.

Dashboards give you activity. They don't give you priority. A +42% week-over-week message chart doesn't tell you that a single install failure is currently blocking seventeen newcomers from ever finishing onboarding. It doesn't tell you that a "small question" dropped in a side channel is the exact same question your biggest prospective enterprise customer has been quietly fighting for two days. Charts describe the noise. Separating noise from signal was supposed to be the product, and it got left out.

Neither shape answers the question a duty engineer actually needs answered every single morning: what needs me today, and why?

The category itself is thinner than it looks

This isn't a crowded market with a UX problem. It's an orphaned one. Orbit, one of the earlier players in developer-community analytics, was acquired by Postman and then shut down. Common Room, arguably the most credible attempt at this; was acquired by Zoom in mid-2026 and has since been repositioned around GTM and buyer intelligence rather than community health. The seat is genuinely empty right now.

What's rushing in to fill it is a wave of "agent promise" products; LLM-powered, MCP-connected, pitched as "your community, automated." But reading your channels with an LLM isn't the hard part anymore; every foundation model can summarize a Discord export. The hard part is still exactly the one the dashboards skipped: producing a decision about what matters, backed by evidence, that a human can actually trust and override in three seconds. Agentness, at this point, is table stakes. Triage is the differentiation, and almost nobody is building for it.

The Right Shape

I've been building against this problem for a while now, under the working name Community Engineer, an operating system for DevRel, not another inbox for it. A few rules have fallen out of that process, and I've come to treat them as non-negotiable:

  • Detect, don't respond. Every GitHub and Discord event gets normalized into one schema, then classified: friction, feedback, builder opportunity, community moment, or noise. Events get deduped by delivery id, because webhook retries will otherwise turn one real signal into two, and a system that double-counts is a system nobody trusts by week three.
  • Bias toward keeping. When the classifier genuinely can't tell what something is, it files the event at low severity instead of silently dropping it. A missed friction report is expensive. A low-priority row sitting unread is not.
  • Evidence before recommendation. Before the system suggests anything, it pulls the developer's history, related signals, and matching threads. Every recommendation has to point at something real.
  • Separate observed, inferred, and recommended. The system is never allowed to launder a guess into a fact. If it thinks something, it says it thinks it.
  • A human approves anything consequential. The output of this whole pipeline is a queue, not an autopilot.

That last point sounds obvious written down. It is, in practice, the single hardest discipline to hold onto once you have a working model that's clearly right most of the time. The temptation to let it just do the thing is constant. I've resisted it on purpose, for reasons I'll get to.

Under the hood: how the classification actually works

The detector runs against a fixed taxonomy. No free-floating "this seems interesting" flag — every event has to land in one of five buckets:

developer_friction     blocked, struggling, install failing
product_feedback       not blocked, but requesting or comparing
builder_opportunity    someone is building with you
community_opportunity  a moment worth engaging
positive_signal        a champion moment, tracked, not acted on
Enter fullscreen mode Exit fullscreen mode

Each classified event gets a severity (low → critical), a confidence score, a one-line plain-language summary a human can read in under two seconds, and a requiresAction flag that only flips to true when a person should actually put eyes on it. Not every friction report trips that flag, one that's already been answered in-thread by another community member doesn't need you twice. That flag is the entire "does this deserve your attention" decision, and it's the one place in the system I'm willing to let the model be liberal, because the cost of a false positive there (you glance at something unimportant) is nothing next to the cost of a false negative (something important goes unseen).

Evidence, not vibes

Before anything becomes a recommendation, the system pulls the developer's history, their prior interactions, related signals across the same time window, and the matching GitHub threads. Every recommendation has to cite what it saw. If the output says "eleven developers hit this install bug this week," there are eleven actual rows behind that number — not a plausible-sounding estimate.

And every claim the system makes is stamped with the level of certainty it's operating at: observed (this literally happened, here's the event), inferred (this is a pattern the model noticed across multiple observed events), or recommended (this is what the model thinks you should do about it). The model never gets to collapse an inference into a stated fact. This one rule turned out to matter more than any other design decision I made, it's the difference between a tool that helps you decide faster and a tool that quietly decides for you and hides its reasoning behind a friendly summary.

The planner, and where the line sits

The planner takes everything above and proposes a single action; file an issue, comment on the existing thread, raise a follow-up task, or mark the signal resolved - attached to a reason, the cited evidence, a target, and a risk rating (low / medium / high). Anything consequential waits for a human. Approve, edit, or reject. The model is explicitly told that every external tool it has access to is high-risk and only callable once a person has said yes.

What's Actually Live vs. What's Designed

I want to be precise here, because it's easy for a build-in-public post to blur "how it works" and "how it will work," and I'd rather you know exactly where the line sits today.

Shipped and running right now: ingestion from GitHub and Discord, the signal detector and classifier, severity/confidence scoring, and the full human-in-the-loop approve-and-execute flow. If you connected this to a real community today, the queue you'd see is real, and the actions you approve actually fire.

Built but not wired in yet: the context-investigation agent, the piece that goes and pulls a developer's history and related threads before a recommendation is made, exists in code, and so does the model-agnostic router (it sits on top of OpenRouter so the system isn't locked to one model provider), but neither is connected to the live routes yet. Today's recommendations are evidence-light compared to what I described above; the richer version is the near-term milestone, not a future-future one.

Barely there: the weekly digest currently prints to stdout. It's a debugging tool wearing a feature's name. It'll get a real surface before launch, but right now, if I told you it emails you a Monday summary, I'd be lying.

I'm putting this section in a build-in-public post on purpose. It's the least impressive paragraph in here, and it's the one I trust the most.

Where It's Still Broken

The loop, as it stands, ends at execute. Nothing yet tracks whether the action actually mattered. Was the filed issue closed? Did the developer who was blocked come back and finish onboarding? Right now, "resolved" means "I closed a row in a queue." It does not mean "it worked." Those are different claims, and I'm not willing to conflate them just because the second one sounds better in a launch post.

The next phase is outcome records and a reconciler; something that polls GitHub to check whether an issue is still open, watches for whether a developer actually replied, actually returned. This is the boring, unglamorous part of the build, and it's exactly the part that gets skipped in demos. A demo shows you the queue, shows you an action, and ends. Nobody goes back a week later, on camera, and checks whether anything actually changed. I'd rather ship this late with verification built in than ship it early and let "resolved" mean nothing.

There's a design question buried in here I'm still working through, and I don't have a clean answer yet: when an action doesn't produce a measurable outcome, what should the system do about it? Escalate back to a human? Quietly discount the recommendation pattern that led there? My current instinct is to surface it as a traceable miss rather than silently retry; a failed outcome is information about the quality of the recommendation that produced it, and burying that information to keep the dashboard looking clean is exactly the kind of shortcut this whole post is arguing against.

What I Won't Automate

I keep landing on the same sentence: deciding whether to act is the one thing I refuse to automate. The product isn't "responds to everything." The product is "never misses the thing that matters, and shows you why it thinks so."

An autopilot version of this is a community-management incident waiting to happen. Every friction report gets an instant reply, developers learn within a week that the fast response is a bot, and the team loses the one thing their community was never actually short on, signal. Triage is the product. The human in the loop is the product. Everything upstream of "approve" exists purely to make that one human decision faster and better-informed. If I ever ship a version where that stops being true, it's a worse product, not a more advanced one.

What's Next

I'm getting close to a launch. Between now and then, I'm posting the specific failures as I hit them, not the wins.

The dedupe bug I got wrong on webhook retries. The recommendation that looked completely reasonable and turned out to be wrong. The severity I over-ranked by a mile because I trusted a confidence score I hadn't actually validated. If this thing is ever going to be trusted with real triage decisions, the failure log has to be public before the dashboard is.

One question, since it's genuinely shaping what I build next: which channel do you skim every day that you wish you didn't have to? Reply with it. I'm collecting the answers, and they're going straight into what gets prioritized next.

X · GitHub

Top comments (0)