Skip to content

panda41983/uni-pilot

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

45 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

UniPilot

Node.js TypeScript Express SQLite Anthropic Claude JavaScript Google APIs Canvas Telegram

Quiet AI teammates for the parts of school you keep forgetting.

UniPilot is a college-student productivity platform built around a handful of focused AI agents. It pulls your real academic life in from Canvas, Ed Discussion, and Google Calendar, then puts a few calm, single-purpose agents on top:

  • The Briefer — texts a short "here's your day" to your phone every morning (via Telegram).
  • The Scheduler — turn plain English ("office hours Tuesday 3pm") into calendar events; you confirm before anything is written.
  • The Messenger — drafts emails to professors when you're sick or slammed. It never sends without you.
  • Syllabus Reader — drop in a syllabus (PDF/DOCX/text) and it extracts grading, key dates, and policies, then lets you chat about the class.

Plus supporting engines: a grade evaluator, an assignment planner, and a RAG course tutor that answers questions from your own uploaded materials.

Built for a hackathon. Everything degrades gracefully — the app runs and is usable even with no API keys configured (agents fall back to deterministic templates and local heuristics).


Tech stack

Layer Choice
Frontend Vanilla JS (no framework, no build step), a tiny hash router, hand-written CSS. Served as static files from public/.
Backend Node.js + Express (TypeScript, ESM), run with tsx in dev and compiled with tsc for prod.
Database SQLite via Node's built-in node:sqlite (no native deps / no compile toolchain). Schema in server/src/db/schema.sql.
LLM Anthropic Claude (@anthropic-ai/sdk) for brief wording, message interpretation, email/answer drafting, and syllabus extraction.
Integrations Canvas LMS (REST + token), Google Calendar + Gmail (OAuth via googleapis), Ed Discussion, Telegram Bot API.
Parsing / utils pdf-parse + mammoth (syllabus/doc text), rrule (recurring events), dayjs (time), zod (request validation), multer (uploads), nanoid (ids).
Security Sensitive fields (tokens, grades) encrypted at rest with AES-256-GCM (server/src/crypto.ts).

The frontend and backend are served from a single origin (Express serves public/ and falls back to the SPA shell), so there's no CORS/proxy setup needed in dev or prod.


Prerequisites

  • Node.js >= 22.5 — required, because the backend uses the built-in node:sqlite module. Check with node -v.
  • npm (ships with Node).
  • Optional API keys (see Configuration) — only needed to light up the LLM and live integrations.

Quick start

# 1. Clone, then install root + server dependencies
npm run install:all

# 2. Set up environment (optional, but recommended)
cp .env.example .env
# open .env and fill in any keys you have (all optional — see below)

# 3. Run the dev server (tsx watch — restarts on changes)
npm run dev

Then open http://localhost:4000.

On first boot the server creates data.db, applies the schema, generates a local encryption key (.enc-key) if one isn't set, and — if Canvas credentials are present — imports your courses/assignments once.

Try it out without any keys

Just run npm run dev and open the app. You can browse Today, Classes, Deploy, and the agent pages with seeded/fallback data. To populate realistic data, run the seed script:

npm run seed

Trying the Syllabus Reader

  1. Go to Deploy and click the Syllabus Reader card → its page opens.
  2. Choose a file (PDF, DOCX, HTML, or .txt/.md) or expand "or paste the syllabus text."
  3. Click Read syllabus — you'll get a structured summary (grading breakdown, key dates, policies, office hours, materials).
  4. Use the chat box to ask anything about the class — answers are grounded strictly in that syllabus. (Chat requires ANTHROPIC_API_KEY; the summary works without it via a regex fallback.)

Available scripts

Run from the repo root:

Command What it does
npm run install:all Install root + server/ dependencies.
npm run dev Start the backend in watch mode (tsx watch) and serve the frontend at :4000.
npm run build Type-check + compile the server to server/dist/ (copies the SQL schema).
npm run start Run the compiled production build (node dist/index.js).
npm run seed Seed the SQLite DB with sample courses/assignments/data.

Configuration

Copy .env.example.env. Every value is optional; missing keys just disable that capability.

Variable Purpose
ANTHROPIC_API_KEY The "brain." Enables LLM brief wording, message interpretation, email/answer drafting, and syllabus extraction. Without it, agents use deterministic fallbacks.
ANTHROPIC_MODEL Claude model name (default claude-opus-4-8).
TELEGRAM_BOT_TOKEN The Briefer's channel. Create a bot with @BotFather, paste the token, then message your bot once to link it.
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET Google OAuth for the Scheduler (write to Google Calendar) and Gmail drafts. Enable the Calendar API, create a Web OAuth client, set redirect URI to http://localhost:4000/api/auth/google/callback, then click Connect in the app.
GOOGLE_REDIRECT_URI Override the OAuth callback (defaults to the localhost URI above).
CANVAS_BASE_URL / CANVAS_TOKEN Server-wide Canvas LMS access (alternatively, connect per-user in-app on the You page).
ED_API_TOKEN Ed Discussion announcements/threads.
PORT Backend port (default 4000).
ENCRYPTION_KEY 32-byte hex key for encrypting tokens/grades at rest. Generate: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))". If unset, a key is generated and persisted to .enc-key on first run.
DB_PATH Override the SQLite file location (default server/../data.db).
RMP_ENABLED / REDDIT_TOKEN Best-effort enrichment sources (RateMyProfessors / Reddit), off by default.

Project structure

