Status: Public repoBuilt solo

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

GeneratedExecuted and checkedmissprogramsreal outputStudentuploads a sheetExtractPDF, Word, PPT, ZIPContent cacheone call per sheetModel callJSON · failoverRunnercompile + runSandboxno secrets · timeoutsEditable draftcode · input · outputDOCX → PDFcollege templateGeneratedExecuted and checkedmissprogramsreal outputStudentExtractContent cacheModel callRunnerSandboxEditable draftDOCX → PDF
  • 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

1234

captured for the report

Enter PIN: 1234

if it can't run

not run — attach your own screenshot
Figure — what “real output” meansrepo docs Typed input is echoed the way a terminal shows it, using the README's own example.