← Back to Blog
Tutorials & How-Tos

Jupyter Notebook Handoff: Saved Outputs, Kernel State and Fresh Runs

A saved notebook, a running kernel and a fresh sequential run provide different kinds of evidence. Use this Jupyter notebook handoff guide to choose the right action, preserve the original and explain what your colleague can actually verify.

Written by Hamza Diaz
November 1, 202610 min read60 views

Imagine receiving a Jupyter notebook with a convincing chart. The parameter cell above it has changed since the chart was generated. This is a hypothetical handoff, but the question is practical: what does the file actually prove?

The chart may be useful. It just cannot establish which saved source produced it. Before pressing Run All, decide what your colleague needs to know. Perhaps they need a fresh sequential run. Perhaps they only need the original notebook, with a clear explanation that its outputs have not been regenerated.

This guide uses the Three-State Handoff to make that choice explicit. It is an editorial checklist, not a Jupyter feature or certification.

Separate the notebook file, the live kernel and rerun evidence

What an .ipynb file preserves

The notebook format specification describes code cells containing source, outputs and an execution_count that is an integer or null. Saving these fields preserves a document. It does not create an audit trail linking every visible result to the current source.

That distinction is the starting point for Optijara's Three-State Handoff. Treat the saved document as one piece of evidence. Investigate the running kernel separately, then record whether a fresh sequential run was attempted. Until you know how a chart was generated, it tells you about the saved document rather than a verified rerun.

What belongs to the running kernel

JupyterLab documents attaching a code console to a notebook kernel. Kernel memory can therefore include interactive work outside the notebook's visible sequence. Those dependencies deserve attention before another person tries to run the file.

Closing the tab does not resolve them. JupyterLab's Running panel documentation says the underlying kernel continues running after the notebook closes. Record the selected kernel and any relevant interactive context instead of treating a closed document as a reset.

What a fresh sequential run can establish

A completed, reviewed fresh-kernel sequential run supports a bounded statement: the code cells included in the reported scope executed in order in the recorded context, with the reported outcome. Record omissions rather than implying every cell ran. The PLOS notebook-sharing guidance recommends restarting and rerunning cells as a check for accidentally missing steps, not as certification of the analysis.

Keep that statement narrow. A fresh kernel can still use the same environment and files. External services also remain outside the notebook. Even successful execution leaves the analytical question open: a calculation can run without producing a correct or meaningful answer.

Walk through a hypothetical out-of-order notebook

An edited parameter beside an older chart

In this unexecuted example, an analyst runs a parameter cell and uses it to prepare data for a chart. Later, they edit the parameter's source text and save the notebook without rerunning the dependent cells.

The recipient sees the new parameter beside the older chart. Nothing in this example supplies observed output values, execution counts or errors. It illustrates an evidence gap: the chart alone cannot establish whether the saved parameter produced it.

Questions to resolve before accepting the handoff

Start by identifying the saved source version and the inputs the sender can name. Ask whether any cells depended on console state. Most directly, were the outputs regenerated after the last relevant edit?

Execution counts may give you a reason to investigate. They do not answer those questions on their own. If a rerun is authorized and practical, document the attempt. Otherwise, preserve the supplied file and say that its outputs were not regenerated.

A failed rerun with a clear record is a better handoff than a polished notebook with an unknown execution history. The recipient needs enough information to decide what to trust, including where that trust should stop.

Choose the right JupyterLab action before sharing

Clear outputs, restart, or run all?

The JupyterLab command registry lists separate operations. Clearing uses notebook:clear-all-cell-outputs; restarting uses notebook:restart-kernel. Run All uses notebook:run-all-cells, while restarting and running uses notebook:restart-run-all.

ActionOutputsKernel and executionHandoff check
Clear outputsRemoves cell outputs from the document in memory; save to persistDoes not restart or execute sourceExplain why outputs are absent
Restart kernelDoes not itself regenerate stored outputsRestarts kernel; does not rerun sourceDo not present existing outputs as fresh
Run AllProduces outputs as cells executeRuns cells without requesting a new kernelExisting kernel state may matter
Restart and Run AllRegenerates outputs for cells reached during executionRestarts, then runs sequentiallyObserve completion and inspect failures
Execute and save separatelyPreserves whatever outputs the attempt producedFreshness requires an explicitly fresh kernel and recorded contextInspect outcome and verify the saved artifact

Match the action to the evidence you need

The same command registry also lists the combined restart-and-clear action, notebook:restart-clear-output. A restart does not automatically mean outputs were cleared. Nor does a command name tell you that execution succeeded.

