P&AI Bot
The AI learning companion that keeps students motivated
Open-source Β· Self-hostable Β· Model-agnostic Β· Chat-first
Quick Start Β·
Features Β·
Architecture Β·
Deployment Β·
Contributing
What is P&AI?
P&AI (Practice & AI) is a proactive AI learning agent that teaches students through chat. It doesn't wait for students to ask β it initiates study sessions, tracks mastery, schedules reviews, and keeps students motivated with battles, streaks, leaderboards, and purpose-driven progress.
Built on Pandai's years of proven engagement mechanics that have made learning fun for millions of students across Southeast Asia.
Content is commodity. Motivation is the moat.
What makes P&AI different?
| Feature |
ChatGPT / Claude |
Khan Academy |
P&AI |
| Answers questions |
β
|
β
|
β
|
| Follows a curriculum |
β |
β
|
β
|
| Structured step-by-step solving |
β |
Partial |
β
|
| Adapts explanation to mastery level |
β |
β |
β
|
| Cites curriculum source in responses |
β |
β |
β
|
| Tracks mastery per topic |
β |
β
|
β
|
| Generates exam-style practice questions |
β |
β |
β
|
| Proactive β initiates sessions |
β |
β |
β
|
| Spaced repetition scheduling |
β |
β |
β
|
| Battles, streaks, leaderboards |
β |
β |
β
|
| Model-agnostic (swap AI providers) |
β |
β |
β
|
| Self-hostable |
β |
β |
β
|
| Works on $50 phones via Telegram |
β |
β |
β
|
| Open source |
β |
β |
β
|
Quick Start
Get P&AI running in under 5 minutes.
Prerequisites
- Docker and Docker Compose (v2+)
- A Telegram bot token (get one from @BotFather)
- At least one AI provider API key (OpenAI, Anthropic, or use free self-hosted Ollama)
git clone --recurse-submodules https://github.com/p-n-ai/pai-bot.git
cd pai-bot
git submodule update --init --recursive
cp .env.example .env
Edit .env with your credentials:
# Required
LEARN_TELEGRAM_BOT_TOKEN=your-telegram-bot-token
# AI Providers (at least one required)
LEARN_AI_DEFAULT_PROVIDER=openrouter
LEARN_AI_OPENROUTER_API_KEY=sk-or-v1-...
LEARN_AI_OPENROUTER_MODEL=qwen/qwen3-max
# Or use free self-hosted AI (no API key needed)
LEARN_AI_DEFAULT_PROVIDER=ollama
LEARN_AI_OLLAMA_ENABLED=true
LEARN_AI_OLLAMA_MODEL=qwen3
2. Start everything
docker compose up -d
This starts: PostgreSQL, Dragonfly (cache), NATS (messaging), the Go server, and the admin panel.
If you want demo rows in PostgreSQL for local testing, run:
just seed
If the app is running in Docker, seed through the app container instead:
just seed-docker
When the backend is running in Docker, make sure .env uses Compose service names such as postgres, dragonfly, and nats instead of localhost. The app service already reads .env, so school admins can choose AI provider and default model purely with Docker env vars. For Ollama, Compose overrides LEARN_AI_OLLAMA_URL inside the app container to http://ollama:11434.
3. Pull a free AI model (optional)
Only do this if you are using Ollama as your AI provider. This downloads the model weights into the Ollama container so the app has something local to run.
Warning: this can be a large download and may take time depending on the model and network speed.
docker compose exec ollama ollama pull qwen3
After that, set LEARN_AI_OLLAMA_ENABLED=true and optionally LEARN_AI_OLLAMA_MODEL=qwen3 in .env.
4. Chat with your bot
Open Telegram, find your bot, and send /start. That's it β you're learning.
5. Access the admin panel
Open http://localhost:3000 to access the admin panel. Current scaffolding keeps the shell publicly reachable in local development, but the planned production model is invite-based account activation followed by email + password login for teacher, parent, and admin roles.
6. Browse the API docs
Open http://localhost:8080/docs for the Scalar-powered API reference. The raw OpenAPI document is served at http://localhost:8080/openapi.json and is generated directly from explicit Go request/response schemas.
Features
π For Students
- AI Tutor on Telegram β Learn any topic through natural chat conversation. The AI uses Socratic method, scaffolding, and growth mindset pedagogy.
- Step-by-Step Problem Solving β Every math question is answered with a structured approach: Understand β Plan β Solve β Verify β Connect. Teaches students how to think, not just the answer.
- Adaptive Explanations β The AI adjusts explanation complexity based on your mastery level. Beginners get simpler language and more examples; proficient students get concise explanations with harder challenges.
- Curriculum-Cited Responses β Every explanation references the exact curriculum source (e.g., "KSSM Form 1 > Algebra > Linear Equations"), so students can find it in their textbook.
- Proactive Study Sessions β The agent initiates conversations when it's time to review. Spaced repetition ensures long-term retention.
- Progress Tracking β See mastery per topic, XP earned, streak length, and progress toward personal goals.
- Quizzes & Assessments β Take quizzes in chat with deterministic grading for OSS-backed free-text answers, hints, and detailed feedback.
- Exam-Style Practice β Current quiz content comes from OSS KSSM assessment sets reviewed against Algebra topics. Dynamic AI-generated UASA/SPM-style mimicry is planned, not yet live.
- Peer Challenges β Battle classmates on the same set of questions. Learn together, compete for fun.
- Goals & Streaks β Set a learning goal ("Master algebra by April") and track daily streaks.
π©βπ« For Teachers
- Class Dashboard β Mastery heatmap showing every student's progress across every topic at a glance.
- Student Detail View β Deep dive into any student: mastery radar, activity timeline, struggle areas, conversation summaries.
- Nudge Students β One-click to have the AI send a personalized study prompt to a specific student.
- Assign Topics β Direct the AI to teach a specific topic to a student or entire class. (Planned)
- Weekly Leaderboards β Motivate the class with weekly rankings by mastery gain.
πͺ For Parents
- Child Progress View β Simple dashboard showing weekly activity, topics studied, streak, and XP.
- Weekly Reports β Automated weekly summary: what your child worked on, what they did well, and how you can help.
π« For Schools & Governments
- Self-Hostable β Run on your own infrastructure. Full data sovereignty. No student data leaves your network.
- Multi-Tenant β One deployment serves multiple schools, each with isolated data.
- Token Budget Management β Allocate AI credits per school, per class, or per student. Automatic fallback to free self-hosted models when budget runs low.
- Data Export β Export all student data as CSV/JSON at any time. Your data, your control.
Architecture
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Chat Channels β
β ββββββββββββ ββββββββββββ ββββββββββββ β
β β Telegram β β WhatsApp β β WebSocketβ β
β ββββββ¬ββββββ βββββββ¬βββββ ββββββ¬ββββββ β
β βββββββββββββββΌββββββββββββ β
β βΌ β
β Chat Gateway β
β β β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββ β
β β Agent Engine β β
β β ββββββββββββββββ ββββββββββββββββββββ β β
β β β Conversation β β Proactive β β β
β β β State Machineβ β Scheduler (NATS) β β β
β β ββββββββββββββββ ββββββββββββββββββββ β β
β β βββββββββββββββ ββββββββββββββββββββ β β
β β β Progress β β Pedagogical β β β
β β β Tracker β β Prompts β β β
β β βββββββββββββββ ββββββββββββββββββββ β β
β ββββββββββββββββββββββββ¬ββββββββββββββββββββ β
β β β
β ββββββββββββββΌβββββββββββββββ β
β βΌ βΌ βΌ β
β βββββββββββββββββ ββββββββββββ βββββββββββββββββ β
β β AI Gateway β βCurriculumβ β PostgreSQL β β
β β βββββββββββ β β Service β β + Dragonfly β β
β β βOpenAI β β β (OSS) β β β β
β β βAnthropicβ β ββββββββββββ βββββββββββββββββ β
β β βOllama β β β
β β βCustom β β β
β β βββββββββββ β β
β βββββββββββββββββ β
β β
β ββββββββββββββββββββββββββββββββββββββββββββ β
β β Admin Panel (Next.js + TanStack Query) β β
β β Teacher Dashboard Β· Parent View Β· Admin β β
β ββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Tech Stack
| Component |
Technology |
Why |
| Backend |
Go 1.22+ (stdlib) |
Goroutines handle millions of concurrent connections. Single binary, ~15MB. |
| Database |
PostgreSQL 17 |
Standard, portable. Every cloud has managed Postgres. |
| Cache |
Dragonfly |
Redis-compatible, multi-threaded, 80% less memory. |
| Messaging |
NATS + JetStream |
Proactive nudge scheduling, background jobs, event-driven communication. |
| AI Providers |
OpenAI, Anthropic, Ollama, OpenRouter |
Provider-agnostic gateway. Swap models without code changes. |
| Chat |
Telegram Bot API, WhatsApp Cloud API, WebSocket |
Works on $50 phones, 2G connections, zero data cost in many countries. |
| Admin Panel |
Next.js 16, TypeScript, TanStack Query, shadcn/ui |
Teacher dashboards, parent views, school admin. |
| Curriculum |
Open School Syllabus |
Structured YAML curriculum consumed by the agent. |
| Deployment |
Docker Compose or Helm |
Single server ($20/mo) to national deployment (millions of students). |
Current Admin Auth
- Teachers, parents, school admins, and platform admins sign in through
/login; visiting / routes signed-in users to their workspace and everyone else to the login flow.
- Ongoing login uses
email + password; if the same email belongs to multiple schools, the UI asks the user to pick the correct school before finishing sign-in.
- The Go backend owns admin auth with one server session cookie (
pai_session); bearer JWT parsing remains only as a compatibility lane.
- Students continue to access P&AI primarily through Telegram; a student web login is not part of the current baseline.
Project Structure
pai-bot/
βββ cmd/
β βββ server/main.go # Application entrypoint
β βββ seed/main.go # Demo data seeder
β βββ terminal-chat/main.go # Terminal chat for testing
β βββ terminal-nudge/main.go # Terminal nudge for testing
βββ internal/
β βββ ai/ # AI Gateway
β β βββ gateway.go # Provider interface + types
β β βββ router.go # Model routing + fallback chain + circuit breaker
β β βββ budget.go # Token budget tracking (in-memory)
β β βββ provider_openai.go # OpenAI + DeepSeek (compatible API)
β β βββ provider_anthropic.go # Anthropic Claude
β β βββ provider_google.go # Google Gemini
β β βββ provider_ollama.go # Self-hosted (Llama, Qwen, etc.)
β β βββ provider_openrouter.go # 100+ models via OpenRouter
β βββ agent/ # Agent Engine
β β βββ engine.go # Conversation state machine
β β βββ scheduler.go # Proactive nudge scheduler
β β βββ quiz.go # Quiz engine + assessment
β β βββ challenge.go # Peer battle system
β β βββ challenge_runtime.go # Challenge gameplay + settlement
β β βββ goals.go # Goal tracking
β βββ chat/ # Chat Gateway
β β βββ gateway.go # Unified message routing
β β βββ telegram.go # Telegram Bot API adapter
β β βββ websocket.go # WebSocket adapter
β βββ curriculum/ # Curriculum Service
β β βββ loader.go # Reads YAML from OSS repository
β β βββ types.go # Go structs matching OSS schema
β β βββ prerequisites.go # Prerequisite graph
β βββ progress/ # Progress Tracker
β β βββ tracker.go # Mastery scoring
β β βββ spaced_rep.go # SM-2 algorithm
β β βββ streaks.go # Streak tracking
β β βββ xp.go # XP system
β βββ auth/ # Authentication
β β βββ jwt.go # Token generation + validation
β β βββ middleware.go # Role-based access control
β β βββ google_oidc.go # Google OIDC sign-in
β β βββ service.go # Login, invites, sessions
β βββ adminapi/ # Admin REST API
β βββ retrieval/ # BM25 knowledge retrieval
β βββ tenant/ # Multi-tenancy bootstrap
β βββ i18n/ # Internationalization (BM/EN/ZH)
β βββ platform/ # Shared infrastructure
β βββ config/ # Environment configuration
β βββ database/ # PostgreSQL connection (pgx)
β βββ cache/ # Dragonfly client (go-redis)
β βββ mailer/ # SMTP email delivery
β βββ seed/ # Demo data seeding
βββ admin/ # Legacy Next.js admin panel
βββ admin-spa/ # Vite/TanStack admin SPA
β βββ src/
β βββ routes/ # TanStack Router routes
β βββ components/ # Admin UI components (shadcn/ui)
βββ migrations/ # SQL migration files (goose)
βββ deploy/
β βββ docker/
β β βββ Dockerfile # Multi-stage Go build
β β βββ Dockerfile.admin # Multi-stage Next.js build
β βββ caddy/ # Reverse proxy config
β βββ nginx/ # Alternative reverse proxy
βββ scripts/
β βββ setup.sh # First-time setup wizard
β βββ deploy-remote.sh # Production deployment
β βββ analytics.sh # Quick metrics from CLI
βββ docker-compose.yml # Local development
βββ docker-compose.prod.yml # Production single-server
βββ justfile # Preferred task runner
βββ .env.example # All configuration documented
βββ .github/workflows/ # CI pipeline
AI Providers
P&AI is not locked to any AI model. Configure one or more providers:
| Provider |
Models |
Cost |
Setup |
| OpenAI |
GPT-5.4, GPT-5.4 mini |
Paid API |
Set LEARN_AI_OPENAI_API_KEY and optionally LEARN_AI_OPENAI_MODEL |
| Anthropic |
Claude Sonnet 4.6, Claude Haiku 4.5 |
Paid API |
Set LEARN_AI_ANTHROPIC_API_KEY and optionally LEARN_AI_ANTHROPIC_MODEL |
| DeepSeek |
DeepSeek-V3.2 (deepseek-chat), DeepSeek-R1 (deepseek-reasoner) |
Paid API (very cheap) |
Set LEARN_AI_DEEPSEEK_API_KEY and optionally LEARN_AI_DEEPSEEK_MODEL |
| Google Gemini |
Gemini 3 Flash Preview, Gemini 3 Pro Preview |
Paid API |
Set LEARN_AI_GOOGLE_API_KEY and optionally LEARN_AI_GOOGLE_MODEL |
| Ollama |
Qwen3, Qwen3 14B, Qwen3 30B |
Free (self-hosted) |
Set LEARN_AI_OLLAMA_ENABLED=true and optionally LEARN_AI_OLLAMA_MODEL |
| OpenRouter |
Qwen3 Max, Qwen3 Coder Next, 100+ others |
Varies |
Set LEARN_AI_OPENROUTER_API_KEY and optionally LEARN_AI_OPENROUTER_MODEL |
DeepSeek uses the OpenAI-compatible API format β no extra code, just a different API key and base URL. Its official deepseek-chat alias already tracks the current DeepSeek-V3.2 non-thinking model. Gemini 3 models are the latest family, but note that the current Flash/Pro API IDs are preview models. Preview Gemini IDs can have different or tighter rate limits, so for steadier production behavior it is usually safer to set LEARN_AI_GOOGLE_MODEL to a non-preview model name such as gemini-2.5-flash. Qwen, Kimi, and other models are accessible via OpenRouter or self-hosted via Ollama.
To prefer one provider first, set LEARN_AI_DEFAULT_PROVIDER to one of: openai, anthropic, deepseek, google, ollama, openrouter.
The AI Gateway automatically routes by task type:
- Teaching (complex explanations) β Best available model (Claude Sonnet, GPT-4o, Gemini Pro)
- Grading (quick JSON responses) β Cheapest model (DeepSeek V3, GPT-4o-mini, Gemini Flash)
- Question generation (dynamic quiz/exam-style) β Cheapest model (DeepSeek V3, GPT-4o-mini)
- Nudges (short messages) β Any available model
- Fallback β Self-hosted Ollama (always free)
When paid API budgets run low, the system automatically degrades to cheaper models, then to self-hosted. No student is ever cut off from learning.
Supported Curricula
P&AI reads structured curriculum data from the Open School Syllabus (OSS) repository.
Currently supported:
| Curriculum |
Subjects |
Status |
| Malaysia KSSM Form 1 |
Matematik (Algebra) |
Live |
| Malaysia KSSM Form 2 |
Matematik (Algebra) |
Live |
| Malaysia KSSM Form 3 |
Matematik (Algebra) |
Live |
| Cambridge IGCSE 0580 |
Mathematics |
Planned |
| More coming β contributions welcome! |
|
|
Adding a new curriculum doesn't require code changes β just add YAML files to the OSS repository and P&AI picks them up automatically. See the OSS contribution guide.
Updating OSS Submodule Pointer
To sync to the latest oss commit from its default branch:
git submodule update --remote oss
Note: the submodule wiring is currently a bootstrap stub for upcoming curriculum sync work, not a finalized end-user feature.
Deployment
Option 1: Single Server (Docker Compose)
For a single school or small deployment. Runs on any VPS with 2GB+ RAM.
git clone https://github.com/p-n-ai/pai-bot.git
cd pai-bot
./scripts/setup.sh # Interactive setup wizard
docker compose up -d # Start everything
Cost: ~$20/month on any VPS provider. Supports 100-500 students.
Option 2: Kubernetes (Helm)
For districts, states, or national deployments. A Helm chart is available at deploy/helm/pai/.
helm install pai deploy/helm/pai \
--set secrets.telegramBotToken=YOUR_TOKEN \
--set secrets.ai.openaiApiKey=YOUR_KEY \
--set secrets.authSecret=$(openssl rand -hex 16) \
--set ingress.enabled=true \
--set ingress.host=learn.yourschool.edu.my
See docs/ops/deployment.md for full configuration, local testing with k3d, and external database setup.
Scales: Horizontally to millions of students. Each school gets a namespace with isolated data.
Option 3: Cloud-Agnostic
P&AI is designed to run on any cloud without lock-in:
| Component |
AWS |
GCP |
Azure |
Self-Hosted |
| Compute |
EKS |
GKE |
AKS |
Any K8s |
| Database |
RDS PostgreSQL |
Cloud SQL |
Azure DB |
PostgreSQL |
| Cache |
(self-hosted Dragonfly) |
(self-hosted) |
(self-hosted) |
Dragonfly/Redis |
| Messaging |
(self-hosted NATS) |
(self-hosted) |
(self-hosted) |
NATS |
| Storage |
S3 |
GCS |
Blob |
MinIO |
Configuration Reference
Configuration is environment-driven. Core app variables use LEARN_; auth variables use PAI_AUTH_ only. See .env.example for the complete list.
| Variable |
Required |
Default |
Description |
LEARN_TELEGRAM_BOT_TOKEN |
Yes |
β |
Telegram bot token from @BotFather |
LEARN_DATABASE_URL |
No |
postgres://pai:pai@localhost:5432/pai |
PostgreSQL connection string |
LEARN_CACHE_URL |
No |
redis://localhost:6379 |
Dragonfly/Redis connection |
LEARN_NATS_URL |
No |
nats://localhost:4222 |
NATS messaging server |
LEARN_AI_DEFAULT_PROVIDER |
No |
β |
Preferred provider to try first (openai, anthropic, deepseek, google, ollama, openrouter) |
LEARN_AI_OPENAI_API_KEY |
No* |
β |
OpenAI API key |
LEARN_AI_OPENAI_MODEL |
No |
β |
Default OpenAI model when request model is not set |
LEARN_AI_ANTHROPIC_API_KEY |
No* |
β |
Anthropic API key |
LEARN_AI_ANTHROPIC_MODEL |
No |
β |
Default Anthropic model when request model is not set |
LEARN_AI_DEEPSEEK_API_KEY |
No* |
β |
DeepSeek API key (OpenAI-compatible) |
LEARN_AI_DEEPSEEK_MODEL |
No |
β |
Default DeepSeek model when request model is not set |
LEARN_AI_GOOGLE_API_KEY |
No* |
β |
Google Gemini API key |
LEARN_AI_GOOGLE_MODEL |
No |
β |
Default Google model when request model is not set |
LEARN_AI_OPENROUTER_API_KEY |
No* |
β |
OpenRouter API key (100+ models) |
LEARN_AI_OPENROUTER_MODEL |
No |
β |
Default OpenRouter model when request model is not set |
LEARN_AI_OLLAMA_ENABLED |
No* |
false |
Enable self-hosted Ollama |
LEARN_AI_OLLAMA_URL |
No |
http://localhost:11434 |
Ollama server URL |
LEARN_AI_OLLAMA_MODEL |
No |
β |
Default Ollama model when request model is not set |
LEARN_AI_PERSONALIZED_NUDGES_ENABLED |
No |
true |
Let AI personalize proactive nudge messages; falls back to template text on failure |
PAI_AUTH_SECRET |
No |
change-me-in-production |
Root auth secret; currently used for JWT signing |
LEARN_SERVER_PORT |
No |
8080 |
HTTP server port |
LEARN_TENANT_MODE |
No |
single |
single or multi tenant mode |
*At least one AI provider must be configured.
First-Boot Tenant Flow
The first setup behavior depends on LEARN_TENANT_MODE:
single mode:
- On server startup, P&AI ensures tenant slug
default exists.
- If it is missing (for example, on a fresh DB), startup will auto-create/upsert it.
- Tenant-bound runtime services use this single tenant context.
multi mode:
- Startup does not auto-create tenants.
- Tenant lifecycle is managed explicitly (seed/admin/invite workflows).
Recommended first setup sequence:
- Run migrations.
- Set
LEARN_TENANT_MODE in .env.
- Start the server.
Development
Prerequisites
- Go 1.22+
- Node.js 20+ (for admin panel)
- Docker and Docker Compose
Local Development
Note: just recipes are supported on macOS/Linux for now. On Windows, prefer Docker/WSL2 instead of just go / just next.
just go / just next require LEARN_DATABASE_URL to be present in .env; the local bootstrap path no longer falls back to an implicit default DSN or shell override.
# Start infrastructure (Postgres, Dragonfly, NATS, Ollama)
docker compose up -d postgres dragonfly nats ollama
# Run database migrations
just migrate
# Check the current migration version
just migrate-version
# Seed demo data (optional)
just seed
# Or, if the app itself is running in Docker
just seed-docker
# Start the Go server (turnkey deps + local Postgres/Dragonfly; auto-seeds only for the default local dev DB target)
just go
# Start the admin panel + Agentation MCP, and try to boot the Go server if needed
# If backend boot fails, Next.js still starts; check /tmp/pai-go.log for backend errors
# Ctrl-C also stops backend + Agentation started by this command
just next
# Start Google auth emulator + backend + admin + Agentation through one wrapper script
# Good target for Codex app "play" / run-button flows
./scripts/run-dev.sh
# Stop docker services plus local backend/frontend/Agentation listeners
just stop
# Stop only the local run-dev.sh processes
./scripts/stop-dev.sh
Running Tests
go test ./... # Run all Go tests
go test -tags=integration ./... # Run integration tests
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out -o coverage.html
go run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@"${GOLANGCI_LINT_VERSION:-v2.4.0}" run ./...
cd admin && pnpm test # Admin unit + component tests
cd admin && pnpm test:e2e # Admin Playwright smoke tests
just admin-e2e # Same Playwright run via just
just test-all # Convenience gate: lint + Go tests + admin unit/component tests
Playwright first-run setup (install deps + Chromium) is documented in docs/ops/setup.md.
Backend-dependent E2E tests are tagged @backend and are skipped by default unless E2E_BACKEND_ENABLED=true. Authenticated routes also require E2E_AUTH_ENABLED=true plus E2E_ADMIN_EMAIL and E2E_ADMIN_PASSWORD.
These E2E_* variables are documented in .env.example.
OpenAI live conversation integration suite:
- Fixture source:
internal/agent/testdata/openai_live_conversations.yaml (30 scripted conversations, 2-10 turns each)
- Test harness:
internal/agent/engine_openai_integration_test.go (//go:build integration)
- Required env for live run:
LEARN_AI_OPENAI_API_KEY
- Optional env:
LEARN_AI_LIVE_TIMEOUT_SECONDS (default 45)
LEARN_AI_LIVE_MAX_CASES (default 30)
- CI behavior: the live OpenAI suite is explicitly skipped in CI (
CI/GITHUB_ACTIONS detection) to avoid external paid API calls in pipeline runs.
Terminal chat workflow:
just chat-terminal
# or:
docker compose run --rm --entrypoint /pai-terminal-chat app --user-id demo-user --lang en
# for an ephemeral local-only session:
docker compose run --rm --entrypoint /pai-terminal-chat app --memory
The terminal chat uses the same agent.Engine and AI router as the app. By default it uses PostgreSQL-backed conversation state for production parity; pass --memory for an ephemeral local-only session.
Terminal nudge workflow:
just nudge-terminal USER_ID=demo-user
# or:
docker compose run --rm --entrypoint /pai-terminal-nudge app --user-id demo-user
The terminal nudge command triggers the real scheduler path for one user and prints any generated nudge message to stdout.
Useful Commands
just setup # First-time setup
just install-deps # Install Go modules + frontend packages
just install-local-runtime # Install missing Postgres client tools via Homebrew when available
just start # Start all services via Docker Compose
just stop # Stop all services
just logs # Tail application logs
just migrate # Run database migrations
just migrate-status # Show applied/pending goose migrations
just migrate-version # Show current goose migration version
just migrate-down # Roll back the most recent migration
just migration-create add_parent_invites # Create a new timestamped SQL migration
just seed # Seed demo tenant/users/messages/progress/events
just seed-docker # Seed through the running app container
just analytics # Print quick metrics from the database
just analytics-xlsx # Export a styled Excel workbook to output/spreadsheet/
just analytics-example # Generate a sample Excel workbook without a database
just ollama-pull # Download a free AI model for Ollama
just chat-terminal # Open a local terminal chat session
just nudge-terminal USER_ID=<user-id> # Trigger a due-review nudge for one user
Excel export notes:
scripts/analytics.sh --xlsx output/spreadsheet/pai-analytics.xlsx keeps the terminal report and also writes a formatted workbook.
scripts/analytics.sh --example-xlsx output/spreadsheet/pai-analytics-example.xlsx creates a sample workbook for layout review without touching the database.
- The analytics script loads
.env automatically when present. When PAI_DB_URL is unset, it falls back to LEARN_DATABASE_URL from the app environment before using Docker Compose PostgreSQL.
- The workbook builder now runs through
go run ./cmd/analyticsxlsx, so there is no separate Python runtime or spreadsheet dependency to install.
Migration notes:
- The repo now uses
goose with single-file timestamped SQL migrations and goose_db_version tracking.
just migrate runs goose up -allow-missing so older timestamped migrations can still be applied after newer ones in out-of-order branch merges.
- Existing databases from the pre-goose migration flow should be recreated in local dev or explicitly baselined before switching tools. Do not run both migration systems against the same database long-term.
Rating Analytics Contract
- Rating callbacks use internal assistant message IDs in callback data:
rating:{messages.id}:{score}.
- Submitted ratings are logged in
events as answer_rating_submitted with:
data.rating (1-5)
data.rated_message_id (assistant messages.id being rated)
data.source, data.channel, data.delayed_submit
- Deduplication is enforced per rated assistant message (
rated_message_id) to prevent duplicate submissions for the same prompt.
Contributing
We welcome contributions! P&AI is built by a community that believes every student deserves a patient, always-available learning companion.
Ways to contribute
- Code β Pick up a good first issue or propose a feature.
- Curriculum β Add topics, teaching notes, or assessments to OSS.
- Translation β Help translate the bot's messages and admin panel.
- Testing β Try P&AI with real students and report what works and what doesn't.
- Documentation β Improve guides, fix typos, add examples.
Development workflow
- Fork the repo
- Create a feature branch (
git checkout -b feature/amazing-feature)
- Make your changes
- Run tests (
go test ./... and go run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@"${GOLANGCI_LINT_VERSION:-v2.4.0}" run ./...)
- Commit (
git commit -m 'Add amazing feature')
- Push to your branch (
git push origin feature/amazing-feature)
- Open a Pull Request
See docs/ops/setup.md for development environment setup.
Documentation
| Document |
Description |
| Setup Guide |
Prerequisites, quick start, environment variables, common issues |
| Configuration |
Environment variable defaults and validation rules |
| Architecture |
Modular monolith design, domain packages, HTTP routing, infrastructure |
| AI Providers |
Provider configuration, fallback chain, structured output, budget enforcement |
| Curriculum |
YAML schema, teaching notes, assessments, adding new curricula |
| Deployment |
Docker Compose production, monitoring, backups |
| Admin Panel |
Dashboard features, roles, API specification |
| Admin Routes |
Admin frontend route and backend API map |
| Telegram Runtime |
Telegram Bot API polling, commands, media, and nudge behavior |
| Embed Chat |
Embeddable widget runtime and security boundaries |
| WhatsApp Runtime |
WhatsApp backend modes, env vars, and setup routes |
| OpenAPI and Scalar |
API docs surface and update rules |
| Local Tools |
Local helper binaries, scripts, and emulation tools |
| Technical Plan |
Detailed architecture, database schema, security model |
| Repository |
Description |
| p-n-ai/oss |
Open School Syllabus β structured curriculum data for any learning platform. See docs/curriculum-oss.md for how pai-bot consumes it. |
| p-n-ai/oss-bot |
GitHub bot + CLI tools for contributing to Open School Syllabus |
License
P&AI Bot is licensed under the Apache License 2.0.
You are free to use, modify, and distribute this software. Self-host it for your school, fork it for your country, build a business on it. The only requirement is that you include the license notice.
Our promise: The core learning platform will always be free and open source. We will never sell student data or show ads.
Acknowledgments
P&AI is built on the shoulders of Pandai β years of making learning fun for millions of students through gamification, battles, leaderboards, and purpose-driven progress. The secret sauce has always been motivation, not content.
Every student deserves a patient, always-available learning companion.
A Pandai initiative. Built with β€οΈ by educators and AI, for everyone.