Multi-agent orchestration system inspired by Interaction Company's Poke assistant - handles email triage, reminders, and persistent task delegation via AI agents.
Stack: Turborepo + pnpm | Next.js 15 (React 19 + Turbopack) + FastAPI (Python) | Postgres + Drizzle | Custom agent framework + OpenRouter + Composio (Gmail)
Think of OpenPoke as your personal AI assistant that actually gets things done. Instead of just chatting, it:
- Triages your emails - Automatically identifies important messages and surfaces them
- Sets reminders - Creates persistent reminders that actually work
- Delegates tasks - Uses specialized agents to handle different types of work
- Learns your patterns - Adapts to how you actually work, not how you think you work
The magic happens through a two-tier agent system: an InteractionAgent that understands what you want, and an ExecutionAgent that actually does the work. No LangChain complexity, just custom-built orchestration that actually works.
Custom-built orchestration (no LangChain/LangGraph):
- InteractionAgent → Main orchestrator, handles user messages and decides what needs to be done
- ExecutionAgent → Task execution specialist (email, reminders, search)
- Direct OpenRouter API integration → Custom client for maximum control
- Composio for Gmail tools → OAuth and email operations
- Custom tool registry → Async batch execution with 8 tool iterations max, 90s timeout
Frontend (apps/app) - Next.js 15 with React 19 + Turbopack
- App Router with API routes
- tRPC for type-safe API calls
- TanStack Query for data fetching
- Better Auth for authentication
- Tailwind v4 for styling
Backend (apps/server) - FastAPI with Python 3.12+
- Custom agent implementations
- OpenRouter client for AI model access
- Postgres with SQLAlchemy for persistence
- Composio integration for Gmail
- Background services for triggers and monitoring
Database - Postgres (remote only, no local databases)
- Drizzle ORM schema shared between frontend and backend
- Must configure
DATABASE_HOST,DATABASE_USERNAME,DATABASE_PASSWORDin.env
- Node.js 18+, pnpm 9+
- uv (auto-manages Python and virtualenv)
- Remote Postgres database (no local databases allowed)
-
Clone and enter the repo
git clone https://github.com/shlokkhemani/OpenPoke cd OpenPoke -
Configure environment
cp .env.example .env
Fill in the required API keys and database credentials (see API Keys Setup below).
-
Install dependencies
pnpm install pnpm run server:sync # optional; uv will sync on first run if you skip -
Run development servers
pnpm run dev
- Web: http://localhost:3000
- API: http://localhost:8001
-
Connect Gmail for email workflows
With both services running, open http://localhost:3000, head to Settings → Gmail, and complete the Composio OAuth flow. This enables email drafting, replies, and the important-email monitor.
- Both services:
pnpm run dev(web :3000 + API :8001) - Frontend only:
cd apps/app && pnpm run dev(Next.js at :3000) - Backend only:
cd apps/server && pnpm run dev(FastAPI at :8001)
- Typecheck:
pnpm run typecheck - Lint:
pnpm run lint(Ultracite/Biome for TS, Ruff for Python) - Build:
pnpm run build - Start:
pnpm run start
- Format:
cd apps/server && pnpm run format(Ruff) - Lint:
cd apps/server && pnpm run lint(Ruff check + fix) - Type check:
cd apps/server && pnpm run typecheck(mypy strict)
- Push schema:
pnpm run db:push - Studio:
pnpm run db:studio - Generate:
pnpm run db:generate
Note: All commands run from project root
OpenRouter provides access to multiple AI models through a single API:
- Create an account at openrouter.ai
- Generate an API key
- Replace
your_openrouter_api_key_herewith your actual key in.env
Composio handles Gmail OAuth and provides email tools:
- Sign in at composio.dev
- Create an API key
- Set up Gmail integration and get your auth config ID
- Replace
your_composio_api_key_hereandyour_gmail_auth_config_id_herein.env
You need a remote Postgres database. No local databases are allowed:
- Set up a Postgres database (Railway, Supabase, etc.)
- Configure
DATABASE_HOST,DATABASE_USERNAME,DATABASE_PASSWORDin.env
openpoke/
├── apps/
│ ├── app/ # Next.js 15 frontend (:3000)
│ │ ├── src/app/ # App Router pages + API routes
│ │ ├── src/components/ # React UI components
│ │ ├── src/server/ # Server-side TypeScript
│ │ │ ├── db/ # Drizzle ORM schema (shared)
│ │ │ └── lib/ # Better Auth, logger, response types
│ │ ├── src/lib/ # Client utilities + hooks
│ │ └── src/trpc/ # tRPC client setup
│ └── server/ # FastAPI backend (:8001)
│ ├── agents/ # Custom agent implementations
│ │ ├── interaction_agent/ # Main orchestrator
│ │ └── execution_agent/ # Task execution specialist
│ ├── openrouter_client/ # Custom OpenRouter API client
│ ├── routes/ # FastAPI routes
│ ├── services/ # Business logic
│ ├── persistence/ # Postgres models & repositories
│ └── models/ # Pydantic API models
├── rules/ # Development guidelines
└── .env # Shared configuration
The frontend uses tRPC for type-safe API calls:
/api/trpcwithhttpBatchStreamLink+ superjson- Next.js proxies requests to FastAPI backend
- Use
getBaseUrl()for port resolution - TanStack Query integration with
createTRPCContext
- Frontend: Better Auth
- Backend: OpenRouter API keys + Composio Gmail OAuth
- Use
import typefor type-only imports - Prefer
interfaceovertype - Arrow functions,
const, strict equality - Never use
any,enums, ornamespaces
- Hooks at top level
- Use
<>not<Fragment> - Use Next.js
<Image>, not<img> - Import builtins with
node:protocol - No Array index keys or nested component definitions
- Ruff formatter (120-char line length, double quotes)
- mypy strict mode type checking
- Python 3.12+ features
- Type hints required on all functions
- Use
uvfor all Python commands
- Validation: Zod schemas
- Auth errors: Throw
TRPCError - Don't swallow errors - always log or propagate
- Follow:
rules/logging.mdfor logging patterns
- Frontend: Vitest (not yet configured)
- Backend: pytest (not yet configured)
MIT — see LICENSE.