An email brief agent built on iGPT, with a runnable demo app and a reusable LangGraph base class for building your own iGPT-backed agents.
This repo contains two pieces:
src/- a reusable LangGraph agent library.IGPTAgentis the base class; it handles credential validation, datasource planning, and OAuth so subclasses only define the agent-specific work.IGPTBriefAgentis the reference subclass - a chief-of-staff style brief over the user's inbox with priorities, deadlines, statuses, and next steps. About 40 lines on top of the base.app/- a runnable demo. FastAPI backend, React frontend, SQLite for multi-user auth, all wired through Docker Compose. A user signs up, asks a question, the demo plans which datasource to query, runs OAuth if needed, and streams a structured brief back. A side panel surfaces every iGPT SDK call as it happens, with method, snippet, purpose, and result.
The point of the demo is not the brief - it's that the brief is built on three iGPT SDK calls (datasources.list, connectors.authorize, recall.ask) and a JSON output schema. The rest is orchestration.
- Docker and Docker Compose
- An iGPT API key - get one at https://igpt.ai/hub/playground
- An OpenAI API key - used for query planning, intent routing, and the topical guard
git clone <your-repo-url>
cd brief-agent
cp .env.example .envFill in .env:
IGPT_API_KEY=your_igpt_api_key
OPENAI_API_KEY=your_openai_api_key
OPENAI_MODEL=gpt-4o-minidocker compose up app -dOpen http://localhost:8080, sign up, and ask the agent something like "What's the most important thing in my inbox right now?"
On first run the agent will return an OAuth URL to connect your email through iGPT. Connect, wait a moment for iGPT to sync, then ask again.
Auth state lives in app_data/app.db (SQLite, gitignored). Inspect it with sqlite3 app_data/app.db.
# Backend changes
docker compose build app && docker compose up app -d
# Frontend changes
cd app/web && npm run build && cd ../..
docker compose build app && docker compose up app -dEach user query passes through three layers before producing output:
┌─────────┐ ┌──────────┐ ┌────────┐
query → │ guard │ ───► │ router │ ───► │ agent │ ──► SSE stream
└─────────┘ └──────────┘ └────────┘
topical scope intent + msg LangGraph subgraph
(fail-open) (live registry) (extends IGPTAgent)
- Guard - an LLM check that the query fits one of the currently registered agents (or is a datasource connection request for one of them) and isn't out-of-scope (general knowledge, role-play, etc.). Pulls the agent menu from the live registry, so registering a new agent updates the guard's understanding with no prompt edits. Fail-open by design.
- Router - an LLM that picks one agent from the live registry and writes the user-facing status message. Adding a new agent extends the menu without router changes.
- Agent - the matched
BaseAgentruns its LangGraph subgraph and yields server-sent events to the frontend.
The base class encodes everything an iGPT-backed agent needs to do before its own work:
START → validate_config → plan_datasource → ensure_datasource → execute → END
(base class) (LLM picks) (OAuth if needed) (subclass)
Each node may short-circuit with a structured status (needs_api_key, needs_connection, error, success). Agents never block or interrupt - they return state.
Subclasses override one method:
class MyAgent(IGPTAgent):
def _node_execute(self, state):
client = self._igpt_client(state["igpt_api_user"])
resp = client.recall.ask(
user=state["igpt_api_user"],
input="...",
output_format=MY_SCHEMA,
)
state["status"] = "success"
state["data"] = resp.get("output")
return state- Create
src/<your_agent>/withagent.py,prompts.py,schema.py. - Subclass
IGPTAgentand override_node_execute. - Wrap each iGPT SDK call with a
dispatch_custom_event("agent:sdk_call", ...)calling/done pair so the side panel populates. - Implement a
BaseAgentwrapper for the demo backend (seeapp/server/agents/igpt_brief.pyfor the pattern). - Register it. The intent router picks it up from the live registry - no UI changes needed.
Detailed checklist in CLAUDE.md.
.
├── src/ # Reusable agent library - import into your own product
│ ├── igpt_agent.py # IGPTAgent base (validate → plan → ensure → execute)
│ ├── models.py # Pydantic models (DatasourcePlan, AgentInput, AgentOutput)
│ ├── prompts.py # Generic recall prompt
│ └── brief/ # IGPTBriefAgent - reference subclass
│ ├── agent.py
│ ├── prompts.py
│ └── schema.py
│
├── app/ # Demo web app
│ ├── server/ # FastAPI: SSE endpoint, auth, guard, router, agent registry
│ └── web/ # React + Vite + Tailwind frontend
│
├── docker-compose.yml # app service (one container)
├── .env.example # Required and optional environment variables
└── CLAUDE.md # Architecture deep-dive for AI assistants
- Backend - FastAPI, LangGraph, LangChain, iGPT Python SDK, SQLite, server-sent events
- Frontend - React 19, Vite, Tailwind CSS, React Router, React Query, Zustand, Zod
- Infra - Docker Compose
- iGPT Playground - interactive query console, get an API key
- iGPT Python SDK -
pip install igptai - iGPT Node.js SDK -
npm install igptai - iGPT API Documentation
MIT - see LICENSE. Copyright SpikeApp Inc.