For a fresh-kernel sequential check, choose Restart Kernel and Run All Cells deliberately. Wait for execution to finish, then inspect exceptions and the relevant results before saving. If execution fails or stops early, report that outcome. Saved errors can help a colleague diagnose a problem; they cannot serve as evidence of a successful run.

Use the Three-State Handoff playbook

Inspect and authorize the rerun

Preserve the received notebook before editing it. Review the cells for operations that touch files or databases, and check for network requests, sensitive inputs and paid service calls. Jupyter Server security guidance makes the underlying capability clear: Jupyter provides arbitrary code execution. Opening a notebook is not permission to run everything inside it.

Choose isolated nonproduction inputs and avoid live secrets. If dependencies are missing or an external write is unapproved, leave the rerun blocked and explain why. Do not relax the execution boundary just to obtain a passing result.

CheckpointPractical requirementRecord if unavailable
OriginalPreserve the received source artifactExact source identity unknown
AuthorizationReview operations and approved inputsNot rerun and reason
EnvironmentIdentify kernel, dependencies and working directoryMissing context explicitly
InputsIdentify accessible data and relevant servicesAccess restrictions or unknown versions
OutcomeInspect completion, errors and relevant outputsFailed, incomplete or not attempted
DeliverySave a reviewed copy separatelyArtifact missing or save failed

Record the context and execute deliberately

Record the notebook's identity and selected kernel. Include the working directory and dependency versions, or an environment specification where available. Identify the inputs and relevant model or service versions. Mark unknown details as unknown; a filename and kernel name are only a small part of the context.

For a notebook that uses Polars, choosing between Polars collect and sink_parquet addresses a related artifact decision. An in-memory result and a written dataset are different deliverables. State which one this notebook needs without treating the related guide as validation of its execution.

Database-writing cells need a separate transaction review. The DBeaver Save vs Commit guide explains the distinction in a database client. Carry that question into the notebook review: saving the notebook does not establish that a database transaction was committed or safely rolled back.

The following flow is a planning aid. It does not record an observed execution.

flowchart TD A[Inspect notebook] --> B{Safe and authorized?} B -->|No| C[Record no rerun] B -->|Yes| D[Record context] D --> E[Fresh kernel run] E --> F[Inspect outcome] F --> G[Save separate artifact] C --> H[Report limits] G --> H

Review, save separately and state the limits

Save the reviewed executed copy to a distinct destination and keep the original. Check that the saved copy is the artifact you intend to deliver. An execution command returning is not enough, and a save failure needs its own status even if execution completed.

The measurement plan below records evidence rather than scores. It asks what happened and what the recipient can inspect, without inventing performance results.

QuestionEvidence to collectBoundary
What was attempted?Source identity and rerun scopeNot an originality or correctness check
Did execution complete?Observed completion and exceptionsNot a performance benchmark
What was delivered?Saved artifact identity and review statusNot proof every widget renders
What remains unknown?Missing inputs, versions or checksNot universal reproducibility

A machine-readable summary can keep the record consistent. This specimen is illustrative; its placeholders are not execution evidence.

{
  "framework": "three-state-handoff",
  "example_only": true,
  "source_artifact": "not-recorded",
  "execution_context": "not-recorded",
  "rerun_status": "not-recorded",
  "saved_artifact": "not-recorded",
  "limitations": ["no-execution-evidence"]
}

Replace a placeholder only when you have observed or supplied evidence for it. Include the rerun scope alongside the actual outcome. If no executed artifact was saved, make that absence explicit rather than letting the recipient infer that a file must exist.

Plan nbclient execution without overstating automation

Execution context and error policy

This section describes an automation design based on documentation. It is not a runnable implementation. No notebook execution or dependency installation was performed for this guide. No AI API calls were made.

The nbclient execution guide shows configuring NotebookClient with a selected kernel and execution directory before calling execute(). Read its settings carefully. The example timeout=600 governs cell execution, not the whole job. Neither kernel_name='python3' nor the notebooks/ directory is a universal recommendation.

The nbclient error-handling guide documents allow_errors=False as the default. With allow_errors=True, execution can continue through cell exceptions. Decide which errors make a handoff unacceptable before scheduling automation. Reaching the last cell is not, by itself, a pass.

An acceptance decision should distinguish an expected exception from an unexpected failure. If your policy permits an error, record that policy and review the resulting notebook against it. Do not quietly change the policy after a run fails. The handoff should let another person understand the decision without reconstructing it from logs.

Saving output is a separate responsibility

In the documented programmatic workflow, nbformat.write saves the notebook separately from execution. Plan a destination that preserves the original, and report persistence failures independently. If you intend to claim fresh-kernel execution, require an explicitly fresh, owned kernel rather than leaving freshness assumed.

The nbclient widget guidance draws another useful boundary: execution does not render widgets against a browser. Stored widget state therefore cannot establish that an interactive output works in the intended viewer. Check those outputs there, or list them as untested.

