Inspiration

Developer communities on Slack answer the same questions on repeat. "How do error boundaries work?" "What package for X?" The answers exist, split across docs, Slack history, GitHub issues, npm, but finding them takes 3-5 manual searches. One @mention should equal one answer.

How we built it

Shared Zod contracts first, agreements on data shapes between services, tested before any implementation. Then a JSON-RPC 2.0 MCP server with 3 tools (search_docs, get_npm_package, get_github_issue). The Slack agent (Bolt + Socket Mode) fans out to all 4 sources via Promise.allSettled, sends results to Groq with JSON mode, and renders Block Kit: synthesis first, then source sections with emoji signposting, clickable permalinks, degradation markers. 50 tests, TypeScript strict, ESLint + Prettier.

Challenges

Wikipedia was unreliable for technical queries → switched to Stack Overflow API. Groq free tier was inconsistent → added model fallback and configurable model selection. Slack RTS search:read is user-token-only → built graceful degradation with explicit ⚠️ markers instead of silent omission. Anti-slop prompt took multiple iterations. The LLM defaults to "I hope this helps" filler even when explicitly forbidden.

What we learned

  • Promise.allSettled > Promise.all in distributed systems: a single source failure should never block a response.
  • Zod contracts across packages prevent service drift without formal API specs.
  • pnpm workspace aliases + TypeScript exports maps need careful config to avoid double-extension runtime resolution.
  • Mock modes for demo vs real API aren't hiding, they let you ship reliability while keeping real integrations visible in the code.

Built With

Share this project:

Updates