Opengrader
Grade paper assignments faster, right on your own computer. Print an assignment, scan the stack, and grade it question by question, without sending student work to anyone else's server.
Quick links: Install · Run it · Demo · Tests
Team
| Name | GitHub | |
|---|---|---|
| Andy Cortes | @andycortes23 | andy.cortes@sjsu.edu |
| Arjun Gill | @arjung04 | arjun.gill@sjsu.edu |
| Tommy Liu | @toommyliu | tommy.liu@sjsu.edu |
| Marco Lopez | @TheMarco408 | marco.lopez@sjsu.edu |
Advisor: Dr. Carlos Rojas
Project Description
Grading paper assignments is slow, and the tools that speed it up (like Gradescope) are cloud services that are expensive, rigid, and require uploading student work to a third party. Opengrader is a local, offline-first grading toolkit: it turns a markdown answer key into a printable assignment, splits and reads the scanned submissions, and gives instructors and TAs a fast question-by-question rubric grader in the terminal or the browser. Opengrader does the grading and leaves the AI to you: hand the written answers to the AI assistant you already use (Claude, ChatGPT, Codex, …) in a redacted copy that carries no student names or IDs, or connect a local or cloud model.
Prototype Scope
Works end to end today
| Step | What you can do |
|---|---|
| 1. Answer key | Write a qa.md answer key (format guide), or draft one from an existing Word, text, or PDF answer key with create-answer-key. |
| 2. Printable assignment | Generate assignment PDFs with answer boxes, multiple versions, optional QR codes, and bubble sheets. |
| 3. Scan intake | Check a scanned stack for rotated, blank, or missing pages, split it into one PDF per student, and import phone photos. |
| 4. Reading answers | Crop every answer and read each student's name and ID (Tesseract / PP-OCR, plus an optional local vision model for handwriting). |
| 5. Grading | Grade question by question in the terminal app (images shown inline) or the web app, with rubrics, comments, undo, and anonymous grading on by default. |
| 6. Auto-grading | Score multiple choice, true/false, and numeric answers automatically; an AI model can suggest grades for written answers, which a human reviews. |
| 6b. Your AI assistant | opengrader agent prepare makes a copy with every student as an og-… code (no names, IDs or scans); your assistant transcribes and grades there through opengrader agent commands; opengrader agent apply merges its suggestions back as AI grades for you to confirm. opengrader ai-readme is the page to give the assistant. |
| 7. Hand back | Write grades and comments onto each student's PDF, export a gradebook CSV, or push scores to Canvas. |
opengrader run chains steps 3–6 into one resumable command. The desktop app (opengrader classic) gives you every step as buttons.
Incomplete or rough
- Windows and Linux installers and password-store support have been written but not yet tested on real Windows/Linux machines. macOS is the tested platform.
- Multi-grader web app: Google sign-in and shared workspaces work, but haven't been tried by a real course staff yet.
- Cloud AI providers are opt-in and work, but several hardening items remain (for example, answer crops are not yet masked before a cloud send).
- Handwritten math recognition (
mathextra) is experimental.
Left for the Expo
See What's Next.
System Architecture
Opengrader is a pipeline of small command-line tools that pass plain files to each other (markdown and image crops), ending in a grading app. All the core logic lives in one Python package; the terminal app, the web app, and the CLI are thin front ends over it.
flowchart LR
subgraph Prepare
AK["Answer key<br/>(.md / .docx / .pdf)"] -->|create-answer-key| QA["qa.md"]
QA -->|qa-file generate-template| TPL["Printable assignment PDF"]
end
subgraph Ingest
SCAN["Scanned stack PDF"] -->|scan-check + submission-splitter| SPLIT["One PDF per student"]
SPLIT -->|"submission-extractor<br/>(OCR + optional AI)"| SUB["student.submission.md<br/>+ answer crops"]
end
subgraph Grade
SUB --> APP["Grading app<br/>Terminal (Textual) · Browser (React)"]
QA --> APP
QA -->|automated-grading| SUB
APP -->|grades, comments| SUB
end
subgraph Return
SUB --> OUT["Annotated PDFs · CSV gradebook · Canvas"]
end
TPL -. printed and handed out .-> SCAN
| Component | Folder | What it does |
|---|---|---|
| Core library | src/opengrader/core/ |
All domain logic: answer-key parsing, scoring, PDF generation, OCR, splitting, auto-grading, exports. Never prints or draws UI. |
| CLI tools | src/opengrader/cli/ |
One thin command per pipeline step, all reachable through opengrader <command>. |
| Terminal app | src/opengrader/tui/ |
The Textual grading app plus the Tools & Settings screens. |
| Local service | src/opengrader/server/ |
A FastAPI service bound to localhost that stores a shared grading workspace in SQLite. |
| Web app | src/opengrader/web/ |
A React/Vite browser client for the same workspace. |
| Installers | packaging/ |
Double-click installers and self-updating launchers for macOS, Windows, and Linux. |
| Your AI assistant (optional) | external | Any assistant that can run commands (Claude Code, Codex, Gemini CLI, Cursor, …), working in a redacted packet (opengrader agent). |
| Local AI (optional) | external | An Ollama server you run on 127.0.0.1:11434. Opengrader connects to it but never installs, starts or downloads it (opengrader ai-readme --local). |
Two ways to store grades:
- Folder mode (default): no database. Grades are saved straight into each student's
.submission.mdfile. - Workspace mode: a local SQLite file and a localhost-only service, so the terminal and browser apps (and several graders) can share live grading.
Prerequisites
| Requirement | Version | Needed for | Notes |
|---|---|---|---|
| macOS (recommended), Windows, or Linux | macOS (tested) | Everything | Windows/Linux are untested. |
| Python | 3.12 exactly (>=3.12,<3.13) |
Everything | uv can install it for you. |
| uv | 0.5 or newer (tested on 0.12) | Everything | Python package/project manager. |
| Git | any | Cloning the repo | |
| Tesseract OCR | 5.x (tested on 5.5) | Reading scans | Without it, scans extract to empty answers. |
| Homebrew | any | Installing the above on macOS | |
| Ollama | recent release (tested on 0.23) | Optional: a local model for handwriting reading and grade suggestions | You install and start it yourself; the two default models need several GB of disk. |
| Node.js (includes npm) | 22 or newer (CI uses 24) | Optional: building the web app, once | |
| A scanner or phone camera | — | Bringing in real submissions | Sample scans are included in samples/ so you can try it without one. |
Canvas account + canvas-sak setup |
— | Optional: pushing grades to Canvas | |
| Google Cloud OAuth client | — | Optional: sign-in for the shared web app | Not needed for local use. |
Hardware: any recent laptop works for grading. For local AI, 16 GB of RAM is recommended (Apple Silicon or a GPU makes it much faster).
Which terminal should I use? (any works; some show sharper images)
Opengrader shows each student's scanned answer inside the terminal and picks the best image protocol automatically.
| Image quality | Terminals |
|---|---|
| Full resolution (Kitty protocol) | Ghostty, kitty, Contour |
| Full resolution (iTerm2 protocol) | iTerm2, WezTerm, VS Code* |
| Full resolution (Sixel) | Konsole, foot, mlterm, Windows Terminal 1.22+, Rio, XTerm |
| Coarse preview | macOS Terminal.app, GNOME Terminal, PuTTY, tmux |
In a coarse-preview terminal, press o while grading to open the full-resolution image in your normal image viewer.
* VS Code needs the terminal.integrated.enableImages setting (details).
Check what was detected (and include this in any bug report):
uv run tui --check-graphics
Installation
Option A: Desktop app (easiest, no terminal knowledge needed)
- Download or clone this repository (see step 2 below).
- Double-click
Install Opengrader (Mac).command(orInstall Opengrader (Windows).bat) in the project folder. - An Opengrader icon appears on your Desktop. Double-click it. The first launch takes a minute or two while it installs
uv, Python 3.12, and dependencies; later launches are instant.
See packaging/README.md for details and uninstall steps.
Option B: Developer setup (from a clean Mac)
-
Install Homebrew (skip if you already have it):
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
-
Install the system tools:
brew install git python@3.12 uv tesseract brew install ollama node # optional: local AI and the web app
-
Clone the repository:
git clone https://github.com/SJSU-CMPE-195/group-project-group-14.git opengrader cd opengrader
-
Install the Python packages:
uv sync --all-groups --extra pydantic-ai --extra photos
Extra Adds Needed for pydantic-aiCloud AI clients (Anthropic, OpenAI, Google, …) Cloud AI providers; part of the test suite photosiPhone HEIC photo support photo-importwith HEIC filesmathHandwritten-math recognition (installs PyTorch, large) Reading handwritten math as LaTeX -
Check your setup.
doctortells you what is missing and the exact command to fix it:uv run opengrader doctor
-
(Optional) Set up an AI. Opengrader does not set one up for you. Pick one:
- Your AI assistant (recommended): nothing to install here. See Working with your AI assistant under Running the Prototype.
- A local model, so nothing leaves the computer. Start Ollama yourself, then choose it in Tools → AI models & providers → Open AI setup (
uv run opengrader ai-readme --localprints every step):ollama serve & # start the Ollama server ollama pull qwen3.5:9b # handwriting reader ollama pull qwen2.5vl:7b # grade suggestions
- A cloud provider with an API key: Tools → AI models & providers → Manage providers, opt-in and consented.
-
(Optional) Build the web app (needed once):
npm --prefix src/opengrader/web ci npm --prefix src/opengrader/web run build
-
(Optional) Install the
opengradercommand globally so you can typeopengrader …from any folder instead ofuv run opengrader …:sh packaging/install-command.sh # macOS / Linux powershell -ExecutionPolicy Bypass -File packaging\install-command.ps1 # Windows
Grading with other accounts on one computer (SSH)
Show how to share grading between accounts
When several people grade on one machine, each logged in with their own account:
- Professor (once): put the class folder where every grader can reach it (for example
/srv/cmpe195), make a group for the graders, then share the workspace:sudo groupadd cmpe195-graders sudo usermod -aG cmpe195-graders alice bob # graders (and yourself) opengrader tui /srv/cmpe195/quiz3 # opens it, and starts your Opengrader opengrader share --group cmpe195-graders /srv/cmpe195/quiz3
- Each grader:
opengrader tui /srv/cmpe195/quiz3from their own account. They join the professor's Opengrader, so only the professor's account writes the files, and the history shows who gave each grade.
Graders give grades where there are none and change their own. A change to a grade someone else gave is sent to the professor, who approves or dismisses it with Shift+Q. opengrader share --instructor <login> makes someone an instructor, --trust <login> lets a grader change any grade, and --off stops sharing. Graders can join while the professor's Opengrader runs; it keeps running in the background and stops with opengrader stop. On Linux, Opengrader checks with the system which account each grader really is.
Over SSH, Opengrader asks your terminal (on your own computer) whether it can show images. That works on a slow connection, but you can skip it: put export OPENGRADER_GRAPHICS=kitty (or sixel, iterm2, halfcell) in your shell profile on the server. opengrader tui --check-graphics shows what was detected and how long it took.
In a plain class folder (opengrader classic), each account writes the files itself: the folder must be group-writable (chgrp -R, chmod -R g+rwX, umask 002). Opengrader says when it opens a folder your account cannot write.
Environment variables
None are required for local use. Everything below is optional. Never commit real values.
Web app sign-in (only for shared, multi-grader hosting). Copy .env.example to ~/.opengrader/server.env and fill it in:
| Variable | Purpose |
|---|---|
OPENGRADER_AUTH_ENABLED |
Turns Google sign-in on. Off by default (local use, no sign-in). |
OPENGRADER_GOOGLE_CLIENT_ID |
Google OAuth client ID. Required when sign-in is on. |
OPENGRADER_GOOGLE_CLIENT_SECRET |
Google OAuth client secret. Required when sign-in is on. |
OPENGRADER_SESSION_SECRET |
Random secret that signs login cookies (generate with openssl rand -hex 48). |
OPENGRADER_GOOGLE_DOMAIN |
Google Workspace domain allowed to sign in. |
OPENGRADER_ADMINS |
Comma-separated emails of admins who can create courses. |
OPENGRADER_SECURE_COOKIE |
Use secure cookies when served over HTTPS. |
OPENGRADER_SERVER_HOME |
Folder for the service's data and server.env (default ~/.opengrader). |
AI and app behavior:
| Variable | Purpose |
|---|---|
Provider API key (e.g. ANTHROPIC_API_KEY, OPENAI_API_KEY) |
Key for a cloud AI provider you opted into. You can instead paste it in the app, which stores it in your OS password store (macOS Keychain, etc.), never in a project file. |
OPENGRADER_AI_ALLOW_CLOUD |
Set to 0 to forbid every cloud AI send on this machine (kill switch). |
OPENGRADER_GRAPHICS |
Force a terminal image protocol: kitty, iterm2, sixel, halfcell, or unicode. Skips asking the terminal, so it is also the fastest start over SSH. |
OPENGRADER_TERMINAL_TIMEOUT |
Seconds to wait for a terminal that never answers the image-support question (default 0.5, or 2 over SSH). A terminal that does answer is never waited for longer than it takes. |
OPENGRADER_IMAGE_VIEWER |
Program used by o to open an image, e.g. "feh {}". |
OPENGRADER_HOME |
Which checkout the global opengrader command should run. |
OPENGRADER_PYTHON |
Which Python interpreter the global opengrader command should use. |
Running the Prototype
Try it in 30 seconds with sample data
The samples/ folder has real scanned quizzes. Copy a sample first, since grading writes into the folder:
cp -R samples/cs146-quiz1 ~/Desktop/cs146-quiz1
uv run tui --qa-file ~/Desktop/cs146-quiz1/qa.md --submissions ~/Desktop/cs146-quiz1/student-submissions/
Press enter to open a question, 1–9 to pick a rubric option, j/k for the next/previous question, and ? for every shortcut.
The desktop app (all tools, as buttons)
uv run opengrader classic
This is what the desktop icon opens. Pick a class folder (with a scan and an answer key) on the Start grading card and press Launch Grading. If the folder hasn't been processed yet, Opengrader offers to check, split, and read the scans for you first.
One command: scan in, graded work out
uv run opengrader run path/to/assignment-folder/
Point it at a folder holding the scanned PDF and the answer key (and optionally a roster and a blank template). It checks the scan, splits it, reads every answer, auto-grades what it can, and opens the grading app. Inside the folder it builds student-pdfs/ (one PDF per student; what the split noticed about each one is kept in student-pdfs/scan-notes/) and submissions/. Run the same command again and it picks up where it left off. Add --dry-run to preview the plan, or --llm to let the AI chosen in AI setup suggest grades for written answers (start Ollama first if it is a local one). If that AI can't be reached, the run stops before auto-grading and asks whether to grade without it; in a script, add --grade-without-ai or --no-auto-grade to answer up front.
Run it without uv run (from any folder)
Once the global opengrader command is installed (step 8 of Option B: Developer setup), drop the uv run and run it from any folder:
opengrader run path/to/assignment-folder/
It runs the same command from your checkout, so every flag above works the same. Without the global command, use uv run opengrader run … from inside the repo.
Working with your AI assistant (Claude, ChatGPT, Codex, … with no student names or IDs)
Small local models grade written answers poorly. The assistant you already use does much better, and Opengrader keeps student identities away from it. The assistant always works in its own folder beside the class folder, never in it.
Class folders and workspaces. The same jobs work in both. A class folder (the desktop app's classic mode) uses the Tools card below. In a workspace (opengrader tui, the browser app), press A on the assignment list, or open AI assistant in the browser's sidebar. The copy is made from the workspace's own grades and merged back through its service. There the assistant counts as a grader of its own: it fills answers nobody has graded, and its grade on an answer someone graded after the copy was made waits as a change request you approve or dismiss (Q while grading). A reading it types helps it grade but is not stored, because a workspace keeps the scan's reading. When you accept a fix to the answer key, you choose whether the assignment's qa.md gets it too: writing grades back to files never carries the key.
In the desktop app: Tools → AI assistant. Choose the class folder and it offers only what fits:
| The class folder has | You see |
|---|---|
| A blank assignment, no answer key | Draft a standard key (no AI: every question, its points and the standard rubric, answers blank) and Write the key with my assistant… |
| An answer key with blank answers | Type the answers…, Answers from a list…, or Write the key with my assistant… |
| An answer key and submissions | Grade… and, for questions with no partial credit yet, Draft rubrics… |
Scanning, splitting and reading the scans always stay on your computer: whole pages carry names.
An answers list is a plain text file, one question a line, numbered like the answer form:
1: H2O; Water
2) B
3a. 101
4.
Paris
City of Light
Several accepted answers go on one line separated by ; or | (a comma followed by a space works too when a line has neither, so 1,000 stays one answer), or on lines of their own under the question, as for 4. A line needs 1:, 1., 1) or 1 - to start a question, so a bare 2 is an answer, and a blank line ends a question. From a terminal: opengrader qa-file fill-answers --qa-file qa.md --answers answers.txt.
From a terminal, the same jobs:
uv run opengrader agent answer-key --class-folder class [--source key.docx] # the assistant writes or fills qa.md
uv run opengrader agent use-key --folder class-ai-answer-key --to class/qa.md
uv run opengrader agent prepare --submissions class/submissions --qa-file class/qa.md # grading
uv run opengrader agent prepare --submissions class/submissions --qa-file class/qa.md --rubrics # drafting rubrics
# the same in a workspace: name it and the assignment instead
uv run opengrader agent prepare --workspace course --assignment "Quiz 1"
uv run opengrader agent answer-key --workspace course --assignment "Quiz 1"
Start your assistant inside the folder Opengrader made and ask it to do what AGENTS.md there says (Claude Code reads CLAUDE.md, which points to it). For grading it checks the key with opengrader agent check-key, looks at each answer image, and records transcriptions and rubric choices with opengrader agent transcribe and opengrader agent grade; Opengrader checks every choice against the rubric and works out the points. When the key looks wrong, or a question has no partial credit, it records a fix with opengrader agent suggest instead of acting on it. You accept or dismiss each one (Suggestions… in the app, or opengrader agent suggestions / accept / dismiss), and an accepted fix changes only that question of your key.
Chat apps without a shell (Claude Desktop, ChatGPT) connect to a copy as an MCP server instead (Copy MCP setup, or opengrader agent mcp-config --packet <copy>). The assistant then has no file access at all, only the grading tools.
When it is done:
uv run opengrader agent apply --submissions class/submissions --incoming class-ai-assistant/<name> --yes --delete-copy
# a workspace (accept / use-key also take --key-file update|leave):
uv run opengrader agent apply --workspace course --assignment "Quiz 1" --incoming course-ai-assistant/<name> --yes
Its grades arrive marked as AI grades. In the grading app, v steps through a question's unconfirmed AI grades and y confirms one; picking another rubric option changes it, and the review queue and grade-check flag the low-confidence ones. The three-way merge never overwrites a grade you made, and grade-restore can undo it.
What protects student data: the copy itself, not instructions to the assistant.
- Every student is an
og-…code. The scans, the name and ID crops, and the key that maps codes to students stay in your class folder. - Only the answers the job needs go in: the ones still to grade (
--questionnarrows it further;--with-gradedadds your graded ones as examples), or, for rubrics, the answers to the questions being drafted. - Names and IDs are scrubbed from answer text and comments, and Opengrader refuses to make a copy that still contains one.
- Every answer image is read with Tesseract first. One showing the student's name or ID, or one that cannot be read, stays with you.
- The copy's
.claude/settings.jsonstops Claude Code reading outside it and sandboxes its shell commands. Other assistants have no such file, so start them in the copy. - Tesseract misses messy handwriting, so a name scrawled inside an answer box can still get through.
The copy is still student work: use the account your school approved, turn off training on your data on a personal plan, and delete the copy once it is merged (--delete-copy). uv run opengrader ai-readme is the page to give your assistant.
The web app
uv run opengrader web # starts the local service and opens your browser
uv run opengrader stop # stops the service
From the desktop app you can also tick Show Open in browser under Tools → Browser app and use the Open in browser button.
Running each step by hand (power users)
# 0. (Optional) Draft a QA answer key from an existing key
uv run opengrader create-answer-key --input answer-key.pdf --output qa.md
# 1. Generate the printable assignment
uv run opengrader qa-file generate-template --qa-file qa.md --output-pdf template.pdf
# 2. Check and split the scanned stack
uv run opengrader scan-check --input scans/all.pdf --pages-per-submission 6
uv run opengrader submission-splitter --input scans/all.pdf --output split/ --fix-rotation
# 3. Read each student's answers (add --llm-responses to transcribe handwriting with the AI in AI setup)
uv run opengrader submission-extractor --input split/ --output student-submissions/ --qa-file qa.md
# 4. Auto-grade what can be matched (add --llm for AI suggestions on written answers)
uv run opengrader automated-grading --solutions qa.md --input student-submissions/
# 5. Grade the rest
uv run opengrader tui --qa-file qa.md --submissions student-submissions/
# 6. Send grades to Canvas (preview first)
uv run opengrader canvas-export --submissions student-submissions/ --course "CS146" --assignment "Quiz 1" --dry-run
Find any command and its options:
uv run opengrader --help # commands grouped by workflow step
uv run opengrader commands --all # every command, including the ones the desktop app covers
uv run opengrader help <command> # one command's options
Short aliases: split, extract, auto-grade, answer-key, grade (= tui), pipeline (= run).
Where are my settings stored?
AI settings are saved once in config.json in your user config folder:
- macOS:
~/Library/Application Support/Opengrader/ - Linux:
~/.config/opengrader/ - Windows:
%APPDATA%\Opengrader\
Edit them from the desktop app under Tools → AI models & providers → Open AI setup. Command-line flags override saved settings, which override the built-in defaults. API keys are never stored here; they go in your OS password store.
Testing
Opengrader has ~250 test files run with pytest, plus browser tests run with Playwright. Both run automatically on every push and pull request to main through GitHub Actions.
Run the unit and integration tests (about 4 minutes):
uv sync --all-groups --extra pydantic-ai --extra photos # make sure the extras are installed
uv run pytest
Run just one area (much faster while developing):
uv run pytest tests/unit/core # e.g. only the core library
uv run pytest tests/unit/core/test_curve.py
Run the browser tests (needs the web app built, see Installation step 7):
uv sync --group browser
uv run --group browser playwright install chromium
uv run --group browser pytest browser_tests --browser chromium
What the tests cover:
| Folder | Files | Covers |
|---|---|---|
tests/unit/core/ |
118 | Answer-key parsing and round-trips, scoring, PDF generation, splitting, extraction, auto-grading, AI safeguards (no student names sent to the cloud), exports, backups, encryption |
tests/unit/tui/ |
63 | The terminal app driven headlessly: key bindings, grading flow, screens, startup speed |
tests/unit/cli/ |
36 | Every command-line tool's flags and outputs; the command registry stays in sync |
tests/unit/server/ |
17 | The local web service's API, workspaces, sign-in, folder sessions |
tests/unit/ocr/ |
15 | Page layout detection, OCR, QR codes, bubble sheets |
tests/unit/packaging/ |
5 | Installers and launchers; every runtime dependency ships in the desktop app |
browser_tests/ |
6 flows | Uploading a scan, importing an answer key, saving grades, live updates across tabs, conflict handling, CSV export |
Tests use the real scanned quizzes in samples/ as fixtures.
Demo
Demo video: Coming soon. The link will be added here.
Screenshots
Coming soon. Screenshots of the generated assignment, the scan splitter, a student submission file, and the grading app will be added here.
Technical Stack
| Area | Technologies |
|---|---|
| Language | Python 3.12 (managed with uv), TypeScript |
| Terminal app | Textual, Rich, textual-image |
| Command line | Click |
| Web app | FastAPI + uvicorn, React + Vite + TanStack Router/Query, SQLite |
| PDF processing | PyMuPDF, pypdf, segno (QR codes) |
| OCR and imaging | Tesseract, RapidOCR (PaddleOCR PP-OCR models on ONNX Runtime), OpenCV, Pillow, NumPy |
| AI (optional) | Ollama running local models (qwen3.5:9b, qwen2.5vl:7b); opt-in cloud providers through Pydantic AI |
| Integrations | Canvas LMS via canvas-sak, Google sign-in via Authlib |
| Security | cryptography (AES-256-GCM encrypted backups), OS password stores for API keys |
| Testing and CI | pytest, Playwright, GitHub Actions |
| Hardware | Any document scanner or phone camera; a laptop (16 GB RAM recommended for local AI) |
What's Next
Before the Project Expo on December 11, we plan to:
- Test on Windows and Linux: run the installers, launchers, and password-store support on real machines and fix what breaks.
- Pilot with real course staff: grade a real quiz with several TAs using the shared web workspace and Google sign-in, and fix the rough edges they hit.
- Close the remaining AI safety gaps: mask the name/ID area out of answer crops before any cloud send, and limit the size of model responses.
- Measure accuracy: report how often handwriting reading and AI grade suggestions agree with human graders (using
llm-evalandtranscribe-eval). - Polish the Expo demo: a one-click demo folder, an updated demo video, and a poster.
- Choose and add a license. MIT; see below.
License
Opengrader is released under the MIT License. The third-party packages it uses keep their own licenses, listed in THIRD_PARTY_LICENSES.
Acknowledgments
- Dr. Carlos Rojas, Advisor, for guidance and support throughout the project
- Dr. Ben Reed, for sharing ideas and experiences, and providing valuable feedback
CMPE 195A/B Senior Design Project · San José State University · 2026
Metadata
Release files for opengrader 0.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| opengrader-0.0.1.tar.gz | 4.8 MB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| opengrader-0.0.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 9.5 MB
Release files / opengrader-0.0.1.tar.gz
| Download URL | opengrader-0.0.1.tar.gz |
|---|---|
| Size | 4.8 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6f937f2166a1b517713ab22a98f060f962dd9e2492af73999546ebd0fe6019d8
|
|
BLAKE2b-256 checksum How to use checksums |
6ff9bdacc13f7762e2b04f38794da666f47de0c152080c4ab71c37bdae1283d4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.20 {"installer":{"name":"uv","version":"0.11.20","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / opengrader-0.0.1-py3-none-any.whl
| Download URL | opengrader-0.0.1-py3-none-any.whl |
|---|---|
| Size | 4.7 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
cf9a8c2e5530339e67bda37a76360e38306c347b8ebf0a1512d7f766c2783e72
|
|
BLAKE2b-256 checksum How to use checksums |
55e0e19be99c2aeb050fb9d2299bf9075f97457f23271fc7f8a66841272badc8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.20 {"installer":{"name":"uv","version":"0.11.20","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Security for opengrader 0.0.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.