Appearance
Local Python workflows
The viewer's Workflow tool is a React Flow editor for a versioned, typed DAG. Python is optional for viewing/annotation and required only to execute workflows. For a paired workflow, captured WSI pixels travel directly from the browser's local reader to the loopback companion rather than to a remote service.
Start a workstation runtime
This package is not yet published. From this repository:
sh
python3 -m venv .venv
. .venv/bin/activate
pip install -e '.[workflows]'
microscope serve
# For a viewer served from another HTTPS origin, explicitly allow that exact origin:
microscope serve --origin https://your-viewer.exampleAfter publication the corresponding install is pip install "microscope-io[workflows]". Base microscope-io can start/discover/pair the companion without importing scientific libraries. The optional workflow extra adds NumPy for array execution; individual node packs supply their own algorithm/model dependencies in separate environments.
Open a slide, select Workflow, and enter the short-lived code printed by your local terminal. Allow local-network access if your browser requests it. Pair only a viewer origin you trust: paired workflows execute Python with your filesystem permissions. Closing the workflow dock preserves an active job; Cancel stops it. The workflow console displays progress and the latest 200 lines / 32 KiB of Python stdout/stderr, including output forwarded from an installed pack's isolated process. These logs are returned only through authenticated localhost job polling and expire with the retained job; they are not uploaded. Closing/replacing the slide cancels its job. Normal viewing works with no companion installed.
Choose an example, or drag installed nodes from the searchable library. Examples that reference a missing pack remain visible and report which node is unavailable. Install/register the reviewed pack and reconnect to refresh the catalogue. Connect matching data types, select nodes to configure them, and Run. Completed mask/probability/instance-label outputs use Add to Layers; these are ordinary raster layers, with normal visibility, opacity, removal and project saving. Measurements have JSON export; terminal RGB/grayscale arrays have NPY export. Intermediate arrays stay local and are released after their last consumer.
Select a connected group of at least two processing nodes and choose Create Node from Selection to turn it into a reusable composite. Double-click it to edit the nested graph; breadcrumbs and Back return to its parent. Composite Input/Output boundary nodes declare typed public ports. Inside a local composite, Expose on composite node publishes a child setting and binds it to that inner node. Ungroup expands a local composite back into the parent graph and preserves its current exposed parameter values. WSI and layer source nodes stay at the workflow root so execution snapshots local inputs consistently. Installed package composites are read-only; Fork and Edit creates a local copy. Root Run executes the recursively expanded graph in Python. Internal progress and runtime failures roll up to the parent composite node.
Sources and coordinates
Sources support viewport, selected ROI bounding rectangle, explicit level-0 rectangle, or bounded whole-slide overview. ROI source is the rectangle enclosing the ROI, not an implicit polygon crop. Actual openslide.mpp-x and openslide.mpp-y calibrate sampling. Objective labels are never used. Choose the working MPP explicitly; the browser selects a suitable pyramid level and reads bounded strips, yielding to viewport reads/gestures.
Inputs are at most 4,194,304 RGB pixels. Finer-than-native resolution is rejected. The output grid uses the requested physical spacing on both axes; less than one output pixel may be cropped at the right/bottom edge to keep exact spacing. Geometry carries level-0 bounds, X/Y MPP and array shape across every spatial edge. Shape changes and mismatched spatial inputs fail rather than silently misaligning outputs.
Raster and vector layer sources use typed inputs (mask, probability, labels, gray, roi) and carry their original geometry. Geometry is WSI level-0 pixels plus X/Y MPP, array shape, an explicit pixel-to-level-0 transform, resolution kind, and optional valid-data bounds. GeoJSON polygon coordinates use this WSI coordinate system, not geographic longitude/latitude. The viewer snapshots selected layers before execution; a deleted/unavailable reference fails before starting. Portable workflows omit layer IDs and contents.
Viewer Run supports bounded regions/overviews and a real whole-slide tile path. Authenticated /v1/workflows/plan expands composites, validates installed contracts, separates an optional overview-mask gate, and returns a tile-local execution segment. The browser runs the overview once, filters row-major cores with its mask, sends at most eight source inputs per batch (four RGB+mask pairs when gated), executes real Python graphs, and assembles one sparse native raster layer per terminal. Inputs/jobs are removed between batches. Source reads preserve actual X/Y MPP and padded geometry; ordinary viewport reads take priority. No second WSI reader or OS source path is required.
Tiled outputs are limited to 1024 total cores / 128 MiB encoded NPY payload. Exceeding a bound fails explicitly without installing a partial layer. Add to Layers then Save beside slide persists version-3 chunk descriptors and immutable NPY cores. Masks, probabilities and uint32 labels retain native visibility/opacity/removal/reopen behavior. Probability merging uses unique core ownership; biological instance fragments are not reconciled across cores. Global label offsets remain deterministic across batches. Models are reused within each batch; model sessions restart between batches. This is a functioning bounded whole-slide V1, not unlimited whole-slide inference or validated biological stitching.
The OpenCV pack provides mask-to-ROI, ROI-to-mask, probability threshold, ROI Boolean operations, and ROI masking. Contour conversion preserves holes and disconnected components, bounds/simplifies vector output, and maps pixel contours to level-0 coordinates. Keep large masks rasterized when polygon conversion would be excessive.
microscope.nodes.tiling.schedule_tiles creates deterministic row-major tiles and can skip cores outside a supplied ROI mask or below a coverage threshold. Reads include overlap/context, while every output pixel has one half-open core owner. stitch_tile_arrays yields bounded sparse core chunks for masks, probabilities, and labels, without a WSI-sized output array. Probability output uses core ownership (no blending). job_worker gives tile-local instance labels deterministic job-global uint32 IDs in tile order; overlap reconciliation helpers are available for predictions retained with overlap, but the current worker crops overlap before output and therefore does not join cross-core fragments. This avoids local-ID collisions and completion-order variation, but can leave one biological object split; it is not a claim of perfect biological stitching. Vector features are not merged by this helper.
Use Text("", portable=False) for a private path or credential parameter: it remains local and is omitted from saved/exported graph parameters. Parameters: Float, Integer, Boolean, Text, Enum, with default, label, help text, min/max/step and enumerated choices. The viewer generates controls from the same descriptors. Ports/parameters must use valid Python identifiers and must not overlap. Node errors carry a stable code/message/node identity; dependency, weights, physical alignment and memory failures are actionable.
self.context.geometry contains the current spatial grid. self.progress(fraction, message) reports node progress. Cooperative nodes check cancellation; the parent also kills the entire job process group for Cancel/deadline on POSIX, including uncooperative native work.
Execution and portability
The engine validates required inputs, parameters, types, branching and multiple inputs; cycles are rejected. It executes topologically, sequentially within one job. Browser source nodes run in the companion process; consecutive nodes in the same approved pack reuse that pack's child interpreter. Crossing environments serializes bounded NumPy NPY files (allow_pickle=False) and JSON descriptors. No Python objects/pickle cross environment boundaries. Intermediate arrays are released after their last consumer, with a 256 MiB aggregate intermediate bound.
Workflow JSON: format: "microscope-workflow", schema_version: 1, name, nodes (stable type/version, parameters, canvas position, optional pinned model descriptor), connections (source/target and port names), required pack identity/version/exact commit/HTTPS URL, and optional local composites definitions. A composite declares typed inputs/outputs, parameter descriptors/bindings, and either a graph or enum-selected graph branches. Boundary nodes are part of the editable definition. Runtime expands definitions into namespaced ordinary DAG nodes before graph validation/execution; recursive references, malformed boundaries, type mismatches, unsupported nodes and excessive depth/size are rejected. Only the selected enum branch is expanded. Current bounds are eight nested levels, 64 expanded nodes, 256 expanded connections and 256 KiB workflow JSON. Opening a workflow never runs nodes or installs code. Missing packs are listed with an explicit Review action. Updates require removal/review/approval; they never happen silently.
Local execution records retain the resolved graph, pinned packs/models, per-node timing and loaded scientific-library/Python/SDK versions. Browser drafts autosave locally; Save, Load and Export are also explicit. Export excludes transient image IDs, weight paths, obvious absolute paths and secret parameter names. Authors should avoid placing patient/source identifiers in arbitrary parameter strings; portable parameters are scientific configuration, not a substitute for private metadata storage. Model weights, WSI pixels and machine credentials are not embedded. Pack nodes may provide checksum-pinned model metadata and local job history records the resolved model; exported workflows ask users to reconnect local assets.
Framework-provided nodes
Core provides browser-captured WSI and layer sources plus typed spatial values, execution, package discovery, and data serialization. Processing/model nodes are ordinary independently installed public node packs. Core does not bundle image-processing algorithms, model inference libraries, or model assets. See the extraction and local registration guide.
Resource and platform bounds
One active job (no unbounded queue), eight retained jobs and eight uploaded inputs, 64 nodes/256 connections, 50 MiB raster-input body ceiling, 256 KiB workflow JSON, ten-minute job deadline by default. Inputs and completed jobs expire after 30 minutes (cleanup on authenticated requests), and runtime artifacts are removed on service shutdown/restart. Failed/canceled jobs are removed promptly. Keep 1 GiB free for inputs/jobs and 2 GiB before pack installation. --job-timeout and --memory-gib configure job limits (default 600 s/8 GiB virtual-address-space ceiling).
Whole-slide integration status
Run is now connected to browser tile scheduling, authenticated Python execution and sparse native layer persistence. Whole-slide graphs use one high-resolution WSI source, tile-local nodes with compatible contracts, and optional binary overview-mask → ROI gates. Composite expansion happens before scope planning. Unsupported global reductions/cross-resolution edges fail explicitly. The existing eight-input tile API remains the transport; a persistent cross-batch model process and out-of-core viewport-driven chunk loading are future work. Static previews and read_raster_chunks also support sparse version-3 layers without densifying a WSI.
Linux/POSIX is validated. POSIX address-space and process-group limits are best effort and are not a sandbox; macOS memory behavior/GPU execution has not been validated. Windows lacks equivalent process-group descendant cleanup and POSIX resource limits: this V1 companion is not supported there yet. Browser workflows target Chromium desktop. Secure-origin loopback CORS/pairing is also tested in Firefox; Safari and real macOS local-network permission prompts remain unverified. See security and API.
Run core tests with python -m unittest discover -s tests -v; set MICROSCOPE_TEST_GIT_INSTALL=1 for the real HTTPS Git/managed-venv test. Pack tests belong to each independently versioned package and must not require model files unless real inference fixtures are explicitly supplied. Existing SDK imaging, annotations and MCP remain separate public APIs.