Skip to main content
Glama
README.md
# Lore — the org-memory agent for Slack

> "What did we decide about pricing?" · "Who owns the hospital pilot?" · "When did we flip the go-live date?"
> Every team has these questions. Nobody has a fast, sourced answer.

Lore is a Slack agent that captures decisions, commitments, and facts **as they happen** — then answers questions about them with **provenance**: every answer links the exact Slack messages (and the GitHub PR, Jira issue, or Notion doc) where the fact was established.

Built for the [Slack Agent Builder Challenge 2026](https://slackhack.devpost.com) · **New Slack Agent track** · Apache-2.0

---

## Qualifying technologies

| Slack Agent Builder Challenge tech | How Lore uses it | File |
|---|---|---|
| **Slack AI / Assistant API** | `assistant_thread_started` + `assistant_thread_context_changed` events; Assistant-thread surface for contextual Q&A; AI digests power the research synthesis pass | `src/lore/slackio/events.py` |
| **MCP server integration** | Lore *is* an MCP server (`org_memory_search`, `org_memory_remember`, `org_memory_forget`) AND an MCP client (per-tenant CRM/Jira/Linear/GitHub integrations) | `src/lore/mcpio/server.py`, `src/lore/mcpio/client.py`, `src/lore/integrations.py` |
| **Real-Time Search API** | `assistant.search.context` called at answer-time to inject fresh Slack context in assistant threads (gracefully skipped on channel `@mentions`, where the action token doesn't apply); used in the 5-phase research pipeline's public-search stage | `src/lore/runner.py`, `src/lore/rts.py` |

All three technologies are active simultaneously on every question.

---

## How it works

```
Slack event ──▶ durable intake          Redis-stream exactly-once admission;
                                        survives restarts, deduplicates retries
            ──▶ armor scan              PII + credential regex screen before
                                        any LLM call; blocks prompt injection
            ──▶ intent classification   simple / research / complex /
                                        high_consequence routing
            ──▶ fact extraction         decision? commitment? owner? date?
                                        attributed to the Slack user who said it
            ──▶ memory store            hybrid vector (Qdrant) + keyword (Postgres)
                                        reinforcement/decay: confirmed = stronger,
                                        untouched = fades, corrected = superseded
            ──▶ retrieval (at ask-time) 3-tier grounding: context → history → RAG
                                        + Real-Time Search API freshness layer
            ──▶ answer + provenance     Block Kit card, source permalinks,
                                        Confirm / Correct / Forget buttons
            ──▶ (if high_consequence)   Approval gate: asyncio.Future bridge,
                                        Block Kit card, 5-minute timeout
```

Questions route to one of four dispatch paths — `simple` (direct retrieval), `research` (5-phase pipeline), `complex` (multi-agent router/council/auto team), `high_consequence` (council deliberation + human approval). An admin console (React/TypeScript, `src/console/`) exposes memory, conflicts, runs, agents, teams, integrations, and routing over `/api/v1` + SSE.

---

## Repository structure

```
src/lore/
├── main.py             entry point: wires all deps, starts Socket Mode + worker
├── config.py            all env-var config (dataclass, validated at startup)
├── runner.py            orchestrator: intent → dispatch → retrieval → answer
├── intake.py            durable Redis-stream admission (exactly-once)
├── store.py             memory CRUD: Postgres (facts) + Qdrant (vectors)
├── mcpio/client.py      MCP client: MCPResolver, stdio/http/sse, per-query construction
├── mcpio/server.py      MCP server: org_memory_search/remember/forget over stdio/http/sse
├── integrations.py      per-tenant MCP integration store + builder
├── rts.py               Real-Time Search API wrapper (assistant.search.context)
├── api.py               aiohttp REST API + SSE + CSRF guard
├── agent/                ReAct tool loop: tools, provider, FakeToolProvider
├── approval/             approval gateway: Future bridge + Block Kit + Bolt actions
├── slackio/              Bolt event/action/shortcut handlers, Block Kit builders
├── teams/                router/council/auto team modes + harness
└── db.py                asyncpg pool + schema (CREATE TABLE IF NOT EXISTS)

src/console/src/         React 18 / TypeScript / Vite SPA
├── api/client.ts         typed API client, CSRF cookie, error handling
├── pages/                admin screens: Memory, Conflicts, Runs, Agents, Teams…
└── nav.ts                navigation manifest (path, label, icon, crumb)

scripts/                  operational scripts (seed data, memory curator, dev console)
agents/                   default agent persona (SOUL.md + lore.yaml)
```

---

## Run it

Requires Python 3.12+, Node 18+, and Redis + PostgreSQL + Qdrant running locally.

```bash
git clone <repo>
cd lore
bash scripts/dev-setup.sh          # creates DBs, venv, installs deps
cp .env.example .env               # fill in Slack tokens
. .venv/bin/activate
lore db-init                       # idempotent schema
lore run                           # Socket Mode listener + worker
# Console: http://127.0.0.1:8096/console
```

Create the Slack app from `slack-app-manifest.yml` (Socket Mode), install to workspace, and set in `.env`:

```env
LORE_SLACK_BOT_TOKEN=xoxb-…
LORE_SLACK_APP_TOKEN=xapp-…
LORE_MODEL_PROVIDER=openai_compat        # or: anthropic | fake
LORE_OPENAI_BASE_URL=http://127.0.0.1:8000/v1
LORE_OPENAI_API_KEY=…
# Capability flags (intent routing, RTS, vision, web search, digest, passive
# capture) are ON by default; each stays inert until its endpoint/channels are
# set. Add LORE_EMBEDDINGS_BASE_URL / LORE_VISION_BASE_URL etc. to light them up.
```

Expose org memory to Claude Desktop / Cursor:

```bash
lore mcp        # MCP server (stdio default; --transport http|sse): org_memory_search / remember / forget
```

---

## License

Apache-2.0 — see [LICENSE](LICENSE).