Lab-Forge
Experiment sheet in, finished lab report out
Upload an experiment sheet and get a finished lab report: AI-written code that is actually run, real output screenshots, and a Word/PDF export in your college's format. Supports Java, Python, Node.js, React, HTML and C/C++, with every program run in a scrubbed environment under time and resource limits.
- Built with
- PythonFastAPITypeScriptReactJavaDockerGemini APIpytest
- Type
- Personal project
- Source
- Public on GitHub
How it decides
Experiment sheet → report with real output
- person
- guesses / untrusted
- decides
- process
- storage
- third party
- trust boundary
Boundary Where guessing stops and something deterministic decides.
- Output is never invented: every program is run, and anything that can't run is marked “not run”. code
- Programs run with a scrubbed environment — no API keys — and are killed as a process group on timeout. code
- A Docker backend runs each program in a throwaway container with no network; the free-tier live app can't use it and relies on loopback-only guards. code
The drawing, in words
Lab-Forge: Experiment sheet → report with real output. Left of the redline is “Generated”; right of it is “Executed and checked”.
- Student — uploads a sheet (Generated)
- Extract — PDF, Word, PPT, ZIP (Generated)
- Content cache — one call per sheet (Generated)
- Model call — JSON · failover (Generated)
- Runner — compile + run (Executed and checked)
- Sandbox — no secrets · timeouts (Executed and checked)
- Editable draft — code · input · output (Executed and checked)
- DOCX → PDF — college template (Executed and checked)
Connections
- Student → Extract
- Extract → Content cache
- Content cache → Model call (miss)
- Model call → Runner (programs)
- Sandbox → Runner
- Runner → Editable draft (real output)
- Editable draft → DOCX → PDF
The problem
- Lab reports need code, real program output and a fixed college layout. Pasting AI output by hand produces screenshots of programs that never ran. repo docs
What was built
- Ingestion of PDF, Word, PowerPoint, text or a .zip of a project folder, condensed before a single structured model call. repo docs
- A runner for Java, Python, Node.js (with a throwaway in-memory MongoDB), React (bundled with esbuild, screenshotted in headless Chrome), HTML and C/C++. code
- Template-driven DOCX output in the Chandigarh University CSE layout, PDF via LibreOffice or Gotenberg, a CLI and a React editor where the live page preview is the editor. repo docs
My part
- Built solo — every commit is mine. commits
Limits and open work
- Languages outside the supported set get the code and an empty slot for the student's own screenshot. repo docs
- Render's free plan can't nest containers, so the live app runs programs in-process behind loopback-only network guards. The Docker-per-run backend exists but isn't used there, and the project's security doc lists what a deliberately hostile program could still do. repo docs
- Hosted on Render's free plan, which sleeps when idle; a scheduled Worker keeps it awake during the day only. repo docs
- Students can edit the draft and attach their own screenshots for programs that couldn't run. repo docs
Decisions worth knowing
Run it or say so
Every program is compiled and run. Anything that can't run is reported as “not run” so the student attaches their own screenshot — output is never invented.
code
Generated code gets no secrets
Child processes get a minimal environment with no API keys, a temp folder as HOME, a timeout that kills the whole process group, and CPU/file-size limits through prlimit on Linux.
code
One model call per sheet
Results are cached by content, so a whole class uploading the same sheet costs one call; changing a name or date never calls the model. Free-tier providers fail over in a configured order.
repo docs
A closer look
stdin given to the program
1234captured for the report
Enter PIN: 1234if it can't run
not run — attach your own screenshot