GC CLI Technical appendix
Module map
Piece
Location
CLI group / commands
nuvolos_cli/grade.py → nv_grade, nv_grade_check, …
Wired into root CLI
nuvolos_cli/interface.py (nuvolos.add_command(nv_grade))
Start / stop / execute / distribute
nuvolos_cli/api_client.py
Collect / handback library
external nuvolos_collect
Client SDK
nuvolos-client-api
Orchestrator: run_grade_check
High-level steps:
Validate the environment (API key and teaching Master Instance).
Create a staging run directory under /files/.nuvolos_grade/<run_id>.
Collect submissions (unless skipped), then relabel by student email.
Read the manifest and resolve students.
Process students sequentially, or via a thread pool executor.
For each student, run test_one_student.
Publish per-student artifacts into the handin/handback structure.
Batch handback via nuvolos_collect.handback.
Print summary counts. (By design, there’s no central grade_run_*.json file.)
Per-student: test_one_student
preflight list_apps → start_app → wait_for_app_running → execute_command_in_app(wrapped_command) → wait for done-file / exit sentinel (GRADE_EXEC_TIMEOUT_SECS) → pull_student_logs_to_instructor (distribute_content: student → instructor) → stop_app (finally)
Command wrapping (completion protocol)
Nuvolos’s default stdout capture is unreliable for multi-segment shell sequences and redirections, so Grade Check owns its own logging:
mkdir -p "$work" { <your command> } > output.log 2>&1 ec=$? printf '%s' "$ec" > .cmd_done : > .cmd_exit.$ec exit "$ec"
Completion is detected by polling the files API for .cmd_done / .cmd_exit.<code>. These are pure shell markers, so detection works even without Python present in the image.
Log pull path
Confirm output.log exists on the student’s files area.
Optionally stage or copy it into the work directory on the student side.
Run distribute_content from the student’s development snapshot to the instructor Instance.
Read the bytes on the instructor’s filesystem, keeping excerpts (up to roughly 5 MB) for terminal display.
Copy the files into handin/handback _grading/ and set them to read-only.
Manifest item → Instance slug resolution
Resolution follows this priority order:
Parse .../handin/<instance_slug>/... from the item’s src.
Otherwise, use the basename of target.
Otherwise, raise an error.
Parallelism semantics
if parallel > 1 and not continue_on_error and not dry_run: force parallel = 1
Sequential mode stops early on the first failure, unless --continue-on-error is set. Parallel mode submits all runnable students and gathers the results as they complete; there’s no mid-pool cancellation.
Dependency note
pip install nuvolos-cli # separately: pip install git+https://github.com/alphacruncher/nv-collect.git
nuvolos_collect is installed separately because git-URL extras can’t be published to PyPI, and its historical click pin has, at times, conflicted with the click version required by nuvolos-cli. If you hit an installation error related to click, check both packages’ current dependency constraints rather than assuming these exact version numbers still apply.
Related but separate: evaluation sessions
A nuvolos grade session-style flow — starting many Applications, holding them running, and bulk-stopping them later — is planned but not part of grade check. Don’t repurpose check’s defaults for long-running, interactive evaluation.
Last updated
Was this helpful?