AI-native to-do application with a conversational interface and a graphical UI. The chat agent uses LLM tool calling and an MCP-style tool layer to create, update, search, tag, and complete tasks on the user's behalf.
┌──────────────────────────┐ HTTPS ┌──────────────────────────┐
│ Next.js Frontend │ ───────────────────▶│ FastAPI Backend │
│ (Cloudflare Workers) │ │ (FastAPI Cloud) │
│ │ │ │
│ • Chat UI │ │ • Auth (JWT) │
│ • Tasks UI │ │ • Tasks CRUD │
│ • OAuth (optional) │ │ • Conversations │
└──────────────────────────┘ │ • Chat agent + tools │
│ • Inline recurrence │
└────────────┬─────────────┘
│
▼
┌──────────────┐
│ PostgreSQL │
│ (managed) │
└──────────────┘
Two deployable units, one managed database. The agent reaches LLMs through OpenRouter, so the model and provider are a one-line config change.
.
├── backend/ FastAPI service — deploys to FastAPI Cloud
│ ├── src/
│ │ ├── api/ REST endpoints (auth, tasks, chat, conversations, health, password reset)
│ │ ├── core/ config, database, security, logging, llm (OpenRouter client)
│ │ ├── mcp/ chat agent + tool definitions
│ │ ├── middleware/ request logging + error handling
│ │ ├── models/ SQLModel entities
│ │ ├── services/ business logic (tasks, auth, chat, conversations, email)
│ │ └── utils/ date parsing helpers
│ ├── alembic/ database migrations
│ ├── main.py uvicorn entry point (re-exports src.main:app)
│ ├── pyproject.toml
│ └── .env.example
│
├── frontend/ Next.js app — deploys to Cloudflare Workers (via OpenNext)
│ ├── src/
│ │ ├── app/ routes (auth, chat, home, landing)
│ │ ├── components/ UI (chat, tasks, navigation, ui primitives)
│ │ ├── lib/ API client + utilities
│ │ └── types/ shared TS types
│ ├── public/_headers Workers Static Assets caching headers
│ ├── package.json
│ ├── next.config.ts wires OpenNext for `next dev`
│ ├── open-next.config.ts OpenNext + Cloudflare config
│ ├── wrangler.jsonc Workers deployment config
│ └── .env.example
│
├── specs/ spec-driven-development artifacts (spec, plan, tasks)
├── history/ prompt history records
└── .specify/ SDD templates and project constitution
- Conversational AI interface — chat with an LLM agent that operates on your task list via tool calls. The model is reached through OpenRouter, so you can switch from
openai/gpt-4o-minitoanthropic/claude-sonnet-4,google/gemini-2.5-flash, or any other supported model by changing one env var. - Graphical UI — full task list, filters, search, tagging, due-dates, priorities.
- MCP-style tool layer —
add_task,list_tasks,complete_task,update_task,delete_task,set_priority,add_tag,set_due_date,search_tasks,set_reminder,set_recurrence, etc. - Authentication — JWT auth, optional Sign-in-with-Google, password reset via Resend email.
- Recurring tasks — when a recurring task is completed the next occurrence is created inline by the backend.
- Python 3.11+
- Node.js 18+
- A PostgreSQL database (local Postgres, Neon, Supabase, etc.)
- An OpenRouter API key (
sk-or-v1-…) uvfor the backend,pnpmfor the frontend
cd backend
cp .env.example .env.local # fill in DATABASE_URL, JWT_SECRET, OPENROUTER_API_KEY, ...
uv venv
uv pip install -e .
uv run alembic upgrade head # run migrations
uv run uvicorn main:app --reload --host 0.0.0.0 --port 8000API: http://localhost:8000 — interactive docs: http://localhost:8000/docs.
cd frontend
cp .env.example .env.local # set NEXT_PUBLIC_API_URL=http://localhost:8000
pnpm install
pnpm devApp: http://localhost:3000.
See https://fastapicloud.com/docs/getting-started/existing-project/
cd backend
fastapi deploySet the following environment variables in the FastAPI Cloud dashboard:
| Variable | Required | Notes |
|---|---|---|
DATABASE_URL |
yes | Postgres connection string |
JWT_SECRET |
yes | 32+ random bytes |
OPENROUTER_API_KEY |
yes | One key for every supported provider via OpenRouter |
CORS_ORIGINS |
yes | Include the Cloudflare Workers domain (e.g. https://taskai-frontend.<account>.workers.dev or your custom domain) |
LLM_MODEL |
no | OpenRouter model slug — e.g. openai/gpt-4o-mini, anthropic/claude-sonnet-4, google/gemini-2.5-flash. Defaults to openai/gpt-4o-mini |
OPENROUTER_BASE_URL |
no | Defaults to https://openrouter.ai/api/v1 |
OPENROUTER_SITE_URL, OPENROUTER_APP_NAME |
no | Optional ranking headers shown on the OpenRouter leaderboard |
RESEND_API_KEY, RESEND_FROM_EMAIL, FRONTEND_URL |
no | Required only for password-reset emails |
LOG_LEVEL |
no | Defaults to INFO |
The Next.js app is bundled for the Workers runtime by @opennextjs/cloudflare. Deploy from your machine with:
cd frontend
pnpm install
pnpm deploy # runs `opennextjs-cloudflare build && opennextjs-cloudflare deploy`Or wire Cloudflare Workers Builds (Git → CI). In the Cloudflare dashboard
under Workers & Pages → taskai-frontend → Settings → Builds, set:
| Field | Value |
|---|---|
| Root directory | frontend |
| Build command | npx opennextjs-cloudflare build |
| Deploy command | npx wrangler deploy |
| Install command | blank (auto-detected from pnpm-lock.yaml) |
Set the following as build variables under Settings → Variables and Secrets (NEXT_PUBLIC_* are inlined into the client bundle at build time):
| Variable | Required |
|---|---|
NEXT_PUBLIC_API_URL |
yes — the FastAPI Cloud URL |
NEXT_PUBLIC_GOOGLE_CLIENT_ID |
optional, for Google OAuth |
After both are deployed, update CORS_ORIGINS on the backend to include the worker URL (https://taskai-frontend.<account>.workers.dev or your custom domain).
The agent talks to models exclusively through OpenRouter. Provider choice is a single environment variable:
LLM_MODEL=openai/gpt-4o-mini # default
LLM_MODEL=anthropic/claude-sonnet-4 # switch to Claude
LLM_MODEL=google/gemini-2.5-flash # switch to Gemini
LLM_MODEL=meta-llama/llama-3.3-70b-instruct
LLM_MODEL=mistralai/mistral-large-latestNo code changes required. The full catalogue is at openrouter.ai/models. Centralized client construction lives in backend/src/core/llm.py; every other call-site just imports get_llm_client and LLM_MODEL from there.
| Method | Path | Purpose |
|---|---|---|
POST |
/api/auth/register |
Register a new account |
POST |
/api/auth/login |
Login, returns JWT |
GET |
/api/auth/me |
Current user profile |
POST |
/api/auth/forgot-password |
Send reset code |
POST |
/api/auth/reset-password |
Reset password with code |
POST |
/api/auth/oauth |
OAuth login/sync (Google) |
GET |
/api/tasks |
List tasks (filters, sort) |
POST |
/api/tasks |
Create task |
PUT |
/api/tasks/{id} |
Update task |
PATCH |
/api/tasks/{id}/complete |
Toggle completion |
DELETE |
/api/tasks/{id} |
Delete task |
GET |
/api/tasks/search?q=... |
Search by keyword |
POST |
/api/tasks/{id}/tags |
Add tag |
DELETE |
/api/tasks/{id}/tags/{name} |
Remove tag |
POST |
/api/tasks/{id}/reminder |
Set reminder time |
POST |
/api/chat/chat |
Send message to agent |
GET |
/api/conversations |
List conversations |
GET |
/api/conversations/{id} |
Get conversation |
GET |
/health/live |
Liveness probe |
GET |
/health/ready |
Readiness probe (checks DB) |
Full schema: http://localhost:8000/docs.
This project follows a spec-driven workflow. See specs/001-taskai-core-platform/ for the spec, plan, and task list. Project rules and templates live in .specify/ and CLAUDE.md.
