Inspiration

Every team makes decisions in Slack. And every team loses them. Three weeks later someone asks "wait, didn't we already pick a vendor for this?" and the answer is buried under two thousand messages, or worse, gone with the person who remembered it. Slack search finds messages, not decisions: you get 200 hits, not an answer.

The tools that exist to fix this all share one fatal flaw. They require a human to remember to log the decision, and nobody does. We wanted an agent that notices on its own.

What it does

Precedent is a decision-memory agent for Slack. It watches team channels, and when a conversation produces a real decision, it logs it automatically: what was decided, by whom, when, and which action items came out of it. No commands, no forms, no behavior change. People just talk, and the agent remembers.

  • 📌 Capture. About 90 seconds after a thread goes quiet, Precedent extracts the decision with Claude, pins the thread, and posts a one-line confirmation. Debates, deferrals ("let's revisit next week"), and chatter are correctly ignored.
  • 🔎 Answers with receipts. Ask "what did we decide about X?" in the assistant panel or by @mention. Answers combine the structured decision log with live workspace retrieval via the Real-Time Search API, and every answer carries a "View source thread ↗" button. You never take the agent's word for it.
  • ↩️ Supersession tracking. When a team reverses itself (SendGrid to Postmark), Precedent links the new decision to the old one and preserves the history. A timestamp invariant guarantees history can only flow forward, so reprocessing old threads can never rewrite it.
  • ☑️ Accountability loop. Action items get owners and due dates, and a weekday cron DMs open items with working Mark done ✅ / Snooze 💤 buttons.
  • 📊 Home dashboard. Active decisions, superseded history, and open action items at a glance.
  • 🔌 Agent-to-agent memory. The decision log is exposed as an MCP server, so Claude Desktop (or any MCP client) can query search_decisions, get_decision, and list_open_action_items against the live database.

How we built it

All three challenge technologies, used deeply, not just the one required:

  1. Slack AI capabilities. Bolt's Assistant class powers the panel: greeting with suggested prompts, live setStatus during retrieval, answers as Block Kit cards.
  2. Real-Time Search API. assistant.search.context with the ephemeral per-event action_token, include_bots, and a two-pass strategy: semantic search first, keyword fallback when results are thin.
  3. MCP server. A self-built stdio server that proxies a bearer-authenticated REST bridge on the deployed app.

Stack: Slack Bolt on Socket Mode, Claude (claude-sonnet-4-6) for extraction and answer synthesis, better-sqlite3 on a Railway volume, and an Express REST bridge in the same process. We store structured records plus permalinks, never message archives. Raw retrieval happens live through Slack's own search, respecting Slack's permissions.

Challenges we ran into

  • Docs vs. reality. The RTS action_token is documented as a top-level event field, but it actually arrives nested under event.assistant_thread. We found it by logging the raw event when the first live search failed.
  • Semantic search whiffs. "Email vendor" didn't match seeded messages saying "email provider." We fixed it with an automatic keyword fallback pass.
  • History integrity. Reprocessing an old thread could let the LLM claim it superseded a newer decision, inverting history. We fixed it with a hard store invariant: supersession only flows forward in time.
  • LLM discipline. Extraction is JSON-only with confidence thresholds and full shape normalization, so a malformed response can never poison the store.

What we learned

Retrieval is the easy part. Trust is the hard part. The single feature that changes how the tool feels is the source-thread link on every answer. The moment a user clicks it and lands on the real conversation, the agent stops being a chatbot and becomes a system of record. We also learned to build for the failure paths first: if live search is down, Precedent answers from its log and says so, rather than pretending.

What's next for Precedent

Reactions-as-corrections (❌ to unlog a false positive), per-channel opt-in policies, decision export, and richer MCP tools like decision timelines and owner workload, so other agents can reason over organizational memory. It's MIT-licensed and self-hostable in about ten minutes.

Built With

Share this project:

Updates