TeamTrail
An AI-assisted Slack onboarding tool
Built and submitted solo for the Slack Agent Builder Challenge 2026
What was the problem?
Starting at a new company means spending the first days hunting through Slack channels, direct messages, and docs for context, and nobody has time to hand-deliver all of it. A chatbot with a fixed knowledge base would be out of date almost immediately.
What did I make?
I built a helper that lives inside Slack. A new hire picks their role (engineer, PM, designer, or other), and it pulls together what the workspace is actually saying right now, with a link to every source. It remembers what it has already covered, so follow-up questions don’t repeat themselves. If the optional connection to Notion docs is down, it still answers from Slack instead of making something up.
Why is that useful?
New people get productive faster without pulling teammates away from their own work, and the source links let them check anything before trusting it.
What is still unproven?
It’s a hackathon build tested in a single Slack workspace, built to run as one always-on copy, not many at once. Its safeguards against the AI citing something it shouldn’t reduce that risk but don’t eliminate it.
The problem
- New team members ramping up in a Slack-heavy org spend their first days hunting for context scattered across channels, DMs, and docs, and nobody has time to hand-deliver it.
- A generic chatbot answering from a static knowledge base would go stale immediately; the answers needed to be grounded in what the workspace actually says, right now.
The approach
- Built as a native Slack "Agents & AI Apps" surface (a top-bar entry point with a dedicated split pane) rather than a slash command, since that’s the pattern Slack’s Assistant lifecycle is designed around.
- Role-based onboarding (Engineer, PM, Designer, Other), each mapped to a different set of search terms so the same pipeline surfaces relevant results for very different jobs.
- Every briefing and follow-up combines two live sources: Slack's Real-Time Search API (actual messages, files, users, and channels) and, optionally, a locally-run Notion MCP server for org docs, merged into one prompt to Groq's LLaMA 3.3 70B, with every claim backed by a clickable source citation.
- Stateful per-user context (role, topics already covered, questions already asked) so a follow-up question doesn’t make the bot repeat itself.
- Explicit fail-closed design: if the local Notion MCP server isn’t running or times out, briefings still work from Slack data alone instead of erroring or inventing an answer.
What broke (and how it got fixed)
- `app.use(assistant)` looked like the obvious way to register Slack’s `Assistant` class as Bolt middleware; it isn’t, and it crashed every incoming event with `middleware[toCallMiddlewareIndex] is not a function`. The framework’s actual entry point is `app.assistant(assistant)`, which converts it internally first.
- Replies sent via `say()` from inside a button-click handler didn’t reliably land in the live split-pane thread; they could post to the App Home History tab instead. Fixed by posting explicitly with `client.chat.postMessage`, targeting the thread’s channel and `thread_ts` directly.
- A naive `sources.slice(0, 5)` silently dropped Notion citations whenever Slack’s own message search returned five or more results first, even when Notion content was clearly used in the answer. The source formatter now reserves dedicated slots for Notion citations instead of truncating by array order.
Outcome
- Unit tests (`test_unit.js`, run with Node’s test runner) cover the pure logic pulled out of the bot (role matching, result formatting, citation labeling, rate limiting) and most of those cases are regressions of actual bugs found during manual testing, not generic filler coverage.
- Separate smoke-test scripts verify the Slack Real-Time Search integration and the Notion MCP tool names/response shapes directly against live APIs before trusting either in the bot.
- The README is explicit that its safeguards are mitigations, not guarantees: the prompt-injection guard and the "don’t invent a source" instruction both reduce, but don’t provably eliminate, the model citing something it shouldn’t.
Stack
- Slack surface
- Agents & AI Apps: top-bar entry point and split pane, not a slash command
- Slack framework
- Slack Bolt for JavaScript (Socket Mode)
- AI model
- Groq API: LLaMA 3.3 70B Versatile
- Workspace search
- Slack assistant.search.context (Real-Time Search API)
- Optional context
- A locally-run Notion MCP server, merged into the same prompt
Honest scope
A hackathon submission built and tested against a single Slack workspace, with per-user context persisted to a local JSON file rather than a database, solid for one always-running process, not yet built for multiple concurrent instances.
Have a technical problem, AI or otherwise, that needs a second pair of eyes?
Let's talk.