Skip to main content

PrismNote

Problem

Most notebook tools force a choice: a lightweight local notebook with no real data-warehouse connectivity, or a heavyweight cloud platform for warehouse access with no simple local-first story — and running untrusted notebook code safely usually means bolting on your own sandboxing.

Solution

A Jupyter-compatible data-science notebook with a Rust backend and a React frontend: real local SQL execution, a real sandboxed code-execution engine, and connectors for cloud data warehouses.

CI

Use cases

  • Querying local SQLite/DuckDB files or a Postgres/MySQL server from the same notebook, with real integration-tested execution, not a mocked query path.
  • Running untrusted or AI-generated code safely — the Docker sandbox gives no network access by default, enforced memory/CPU/process limits, and a wall-clock timeout, rather than executing code in-process.
  • Querying a cloud warehouse (Snowflake, BigQuery, Redshift, Databricks, etc.) from a notebook without switching to a separate BI tool.
  • Not yet a good fit for: MongoDB access (not implemented, returns an explicit error rather than faking success); data-quality scoring (the one area still not wired to real execution — see Other integrations); Linux/Windows without building from source (prebuilt binary is macOS Apple Silicon only today).

What this is

  • Backend: Rust (Axum). Serves the API, runs SQL against local and remote databases, and launches Docker containers for sandboxed code execution.
  • Frontend: React + TypeScript (Vite). Notebook UI, SQL cells, schema explorer, results grid.
  • The release binary embeds the built frontend, so prismnote is a single executable that serves the whole app.

Install

pip install prismnote
prismnote

pip install installs a thin Python launcher (python/) — on first run it downloads the matching prebuilt server binary from GitHub Releases and execs it. As of this version, a prebuilt binary is published for macOS (Apple Silicon) only; other platforms need to build from source (see Building below) until more platform binaries are uploaded.

SQL execution

SQL cells run against real databases — there is no mocked or placeholder query path:

Backend Status
SQLite Real, embedded (via sqlx), no server required
DuckDB Real, embedded (bundled DuckDB, compiled from source), no server required
PostgreSQL Real, via sqlx; requires a reachable Postgres server
MySQL Real, via sqlx; requires a reachable MySQL server

All four are covered by integration tests that run genuine CREATE TABLE / INSERT / SELECT round trips (crates/server/src/db/executor.rs). SQLite and DuckDB tests always run. The Postgres/MySQL tests connect to a real server and skip (rather than fail) when one isn't reachable — point them at a running server with PRISMNOTE_TEST_PG_PORT / PRISMNOTE_TEST_MYSQL_PORT.

MongoDB is not implemented; connecting to it returns an explicit error rather than a fake success.

Sandboxed code execution

docker_executor.rs runs untrusted code in a brand-new, disposable Docker container per execution (docker run --rm):

  • No network access by default (--network=none)
  • Memory, CPU, and process-count limits enforced per run
  • A wall-clock timeout that force-kills and cleans up the container
  • Real stdout/stderr/exit-code capture

Requires a working Docker installation. Supported languages: Python, Bash/shell, JavaScript (Node), Ruby.

Cloud warehouse connectors

Real connection + query execution for Snowflake, BigQuery, Redshift, Azure Synapse, Databricks, Athena, Presto, and Trino (crates/server/src/cloud_warehouse/). AWS-signed requests (Athena, Redshift) use a real SigV4 implementation.

Other integrations

All real API calls, not placeholders:

Integration What's real
dbt Shells out to the real dbt CLI; parses its manifest.json/run_results.json
GitHub Real Contents API for notebook backup/sync
Airflow Real REST API v1 (list/trigger DAGs, run status, tasks). DAG creation writes a file to a configured local DAGs folder, since Airflow's API has no DAG-creation endpoint
Kubernetes Real kubectl apply/get pods/scale
RunPod Real GraphQL API for training-instance lifecycle and serverless endpoint deployment

Two data-quality-scoring code paths (api::get_quality_score, lineage::data_quality_score) are the one area still not wired to real execution — they'd need an assertion-storage and table-to-queryable-data layer that doesn't exist yet, rather than something fakeable in isolation.

Cloud storage (S3/GCS/Azure Blob/Google Drive) is wired to the API. crates/server/src/cloud_storage.rs has real, unit-tested HTTP clients — S3 (SigV4-signed), GCS (service-account JWT OAuth), Azure Blob (Shared Key HMAC-SHA256), Google Drive (OAuth refresh-token) — with real upload/download/list/delete methods on each client. The /cloud-storage HTTP endpoints (api::add_cloud_storage, api::list_cloud_storage, api::remove_cloud_storage) call this code: add_cloud_storage parses the provider credentials and registers a real client, list_cloud_storage returns the configured clients, and remove_cloud_storage drops one. A user who configures real S3 credentials through this API gets a real client backed by the same code the unit tests exercise. (What is not yet built is automatic notebook backup scheduling on top of these clients.)

vs Jupyter

Real Jupyter (via nbclient) is the direct comparison the "Jupyter-compatible" claim above invites. Tested both against the same real notebook (3 cells: define a DataFrame + variable, use them in the next cell with no re-import, then a cell that deliberately divides by zero), driven through PrismNote's real HTTP API (register → login → create notebook → execute) and through nbclient against a real ipykernel.