ai-hackathon-2026/
├── public/                 # Vanilla JS frontend (no build step)
│   ├── index.html          # App shell
│   ├── app.js              # Hash router + all views
│   ├── api.js              # Backend client + bootstrap/data mapping
│   ├── data.js             # Agent config + live state containers
│   ├── styles.css          # Hand-written styles
│   └── logo.svg / favicon.svg
├── server/
│   └── src/
│       ├── index.ts        # Express app, static serving, boot tasks
│       ├── http/           # API routes (routes.ts) + request context
│       ├── agents/         # brief, calendar, email, faq, grade, planner, syllabus
│       ├── integrations/   # canvas, google, ed, telegram, RateMyProf/Reddit
│       ├── db/             # SQLite adapter, repo layer, schema.sql, seed
│       ├── llm/            # Anthropic client wrapper
│       ├── domain/         # time/date helpers
│       ├── crypto.ts       # AES-256-GCM field encryption
│       ├── scheduler.ts    # daily-brief scheduler
│       └── telegram-router.ts
├── .env.example            # Copy to .env
└── package.json            # Root scripts (proxy to server/)

Architecture

flowchart TB
    subgraph Browser["Browser — Vanilla JS SPA (public/)"]
        UI["index.html · app.js (hash router + views)"]
        APIJS["api.js — fetch client + bootstrap"]
        UI --> APIJS
    end

    subgraph Server["Node.js + Express (server/) — single origin :4000"]
        STATIC["Static serving + SPA fallback"]
        ROUTES["http/routes.ts — /api/* (zod-validated)"]

        subgraph Agents["Agents (engines)"]
            BRIEF["Briefer"]
            CAL["Scheduler / calendar"]
            EMAIL["Messenger / email (draft-only)"]
            SYL["Syllabus Reader"]
            FAQ["RAG tutor / faq"]
            GRADE["Grade eval"]
            PLAN["Planner"]
        end

        subgraph Bg["Background"]
            SCHED["scheduler.ts — daily brief"]
            TG["telegram-router.ts"]
        end

        CRYPTO["crypto.ts — AES-256-GCM at rest"]
        REPO["db/repo.ts"]
        DB[("SQLite — data.db<br/>node:sqlite")]

        ROUTES --> Agents
        SCHED --> BRIEF
        TG --> BRIEF
        TG --> EMAIL
        Agents --> REPO
        REPO --> CRYPTO --> DB
    end

    subgraph LLM["LLM"]
        CLAUDE["Anthropic Claude<br/>@anthropic-ai/sdk"]
    end

    subgraph Ext["External integrations (all optional)"]
        CANVAS["Canvas LMS"]
        GOOGLE["Google Calendar + Gmail"]
        ED["Ed Discussion"]
        TELEGRAM["Telegram Bot API"]
    end

    APIJS -- "HTTP /api/*" --> STATIC
    STATIC --> ROUTES
    Agents -. "wording / extraction<br/>(falls back to templates)" .-> CLAUDE
    CAL <--> GOOGLE
    EMAIL <--> GOOGLE
    ROUTES <--> CANVAS
    FAQ <--> ED
    TG <--> TELEGRAM
Loading

Request flow (e.g. add a calendar event):

sequenceDiagram
    participant U as User (Browser)
    participant S as Express /api
    participant A as Scheduler agent
    participant L as Claude
    participant G as Google Calendar
    U->>S: POST /agents/calendar/parse {text}
    S->>A: parseEvent(text)
    A->>L: interpret "office hours Tue 3pm"
    L-->>A: structured event (+conflicts)
    A-->>U: preview (no write yet)
    U->>S: POST /agents/calendar/commit {event}
    S->>G: create event (only write)
    G-->>U: confirmed
Loading

The preview → confirm → commit split means side-effecting actions (calendar writes, email send) never happen until you approve them.


How it works

  • Single user, local-first. Data lives in a local SQLite file (data.db). Sensitive fields are encrypted at rest.
  • Preview → confirm → commit. Side-effecting actions (calendar writes, email "send", deletes) are split so the server never auto-sends email or posts externally. Email is draft-only unless you explicitly send.
  • Graceful degradation. Each integration and the LLM are optional; the app detects what's configured and falls back to templates/heuristics otherwise.
  • Background agents. On boot, the server starts the Telegram channel (brief push + commands) and the daily-brief scheduler.

API surface (selected)

All routes are under /api. A few highlights:

  • GET /api/health — liveness check.
  • GET /api/me, GET /api/status, GET /api/courses, GET /api/events
  • GET /api/agents/brief — the morning brief.
  • POST /api/agents/calendar/parsePOST /api/agents/calendar/commit — natural-language → event (with conflict detection).
  • POST /api/agents/email/draftPOST /api/agents/email/save-draft / send — draft-only email writer.
  • POST /api/agents/syllabus/parsePOST /api/agents/syllabus/chat / commit — Syllabus Reader.
  • POST /api/courses/:id/docs + POST /api/courses/:id/chat — upload materials and chat with the RAG tutor.
  • POST /api/integrations/canvas/connect / import, GET /api/auth/google — integrations.

Troubleshooting

  • node:sqlite errors / module not found → you're on Node < 22.5. Upgrade Node.
  • Agents give templated, generic output → no ANTHROPIC_API_KEY set. Add one to .env and restart.
  • No courses show up → connect Canvas on the You page, or set CANVAS_BASE_URL/CANVAS_TOKEN, or run npm run seed.
  • Frontend changes not appearing → assets are cache-busted via ?v=N in index.html; a normal reload should suffice (the server sends no-cache).

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors