feat(notebook): add a notebook plugin - #300
Draft
Fan Shangxiang (MartinForReal) wants to merge 1 commit into
Draft
Fan Shangxiang (MartinForReal) wants to merge 1 commit into
Fan Shangxiang (MartinForReal) wants to merge 1 commit into
Conversation
Adds the TauGrid notebook integration as a JupyterLab 4 prebuilt extension plus a Jupyter Server extension shipped inside the tau wheel. The researcher stays in JupyterLab: submit the notebook they are working in, then watch status, logs and a loss curve until the run finishes. The browser never talks to Kubernetes; the server extension drives the Python SDK on the Jupyter Server identity, so the notebook needs no cluster credentials and no tau binary. Surfaces, each where it belongs rather than in one panel: - Left sidebar (taugrid-runs): a run table that loads itself and follows the namespace and queue, a filtered namespace picker that prefers Tau-ready destinations, exact lookup and a portal link. - Main-area tab per run (taugrid-detail): lifecycle phases, admission/pods/ execution tiles, diagnostics, pods, identifiers and the loss curve. Reopening a run reuses its tab. - Logs tab (taugrid-logs): one pod and container, a bounded snapshot. - Notebook toolbar and palette: submit the current notebook, review the resolved plan, then confirm in a native dialog. - About: whether submission is enabled on this server, and why. Server: - _payload.py: the CLI's embedded transport - envelope v2, immutable encoding, 64 KiB encoded environment entry and 1 MiB decoded, digest verified by the tau-payload initContainer. - _notebook_pkg.py: validate the saved notebook, strip outputs and execution counts before measuring, drop approved launcher cells, embed the notebook with the runner and a digest context manifest, and stage chosen files into the working directory so relative imports resolve. - _render.py: renderer parity with cli/internal/rayjobrender - Kueue queue label, tau.azure.com/managed-by, K8sJobMode for plugin submissions so driver output is a readable pod log, and longer retention so a finished run can still be read. - submit.py / _notebook_submit.py: plan-first submission behind TAUGRID_SUBMISSION_ENABLED with an explicit confirm bound to the reviewed manifest digest. - runs.py / metrics.py: run discovery for Jobs and RayJobs with lifecycle phases and owner-UID-scoped evidence, namespace discovery, and bounded loss metrics with explicit truncation reasons. - notebook_files.py: choose which files ship, bounded and refused when a path escapes the notebook directory or the payload ceiling. Choosing files: GET /taugrid/api/files lists the flat source files beside the notebook; the review's "Files to ship" selection embeds them and reports them as includedFiles in the plan. Verified end to end on the CPU profile - the submitter log showed "tg-runner: staged 1 file(s) into /data: nb_helpers.py" followed by HELPER_VALUE 41 / HELPER_OK. Demos and packaging: examples/notebook-ray-cpu-demo.ipynb, examples/notebook-loss-curve-demo.ipynb, examples/notebook-files-demo.ipynb with nb_helpers.py, images/notebook-runtime/Dockerfile for the notebook executor (built offline from vendored wheels, selected with TAUGRID_RUNTIME_IMAGE), and wheel packaging that ships the prebuilt labextension and enables the server extension so a clean install registers it. Verified live against a local JupyterLab and a docker-desktop cluster with Kueue and KubeRay: the loss demo reached SUCCEEDED with real observations and a 40-point curve in the browser, and the browser e2e passes all five journeys (runs sidebar, run detail, loss curve, logs, confirmed submit). This is what caught the empty submitterPodTemplate, which left the K8sJobMode submitter with no /script payload and no /data mount while the RayJob still reported success. Removed as dead weight with the rationale recorded in the design: the branch's uncalled Go TensorBoard renderer and Portal proxy route, the conformance scaffold, a stale executed example, committed notebook outputs, and the superseded ipywidgets-era screenshots. Checks: 233 offline notebook tests, 33 node tests, both frontend builds, ruff, license headers and git diff --check pass; the wheel builds and carries the current sources, both asset locations and the server config. The broader SDK and Portal failures are identical on untouched main and were left alone. Design source, API surface, metrics contract and the whole-PR audit record: docs/design/notebook-plugin.md. Task-oriented docs: site/content/en/docs/examples/notebook-plugin.md.
Fan Shangxiang (MartinForReal)
force-pushed
the
feat/notebook-plugin
branch
from
September 23, 2026 09:35
588e633 to
68fd6bd
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds the TauGrid notebook integration as a JupyterLab 4 prebuilt extension plus a
Jupyter Server extension shipped inside the
tauPython wheel. The researcher stays inJupyterLab: submit the notebook they are already working in, then watch status, logs and a loss
curve until the run finishes.
The browser never talks to Kubernetes. The Jupyter Server extension drives the Python SDK on the
Jupyter Server identity, so the notebook needs no cluster credentials and no
taubinary.The workflow
run name, namespace, queue, profile, payload sizes, excluded cells, submission mode, retention.
Surface placement
Each capability sits on the JupyterLab surface it belongs to, rather than one mega-panel:
taugrid-runs)taugrid-detail)taugrid-logs)The panel uses the TauGrid Portal design system exactly - the same tokens, type scale, cards,
stat tiles, badges, tables, buttons, focus ring and chart treatment.
What is in it
Server (Jupyter Server extension)
_payload.py- CLI-parity embedded payload: envelope v2, immutable encoding, the 64 KiBenvironment-entry cap and 1 MiB decoded ceiling, digest verified by the
tau-payloadinitContainer.
_notebook_pkg.py- validates the saved notebook, strips outputs and execution counts beforemeasuring, drops approved launcher cells, and embeds the notebook with the runner and a digest
context manifest.
_render.py- renderer parity withcli/internal/rayjobrender: Kueue queue label,tau.azure.com/managed-by,K8sJobModefor plugin submissions so the driver output is areadable pod log, and a longer retention so a finished run can still be read.
submit.py/_notebook_submit.py- plan-first submission behindTAUGRID_SUBMISSION_ENABLEDwith an explicit confirm, bound to the reviewed manifest digest.runs.py,metrics.py- run discovery for Jobs and RayJobs with lifecycle phases andowner-UID-scoped evidence, and bounded loss metrics with explicit truncation reasons.
Frontend
Portal and keyboard operable.
step=N loss=Vobservations; a bounded window, not thecomplete history, and it says so. One observation stays a point; nothing is smoothed or invented.
Demos and packaging
examples/notebook-ray-cpu-demo.ipynb(Ray CPU tasks) andexamples/notebook-loss-curve-demo.ipynb(a deterministic 40-step loss curve).images/notebook-runtime/Dockerfile- the runtime image the notebook executor needs, builtoffline from vendored wheels; selected with
TAUGRID_RUNTIME_IMAGE.share/jupyter/labextensionsand enables the serverextension through
etc/jupyter/jupyter_server_config.d, so a clean install registers it.Whole-PR audit and re-implementation
The PR was audited end to end and re-implemented rather than patched. Fourteen findings with
file:lineevidence, the decisions, and a 50-path inventory are indocs/design/notebook-plugin.md. The corrections that matter:review and confirm is rejected instead of silently submitted.
separate policies, so they cannot drift apart again.
replacement pod cannot be read under a stale identity.
preserved; the launcher-cell detection that could discard user code was replaced.
Removed as dead weight, with rationale recorded: the branch's uncalled Go TensorBoard renderer and
Portal proxy route (unbounded reads, non-empty-string-only validation, superseded by the native
extension), the
_conformancescaffold, a stale executed example notebook, committed notebookoutputs, and the superseded ipywidgets-era screenshots.
Live verification
Driven against a local JupyterLab and a docker-desktop cluster with Kueue + KubeRay:
tools/run-cpu-ray-demo.pysubmittedexamples/notebook-loss-curve-demo.ipynbascpu-loss-demo-2on the CPU profileazure.research.cpu.small(queuejobqueue,K8sJobMode,gpusPerWorker=[0]). The submitter ran the notebook, streamed real observations(
step=0 loss=9...step=6 loss=0.086),GET /status?includeMetrics=truereturned a boundedwindow, and the driver reported RESULT SUCCEEDED WITH LOSS.
tools/run-labextension-e2e.mjsdrives Edge through five journeys - open the runs sidebar, open arun detail, render the loss curve, open logs, submit a notebook through review and confirmation.
PASS, with
loss curve points: 40, polyline: 1.submitterPodTemplate: the K8sJobMode submitter had no/scriptpayload and no/datamount, the entrypoint died oncd /data, and the RayJob stillreported success. Now wired and locked by tests.
Checks
python scripts/check-license-headers.pynpm run build:lib/build:labextensionnpm testruff check tau tests setup.pyThe broader SDK (54) and Portal (16) suites are not green, but both failure sets are identical on
untouched
main- pre-existing Windows/environment failures, deliberately not fixed here.Deferred
(the prepared notebook, the runner, and the context manifest); there is no picker yet. The CLI
offers
--extra-script SRC:DEST, a project archive handed to Ray asworking_dir, andimage/PVC sources for anything large. Bringing that choice into the review is the obvious next
step, bounded by the payload caps.
authenticated portal series, and multi-rank aggregation.
behind
TAUGRID_SUBMISSION_ENABLEDuntil a certified image is recorded.Try it
pip install "tau[widgets]" docker build -t taugrid-notebook-runtime:local images/notebook-runtime TAUGRID_SUBMISSION_ENABLED=1 \ TAUGRID_RUNTIME_IMAGE=taugrid-notebook-runtime:local \ TAUGRID_PORTAL_URL=https://your-portal \ jupyter labDesign source, API surface, metrics contract and the audit record:
docs/design/notebook-plugin.md. Task-oriented docs:site/content/en/docs/examples/notebook-plugin.md.