PrismNote (real API) Jupyter (nbclient + ipykernel)
Kernel/first-cell time ~4ms once a kernel is warm (see bug below) 0.57s kernel startup + ~0.17s first cell
Cross-cell state (cell 2 uses cell 1's x/df, no re-import) Correct: 43, 6 Correct: 43, 6
Real exception (cell 3, 1/0) Correct: real ZeroDivisionError traceback, not swallowed Correct: real ZeroDivisionError traceback
"Integrated intelligence" (/api/ai/explain) Real — verified against a real local Ollama model (qwen2.5:7b-instruct), returned a real, coherent, non-canned explanation in 5.3s N/A (not a Jupyter feature)
.ipynb format compatibility Real, genuine from_ipynb/to_ipynb conversion exists (crates/server/src/files.rs) N/A (native format)

Two real bugs found while running this benchmark — both now fixed:

  1. Fixed: the kernel process spawn hardcoded Command::new("python"), which doesn't exist on this (or many modern) machines — only python3 does. This meant every cell execution failed with the misleading "Kernel not available. Install ipykernel" error, even with ipykernel correctly installed under python3. Fixed with a python3-first resolution helper used consistently across all 3 call sites that previously hardcoded "python" (crates/server/src/kernel.rs). Regression test added.
  2. FIXED (was critical): the Python kernel used to be a single global process shared by every notebook on the server, not one kernel per notebook. Reproduced live: defined x = 42 in one notebook, then read x from a brand-new, unrelated notebook that never defined it — it printed 42. Any two notebooks (including two different logged-in users', given the real JWT auth system) shared one Python namespace — a real data-isolation/security issue, not just a quirk. Fixed by replacing the single shared KernelManager with a kernel::KernelRegistry keyed per-notebook (plus a job:<id> slot per saved job and a fixed system slot for one-shot warehouse/database queries), spawned lazily on first use. Required changing the public API shape for 3 endpoints that previously had no notebook-id parameter at all (kernel/interrupt, kernel/restart, kernel/variables — now /notebooks/:id/kernel/...) plus updating every frontend caller. Re-verified live against the real running server (not just unit tests): the exact reproduction above (x = 42 in notebook A, read from notebook B) now correctly raises NameError in notebook B, while notebook A's own state persists correctly across multiple real calls. New Rust regression test (kernel::tests::different_keys_get_independent_kernels_with_isolated_namespaces) spawns two real Python processes and asserts the same isolation. Full detail in ROADMAP_HONEST.md.

Bottom line: the core notebook semantics (cross-cell state, real error handling, and now real per-notebook kernel isolation) genuinely work and match real Jupyter behavior — plus real, working local-LLM-backed AI assistance Jupyter doesn't provide out of the box. Idle kernel eviction (kernels are never terminated once spawned) is a real, separate resource-management improvement, not a correctness gap.

Building

git clone https://github.com/Mullassery/PrismNote.git
cd PrismNote
make build

make build builds the frontend first and embeds it into the release binary — this is the only build path that produces a binary that actually serves the UI. Running cargo build --release directly will build a backend with no frontend assets. The binary is written to target/release/prismnote.

Requirements: Rust (stable), Node 20.19+ (required by Vite 8), and Docker if you want sandboxed code execution or want to test the container-management endpoints.

Development

# Terminal 1: backend on http://localhost:8000
cargo run

# Terminal 2: frontend dev server on http://localhost:5173
cd frontend && npm install && npm run dev

Tests

cargo test --workspace --release   # backend
cd frontend && npm test            # frontend (vitest)

Real results as of 2026-09-19: backend 170 passed / 1 flaky failure (a Docker-sandbox timeout-cleanup test that's timing-sensitive under concurrent test load); frontend vitest 114/114 passed. npm run lint and npm run test:e2e currently fail in this repo (435 lint errors; 57/85 Playwright tests) — CI's frontend workflow does not currently fail the build on either, which is a known gap. See ROADMAP_HONEST.md for the full, unfiltered list of bugs and gaps found in the most recent audit, including this one.

Configuration

Everything runs with no environment variables set — Google Sign-In and AI features (code explain/fix/complete, NL-to-SQL, RunPod fine-tuning) are just disabled until configured. Copy .env.example to .env and fill in what you need; see the comments in that file for which variables are required together (e.g. PRISMNOTE_AI_PROVIDER=claude needs ANTHROPIC_API_KEY) and which are backend-only vs. frontend (VITE_-prefixed).

Project layout

crates/server/   Rust backend: API, SQL executors, Docker sandbox, cloud warehouse connectors
frontend/        React app (components, hooks, API clients)
python/          PyPI launcher package
docs/            architecture notes and screenshots

Contributing, security, status

License

Apache License 2.0. See LICENSE for the full terms.

Metadata

Release files for prismnote 1.12.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for prismnote 1.12.0
File Size Uploaded
prismnote-1.12.0.tar.gz 38.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for prismnote 1.12.0
File Interpreter ABI Platform
prismnote-1.12.0-py3-none-any.whl Python 3 none any Details

Total release size: 64.9 kB

Release files / prismnote-1.12.0.tar.gz

Download URL prismnote-1.12.0.tar.gz
Size 38.7 kB
Tags Source
SHA-256 checksum
How to use checksums
59a512de3e0fbe50db482ad747002fcfde0487cb927df1ebadd9ee76e0eb2696
BLAKE2b-256 checksum
How to use checksums
12028aef79db5abfd0748c243bfa8ed6755a24a809a31dec93a13b800cc3c0de
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.6

Release files / prismnote-1.12.0-py3-none-any.whl

Download URL prismnote-1.12.0-py3-none-any.whl
Size 26.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
48ca0b7dd83b6d32bacdffbd9338bf091e96e545da5c8cc1985b97f3da364fc2
BLAKE2b-256 checksum
How to use checksums
1bbdec50680fcd52aa78fec85732dffe7c5cc8fe33ee187510780418653e8fb9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.6

Release history Release notifications | RSS feed

This release

1.12.0 This release

2 release files

1.11.0

2 release files

1.9.0

2 release files

1.8.2

1 release file

1.8.1

2 release files

1.8.0

1 release file

1.7.0

1 release file

1.6.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page