Skip to main content
The chat agent is a right-side panel on every organizer page: threads, streaming responses, @-mention any submission/speaker/session as context, clickable entity badges that navigate the app, and inline Approve/Deny confirmation before anything sensitive happens (emails, decisions, publishing, deletes).

One switch

The agent is dormant by default and activates only when a provider key exists: The frontend follows automatically via GET /api/agent/capabilities — there is no second flag.

Architecture

api/agent/service.py:run_turn owns the complete provider-neutral turn lifecycle: thread claims and persistence, history, prompts, runtime events, tool dispatch, permission cleanup, and the final reply. In-app Ask is an SSE adapter over that function. The Slack agent is an Events API adapter over the same function, so both transports use the same tools, MCP connectors, thread store, and permission gate; Slack approval requests arrive as Approve/Deny buttons and Slack threads appear in Ask history. The provider harness is shared — tool registry, event vocabulary, permission gate, thread persistence — with the model loop as the only swappable part. The full provider-swap notes (including what differs when running on Claude) live in the repo at docs/chat-agent.md.

MCP connectors

Organizations can attach external tool servers from Settings → Integrations: Every ships as the first preset, and any Streamable-HTTP MCP server can be added with OAuth (discovery + dynamic client registration + PKCE), a static bearer token, or no auth. External tools are namespaced mcp__<connector>__<tool> and every external mutation passes the same Approve/Deny gate. See MCP connectors.