Avoid the mistakes that a clean rerun cannot fix

Common handoff mistakes

A saved plot is easy to mistake for current execution. An undocumented console variable is harder to spot, but it creates the same practical problem: the recipient must guess how the result was produced. Treating Run All as a reset adds another unsupported assumption.

Overwriting the received notebook removes the comparison point. Omitting failed cells hides evidence the next person needs. Preserve both the source and an honest account of the attempt, even when the result is untidy.

Notebook Trust answers a different question. JupyterLab's trust documentation concerns HTML sanitization and displaying interactive outputs. Read alongside the server security model, it explains why trusting a notebook does not sandbox its code or validate its analysis. Making blocked rich output appear is not a reason to trust an unfamiliar notebook without review.

Limits of reproducibility, trust and external services

The 2019 PLOS article Ten simple rules for writing and sharing computational analyses in Jupyter Notebooks offers methodological background on documenting dependencies, data and analysis steps. Use it in that role. It is not evidence of a current product release or an Optijara deployment.

Research references have their own place in the handoff. Preserving research references with Zotero can help with bibliographic traceability, while leaving the calculations and execution to be checked separately.

A later run may use different dependencies or inputs. Random state and external services also belong in the reproducibility discussion, especially where a model identifier does not guarantee identical future responses. Document what you know rather than promising that the notebook will reproduce everywhere.

Rerunning also has an operational cost. Review service charges and privacy before execution, and keep private inputs or credentials out of the handoff record. Share restricted context through approved access controls. The useful deliverable is a precise account of what was attempted, with enough context to assess the result and clear limits on what remains untested.

Key Takeaways

  • 1Saved outputs, live kernel context and fresh-run evidence answer different handoff questions.
  • 2Clearing outputs, restarting and running all cells are distinct operations, not interchangeable resets.
  • 3Preserve the received notebook and authorize execution separately from opening or trusting it.
  • 4Inspect the actual outcome and save a reviewed executed copy separately when a rerun is appropriate.
  • 5Record the source, kernel, working directory, dependencies, inputs, error policy and missing context.
  • 6A successful fresh-kernel run does not prove analytical correctness, safe code or universal reproducibility.

Conclusion

A notebook handoff should let the next person tell what happened without guessing. Keep the saved document separate from what you know about the running kernel. If a fresh sequential run is authorized, inspect the outcome and save the executed copy separately. If it fails, stops early or cannot be attempted, say so.

The Three-State Handoff gives that report a structure. It does not certify the analysis: even a completed rerun remains evidence within a documented environment, with any missing context and untested outputs still to resolve. If your team needs a tailored checklist, discuss your notebook handoff requirements with Optijara.

Frequently Asked Questions

Do saved Jupyter notebook outputs prove the current code was run?

No. A notebook can preserve outputs alongside source that has since changed. Visible results and stored execution counts alone do not establish a recent sequential run of the saved source. Ask which source and inputs produced the supplied outputs.

Does closing a JupyterLab notebook stop its kernel?

No. JupyterLab documents that the underlying kernel continues running when the document closes. Manage the kernel separately through the appropriate controls, including the Running panel. Closing a view is not evidence that its execution state was reset.

Is Run All the same as Restart Kernel and Run All Cells?

No. Run All executes cells without itself requesting a new kernel. Restart Kernel and Run All Cells adds the restart. Observe completion and inspect errors before reporting the outcome; the operation still uses the selected environment rather than proving independent reproduction.

What should accompany a notebook executed with nbclient, and what does success establish?

Include the preserved source, a separately saved executed artifact when available, kernel and working-directory details, dependency and input references, the error policy and actual outcome. Identify missing context and outputs, such as interactive widgets, that were not checked in a browser. A completed fresh-kernel run supports a bounded execution statement in that documented context, not analytical correctness or reproducibility everywhere. See the [nbclient execution guide](https://nbclient.readthedocs.io/en/latest/client.html) and [PLOS notebook-sharing guidance](https://journals.plos.org/ploscompbiol/article?id=10.1371/journal.pcbi.1007007).

Does trusting a notebook make it safe or validate its results?

No. Trust concerns handling of notebook outputs. It does not sandbox arbitrary code or establish analytical correctness. Inspect unfamiliar notebooks and authorize execution separately. Trusting a notebook just to display blocked output is not a substitute for that review.

Sources

Share this article

Hamza Diaz

Written by

Hamza Diaz

Hamza Diaz is the founder of Optijara, where he builds practical AI agents, automation systems, and Copilot workflows for service businesses. He writes about AI operations, agent strategy, and real-world implementation for teams that want usable systems instead of hype.