Use notebooks and kernels
Connect exact block revisions and execution outputs without making a notebook file canonical.
Outcome
You can save immutable block revisions, queue an exact revision for filtered kernel execution, and
follow normalized outputs and captured values without treating the browser layout or an .ipynb
file as canonical state.
Prerequisites
Open the notebook section of the deterministic research story.
Steps
- Read the document, block, and current block-revision IDs. Saving a changed block sends the base revision and document structure version; a conflict preserves the draft instead of rebasing it silently.
- Run a clean code block through the authenticated execution command. The command queues that exact
revision. PostgreSQL claims the document's canonical runtime-session lease and generation before
the worker provisions compute. Local development may use
KERNEL_RUNTIME_PROVIDER=local_docker; every non-local profile requiresdaytona. - In production, the worker provisions one dedicated Daytona sandbox for that document runtime-session generation and starts the private JSONL sidecar inside the repository-digest-pinned runtime image. This human-notebook sandbox is separate from every Pi attempt sandbox, and an API handler never calls the compute provider directly. An unconfigured or stale provider fence rejects execution explicitly.
- Inspect the execution state and ordered normalized outputs. Small text, stream, error, JSON, image, sanitized Markdown/SVG, sandboxed HTML, and inline-only Vega-Lite outputs render in the workbench. Externalized output remains a canonical artifact and downloads through the authenticated artifact boundary. HTML cannot run scripts or share the application origin; Vega-Lite receives no external loader and has an adjacent readable specification.
- Open the notebook's Variables tab to inspect the canonical definitions and current live values available to it. Select a row to see sensitivity and exact provenance. Values produced by the selected execution or block revision are labelled in the table; other rows remain explicit project values rather than being presented as kernel memory. Sensitive and restricted values stay hidden until you choose Reveal value. Use Manage project variables for definition, manual value, and retraction commands. The trusted post-execution hook can capture an allowlisted kernel value with its execution, block revision, environment, and inputs.
- Follow an artifact or evidence reference to its exact revision. Never infer evidence from the newest mutable block or from untracked terminal work.
- Open the terminal only when the selected execution exposes a current runtime session. The browser obtains a short-lived, one-use ticket and never receives a Jupyter connection file or speaks the raw protocol. The terminal is labelled Untracked exploration and cannot produce citable output until work is captured through a canonical execution or reviewed artifact.
- Import and export notebooks through the bounded nbformat 4
.ipynbendpoints. Import creates a new document; export writes a deterministic snapshot. Neither makes the file the live database.
Opening, splitting, moving, or collapsing a notebook pane changes browser-local workspace state. The workbench separately persists the appearance and expanded side-region widths through project settings; neither kind of chrome change creates a notebook revision. The current notebook toolbar supports selected-block save/run, add/move/delete, patch review, import/export, canonical variable inspection, and an eligible terminal. Choose Attach agent to open inspector chat against the exact selected block; this changes the inspector context and does not invent a durable notebook-to-attempt relation. The action remains disabled when the notebook renders outside the workbench host. Run all queues every saved code block in document order only after the complete canonical block page has loaded; unsaved drafts are not part of that execution.
CodeMirror supplies editor-local Python language support, bracket closing, and typing-time autocompletion for the active block. Those suggestions are an editing aid only: they do not call an agent, discover trusted tools, execute code, or grant network authority.
Attempt scratch Python is different
Each research or verification attempt has a local python tool backed by one persistent,
Jupyter-compatible Python sidecar in that attempt's own sandbox. Variables survive across calls in
one uninterrupted process. A canonical pause preserves the sandbox filesystem, rematerializes the
frozen context and skills, and starts fresh Pi and Python processes on resume; save reusable values to
workspace files and reload them instead of relying on kernel memory. Scratch state does not appear as
a canonical notebook execution, block output, project variable, artifact, evidence reference, or
claim until the attempt explicitly publishes immutable output and records its provenance through
Lumen's trusted research boundary. Planning attempts have no local Python tool.
Verify
The execution points to a block revision and source hash, not only a mutable block. The filtered
JSONL runtime protocol keeps Jupyter behind the private sidecar and rejects stdin, unsupported
messages, raw buffers, wrong session identities, unsafe connection files, output after idle, and
oversized staged output. Display updates and clear requests append normalized records whose visible
result is resolved in sequence; large output is staged and verified rather than embedded without a
bound. PostgreSQL remains canonical for both sandbox leases and runtime-session generations; provider
state never becomes the only record of a running kernel. For an attempt, verify the frozen runtime
manifest includes local python and its hard limits before accepting scratch-runtime telemetry; for a
human notebook, verify the separate document runtime-session generation instead.
Recover
If source and output identifiers disagree, stop using the conclusion and preserve the run for
diagnosis. Interrupt or restart a tainted kernel through the worker-owned scoped runtime control path;
the filtered runtime holds an early interrupt until the correlated execution-input event proves the
code has started, so the signal cannot disappear between busy and execution. The browser has no
raw Jupyter escape hatch. If the worker or runtime dies, the current session
generation becomes an immutable failed generation. Recovery claims a fresh generation and provisions
a new sandbox; it never resurrects the old lease or relabels its output as current. Never relabel
output from one revision as if another revision produced it.