Project Info
Uni Pilot A small team of AI agents that quietly runs the busywork of college, and gets smarter every time another student uses it.
Inspiration
Every college student loses hours each week to the same low-value busywork: decoding a syllabus to figure out how grades actually work, drafting the "can I get an extension?" email for the fifth time, manually copying due dates into a calendar, doing the mental math on "what do I need on the final to keep my A," and re-asking a question in the class forum that fifty people before you already answered. None of it is hard. All of it is friction. And it's the same friction for everyone in the class, which is the part that always bothered us. We wanted to build something that felt less like another productivity app you have to manage, and more like a small team of people working quietly on your behalf in the background.
What it does
Uni Pilot is a platform where students activate single-purpose AI agents, each owning one slice of academic life. You browse a gallery, see what agents you'd like to use, add them to your homepage, and they start working away for you. Helping pilot your university life. The agents: π Briefer: every morning, a rundown of what's due, what classes you have, and a ranked list of what to actually work on next. βοΈ Messenger: emails your prof for extensions, absences, regrade requests, or intros β with the right tone every time. ποΈ Scheduler: turn "midterm Friday March 14 at 2pm in Wheeler 150" into a real Google calendar event, with conflict detection. π FAQ Finder: surfaces answers from your emails, Reddit, and Piazza so you're not digging through threads. π Syllabus Summarizer: distills any course into a clean overview β grading breakdown, key dates, and Rate My Prof insights all in one place. π Grade Evaluator: tracks your current average, breaks down performance by category, and tells you exactly where to focus your studying. π Assignment Planner: reads the prompt so you don't have to panic β then gives you a concrete game plan for tackling it. And more to come!
How we built it
Backend: Node.js + Express with an embedded SQLite database β a single-origin server that serves both the API and the frontend, so there's zero CORS/proxy setup. Frontend: A lightweight TypeScript app with a hash router, built around a calm, minimal aesthetic where agent activity always reads like a plain English sentence. AI: Anthropic's Claude Sonnet 4.6 powers the agents through a single choke-point LLM module. We lean on forced tool calls for reliable structured output (syllabus extraction, calendar parsing) and plain completions for narrative tasks (briefs, emails, grades). A strict division of labour: the LLM handles language and judgment; deterministic code handles anything that must be correct. Grades are computed by code, not the model. Backward scheduling is code. The model never invents a number or a link. Privacy by design: sensitive fields like grades and email content are encrypted at rest, and the whole app degrades gracefully β pull the API key and every agent falls back to deterministic behaviour instead of breaking. Live integrations: Canvas LMS (auto-import courses and grades), with scaffolding for Ed Discussion, Google Calendar, and email via Canvas.
Challenges we ran into
Trust boundaries. An agent that emails your professor or writes to your calendar is terrifying if it acts on its own. We made a hard architectural rule: agents draft and propose, humans confirm and send. The email agent literally cannot send unless you explicitly tell it to. Keeping the AI in its lane. Early on, the model would happily "compute" a grade β and sometimes get it wrong. We redesigned so the LLM only ever narrates numbers that deterministic code produced. No embeddings endpoint. The Anthropic API doesn't offer embeddings, so for the FAQ's retrieval we built a fully-offline, deterministic bag-of-words hashing embedder β RAG with zero external dependencies. Graceful degradation. Making every single agent work without an API key (so a demo never hard-fails) meant writing a deterministic fallback for each one.
Accomplishments we're proud of
Three working agents, each genuinely useful on its own, sharing one clean data backbone. An LLM architecture where the model never touches anything that has to be correct β so we get AI flexibility without AI unreliability. A setup flow that gets a student from "never seen this" to "active agent" in under two minutes. It actually feels calm. The dashboard makes coursework feel handled.
What we learned
The best place for an LLM in a high-stakes workflow is often narrow: parsing messy human input into structure, and turning structured data back into friendly language β with deterministic code owning everything in between. That boundary is what makes the agents feel trustworthy instead of scary.
What's next
Fully wire the collective-intelligence layer so cross-student answers surface automatically. An agent marketplace where students publish agents for their own courses. Proactive nudges β the brief that messages you when something's about to slip.
UniPilot
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:sqlitemodule. Check withnode -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
- Go to Deploy and click the Syllabus Reader card β its page opens.
- Choose a file (PDF, DOCX, HTML, or
.txt/.md) or expand "or paste the syllabus text." - Click Read syllabus β you'll get a structured summary (grading breakdown, key dates, policies, office hours, materials).
- 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
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
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/eventsGET /api/agents/briefβ the morning brief.POST /api/agents/calendar/parseβPOST /api/agents/calendar/commitβ natural-language β event (with conflict detection).POST /api/agents/email/draftβPOST /api/agents/email/save-draft/sendβ draft-only email writer.POST /api/agents/syllabus/parseβPOST /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:sqliteerrors / module not found β you're on Node < 22.5. Upgrade Node.- Agents give templated, generic output β no
ANTHROPIC_API_KEYset. Add one to.envand restart. - No courses show up β connect Canvas on the You page, or set
CANVAS_BASE_URL/CANVAS_TOKEN, or runnpm run seed. - Frontend changes not appearing β assets are cache-busted via
?v=Ninindex.html; a normal reload should suffice (the server sendsno-cache).
Analysis
View
Metric
- 20
- 13
- 4
- 1
Figures cover GitHub contributors during the hackathon window. A co-authored commit counts in full for each author, so per-member totals add up to more than the whole-team figures.
Technology
- AnthropicIn code
- CSSIn code
- ExpressIn code
- HTMLIn code
- JavaScriptIn code
- SQLIn code
- TypeScriptIn code
- FlaskClaimed
- Node.jsClaimed
- PythonClaimed
- ReactClaimed
7 of 11 appear in the indexed code. 4 claimed on Devpost could not be matched to code, which may simply mean the tool leaves no trace in the repository.
AI coding agents
- Claude CodeCommits
Detected from committed agent config files and commit authorship. Absence of a signal is not proof an agent was unused.
Codebase size
Source size
412 KB
Source files
38
Counts recognized source files only; vendored directories, binaries and lockfiles are excluded, so this is smaller than the repository on disk.
Repository
panda41983/uni-pilot
49 files Β· 550 KB Β· @ c258e99
Structure
API & routing
29 files Β· 59%Request entry points: routes, handlers and controllers.
Application logic
1 file Β· 2%Domain rules, services and shared utilities.
Data & schema
5 files Β· 10%Schema definitions, migrations and data access.
Supporting
Layers are inferred from where files sit in the tree, not from reading the code. A project that names its directories unconventionally will read oddly here β open the file browser to check anything the diagram implies.
Languages
- TypeScript47%
- JavaScript31%
- CSS16%
- Markdown4%
- SQL1%
- HTML0%
Share of indexed source by file size. Binary and vendored files are excluded.
Dependencies
server/package.json
npm Β· 17- @anthropic-ai/sdk
- cors
- dayjs
- express
- googleapis
- mammoth
- multer
- nanoid
- pdf-parse
- rrule
- zod
- +6 more
Declared in the repositoryβs manifests at the indexed commit. A declared package is not proof it is used, and runtime dependencies are listed first.
This projectβs features have not been analysed yet.
Export this project's context (description, README, evidence, key source files) to chat with an AI agent elsewhere.