Inspiration

Every team already has the answer to "what did we decide about X?" — it's just scattered across a Slack thread, an email, a Google Doc, and a GitHub issue. Ask a normal AI assistant and it answers from the model's memory: it guesses, confidently, with no source. We wanted an agent that answers from the company's memory instead — and shows its receipts. And it had to live where the team already works: Slack.

What it does

Engram is a Slack agent that answers questions from your company's own memory across Slack, Gmail, Google Docs, and GitHub — every answer cited back to the exact source. It doesn't just retrieve, it acts: draft and send an email, file a GitHub issue, share or save an answer — each gated by a confirmation modal so nothing happens behind your back.

You talk to it two ways:

  • As a Slack Assistant (built on Slack's Assistant API) — open the assistant pane, get suggested prompts, ask in natural language.
  • Via the /engram slash command with 7 verbs: ask · recap · who · sources · issue · sync · help.

Ask "What did we decide about pricing for the v2 launch?" and it returns one answer stitched from a Google Doc and a Slack thread, each fact linked to its origin.

How we built it

  • Slack layer: a Socket Mode app using Slack's Assistant API (assistant_view + assistant:write, thread-started hooks, suggested prompts, live status) plus slash commands.
  • The brain: a cross-source knowledge graph. Content from 4 real OAuth connectors is ingested, embedded with BAAI/bge-large-en-v1.5, stored in Postgres (episodes/metadata) and Kuzu (the graph), and retrieved with a smart multi-step recall that assembles cited answers.
  • MCP: the agent reaches the Engram brain over MCP (a FastMCP server), so recall and actions are exposed as tools. Engram qualifies on both Slack AI and MCP.
  • Actions: real side effects — Gmail SMTP send, GitHub issue creation — behind confirm modals, with an optional allowlist so only approved users trigger writes.
  • Hosting: the entire brain runs self-hosted on a Raspberry Pi 5, always-on, with no inbound ports (Socket Mode is outbound-only). Your company's memory never leaves your infrastructure.

Challenges we ran into

  • The embedding model timed out on the first query. The ~1.3GB bge-large model downloaded lazily on first recall, blowing past our 20-second timeout so the very first question always errored. We baked the model into the Docker image at build time so it's ready the moment the container starts.
  • A UTF-16 database dump that wouldn't restore. Piping pg_dump > file.sql in PowerShell silently wrote UTF-16, which Postgres rejected on restore (invalid byte sequence for encoding "UTF8"). Fix: dump with -f inside the container and copy the raw bytes out.
  • Kuzu's single-writer lock. Re-syncing while the agent was running collided with Kuzu's single-writer constraint, so /engram sync re-ingests in-process instead of as a competing writer.
  • Keeping it live for judges on a Pi — boot-time DNS resolver crashes, connector-failure isolation so one dead source doesn't break recall, and an always-on restart policy.

Accomplishments that we're proud of

A complete, live product on real data — not a mock. Cross-source cited answers from four live connectors, real actions (a GitHub issue filed and an email actually sent), and the whole thing running privately on a Raspberry Pi with zero inbound ports.

What we learned

The hard part of a "company brain" isn't the LLM — it's ingestion, the graph, keeping every answer cited, and the unglamorous ops (timeouts, encodings, single-writer locks) that decide whether it's actually live when someone asks it a question.

What's next for Engram

More connectors (Notion, Linear, Confluence), a device-code OAuth flow so non-technical teammates can connect sources without a terminal, and richer agentic actions.

Built With

Share this project:

Updates