Inspiration

I'm a computer science student and a gamer, and I basically live in Discord. Every day it's the same: I close it for one evening, come back, and there are hundreds of messages waiting. Nobody reads that. So people scroll a bit, give up, and ask something that got answered an hour ago. Then somebody has to answer it again. In a busy server that somebody is usually a mod, typing the same answer for the fifth time that week.

What it does

Previously On treats your server like a TV show.

  • /previously gives you a private recap of what you missed since you last spoke in that channel, like the "previously on" bit at the start of an episode. 4 to 6 short narrator lines, and every line has a Jump to this message link to the real message.
  • Reruns. When someone asks a question the channel already answered, the bot calls it a rerun and replies with a link to the answer and how many times it's been asked. A new question gets nothing. If the bot isn't sure, it stays quiet, because a wrong rerun is worse than no rerun. It never pings anyone, and nobody gets rerun twice in 10 minutes.

It never makes things up. The AI has to say which message every line came from, and plain code throws away anything that doesn't point at a real message.

How I built it

I built it for this hackathon with the Devpost Learn skills, starting from an empty folder on 9 October. I planned before writing any code: scope.md (the kernel: the server is a TV show and every line links to a real message), prd.md (the main flow, the look, edge cases like a quiet channel or missing permissions) and spec.md (stack, components, costs, and my one real unknown: how do you tell two questions are the same when they're worded completely differently and a keyword search would miss it).

Then I built it in four small slices, each verified and committed before the next: a grounded recap of sample chat first (before touching Discord), then /previously in Discord, then reruns, then the edge cases.

  • Node 22 and discord.js 14. The bot reads channel history on demand, nothing is stored.
  • Claude Opus 5.5 writes the recap as structured JSON where every line names a message id.
  • Claude Haiku 5.5 judges whether a question is a repeat.
  • src/grounding.js checks every id against the real messages and drops anything that doesn't match.
  • Prompt caching on both calls, so it's cheap enough to leave on: a recap costs about $0.057 the first time and about $0.009 when repeated, and a rerun check is about $0.0001 once cached. Measured with real calls.

Challenges I ran into

  • The first time I tested /previously it said "Quiet episode. Nothing aired since you left." Because I'd been chatting in the channel after the sample messages. It was right, I was wrong.
  • I had three copies of the bot running at once, all fighting over the same command, which gave me "Unknown interaction" errors. Now I check there's only one.
  • The sample chat had the same filler questions so many times that they pushed the real question out of the bot's memory. Identical questions now get grouped.
  • During recording, a rerun didn't fire. The bot had matched the question, but the AI pointed at the new question itself as "the answer", and my grounding check correctly threw it out. My tests used a fake id so they never caught it. Fixed by never showing the AI the new question's id, and the test now uses real Discord style ids.
  • My first recap links were little arrows. Nobody knew what they were. They're "Jump to this message" now.

Accomplishments that I'm proud of

  • Every recap line in every test pointed at a real message. Lines that can't be tied to one get dropped, not shown.
  • The rerun check gets 7 out of 7 sample questions right, including the ones that should stay quiet.
  • 13 unit tests, running on GitHub Actions on every push.
  • It's cheap. Caching cut a repeat recap from about six cents to under one.

What I learned

Don't trust a summary, make it cite. Ask the model for an id with every claim, then check the id in code and show the link. It works for anything where an AI summarises data you hold. And planning first with the Devpost Learn skills meant the weird bugs showed up in a small slice, not at the end.

What's next

  • Telegram. Its bots can't read old messages, so it needs a different approach.
  • A recap of the whole server in one go.
  • Mods marking the official answer to a question.
  • A trailer voice reading the recap out loud, because obviously.

Built with

Node.js, discord.js, Claude Opus 5.5 and Claude Haiku 5.5 (Anthropic), zod, dotenv. Planned and built with the Devpost Learn skill pack. Claude Code was the coding tool. The chat in the demo is made up sample data in a private test channel.

Built With

Share this project:

Updates

Submission history