Skip to content

Audit and overhaul Python environment management#167

Merged
rgbkrk merged 22 commits intomainfrom
rgbkrk/audit-env-management
Feb 21, 2026
Merged

Audit and overhaul Python environment management#167
rgbkrk merged 22 commits intomainfrom
rgbkrk/audit-env-management

Conversation

@rgbkrk
Copy link
Copy Markdown
Member

@rgbkrk rgbkrk commented Feb 20, 2026

Summary

Comprehensive audit and overhaul of the Python environment management system. Maps every kernel launch path, adds project file auto-detection, improves the dependency panel UX, and fixes bugs found during manual testing.

Backend: Auto-detection and kernel launch

  • pyproject.toml: Auto-detect on launch, start kernel via uv run with retry loop and progress events
  • pixi.toml: Auto-detect on launch, convert deps to conda format, start via rattler
  • Detection priority: inline notebook deps > pyproject.toml > pixi.toml > prewarmed pool
  • Default changed from conda to uv for new notebooks

Frontend: Dependency panel

  • Non-blocking conda sync: Adding/removing deps no longer blocks the UI; "Sync Now" button for dirty state
  • Both-deps warning: Banner when notebook has both uv and conda deps, shows which is active
  • pyproject.toml actions: "Use project env" (launches uv run) and "Copy to notebook" (imports inline)
  • pixi.toml import: "Copy to notebook" button converts pixi deps to conda metadata
  • Read-only state: When kernel uses uv run, dep panel shows project-managed indicator
  • Env source indicator: Toolbar shows where the kernel came from (e.g. pyproject.toml, pixi.toml)
  • Panel mismatch fix: envType now derives from backend's envSource when kernel is running

Reliability

  • uv run retry loop: 8 attempts with increasing delays (2s-15s), stderr parsing for progress events, process exit detection
  • Execution queue timeout: Increased from 5s to 5min to support slow uv run installs
  • Error lifecycle events: Auto-launch failures now emit kernel:lifecycle error so frontend exits "Starting" state
  • Unified env_id: Removed redundant conda.env_id, using only runt.env_id

Testing

  • 6 fixture notebooks covering vanilla, uv-inline, conda-inline, both-deps, pyproject, and pixi scenarios
  • 3 new E2E specs: both-deps-panel, pixi-env-detection, pyproject-startup
  • wdio.conf.js: Added NOTEBOOK_PATH and E2E_SPEC env vars for fixture-based testing

Verification

  • Open fixtures/audit-test/1-vanilla.ipynb — kernel starts with uv, no deps panel content
  • Open fixtures/audit-test/4-both-deps.ipynb — warning banner shown, correct panel after Trust & Install
  • Open fixtures/audit-test/pyproject-project/5-pyproject.ipynb — kernel starts via uv run, progress shown in toolbar, no hang
  • Open fixtures/audit-test/pixi-project/6-pixi.ipynb — conda panel shown, pixi.toml banner with "Copy to notebook"
  • Verify "Sync Now" appears when adding deps to a running conda kernel

rgbkrk and others added 12 commits February 20, 2026 14:55
The backend `start_default_python_kernel_impl` now checks for project files
when a notebook has no inline dependencies, matching the frontend's detection
chain. This fixes the main UX gap where the backend auto-launch would give a
bare prewarmed kernel even when a pyproject.toml or pixi.toml was present.

Detection priority chain (after inline deps):
1. pyproject.toml → start with `uv run` (if has_dependencies or has_venv)
2. pixi.toml → convert to conda deps via rattler
3. (environment.yml placeholder for future PR)
4. Fall back to user preference for prewarmed envs

Co-Authored-By: QuillAid <261289082+quillaid@users.noreply.github.com>
Backend now returns detailed env_source strings from start_default_python_kernel_impl
(e.g. "uv:inline", "uv:pyproject", "conda:pixi", "uv:prewarmed") instead of just
"uv" or "conda". A "ready" lifecycle event carries this to the frontend.

The toolbar kernel status now shows the source alongside the status (e.g.
"Idle · pyproject.toml" or "Idle · conda") so users always know what
environment their kernel is using.

Co-Authored-By: QuillAid <261289082+quillaid@users.noreply.github.com>
Previously, adding a conda dependency blocked the UI for 30-150+ seconds
because addDependency immediately called syncToKernel() which triggers a
full conda solve+download+install cycle with the input disabled.

Now matches the UV pattern:
- addDependency just updates metadata and checks sync state (~200ms)
- A "Sync Now" button appears when deps are dirty
- Input stays enabled during sync so users can add multiple deps quickly
- Separate syncing state tracks sync progress without blocking the input

Co-Authored-By: QuillAid <261289082+quillaid@users.noreply.github.com>
Shows a visible warning banner in the dependency header area when a notebook
has both uv and conda dependency metadata. Previously this was a log-only
warning. Now users can see which env type is being used and are prompted
to clean up the unused deps.

Co-Authored-By: QuillAid <261289082+quillaid@users.noreply.github.com>
UV is always available (bootstrapped via rattler), faster for installs, and
has better UX (non-blocking sync, pyproject.toml support). With P1/P2 adding
project file auto-detection, the defaults are now context-sensitive:
- pyproject.toml nearby → UV (auto-detected)
- pixi.toml nearby → conda (auto-detected)
- environment.yml nearby → conda (auto-detected)
- No project files → UV (this change)

Users who prefer conda can still set it explicitly in settings.

Co-Authored-By: QuillAid <261289082+quillaid@users.noreply.github.com>
…roject.toml

The pyproject.toml banner now offers two distinct actions:
- "Use project env" (primary, green) — starts kernel via uv run, stays
  in sync with pyproject.toml. Shows "Active" badge when already using it.
- "Copy to notebook" (secondary, subtle) — copies deps as a snapshot
  into notebook metadata for portable sharing.

Previously only "Import to notebook" existed, which was the copy action
but wasn't clearly distinguishable from "use the project environment".

Co-Authored-By: QuillAid <261289082+quillaid@users.noreply.github.com>
When the kernel was started via uv run (pyproject.toml), the dependency
management UI now shows a read-only view: "Managed by pyproject.toml —
restart kernel to pick up dependency changes." The add/remove dependency
input is hidden since deps are managed by the project file.

Co-Authored-By: QuillAid <261289082+quillaid@users.noreply.github.com>
Adds pixi.toml detection and import flow for conda environments:

Backend:
- New `import_pixi_dependencies` Tauri command that finds pixi.toml,
  converts dependencies to conda format, and writes to notebook metadata

Frontend:
- useCondaDependencies detects pixi.toml on mount via `detect_pixi_toml`
- CondaDependencyHeader shows pixi.toml banner with dep count and
  "Copy to notebook" button when a pixi.toml with deps is found
- Wired through App.tsx

Co-Authored-By: QuillAid <261289082+quillaid@users.noreply.github.com>
Previously env_id was stored in both metadata.runt.env_id (canonical)
and metadata.conda.env_id (redundant copy). All reads already came from
runt.env_id, so the conda copy was never used.

Changes:
- notebook_state.rs: Stop writing env_id into conda metadata when
  creating new notebooks
- lib.rs: Remove redundant conda.env_id update in clone_notebook_to_path

The CondaDependencies.env_id struct field is kept as an internal carrier
(populated from runt.env_id before calling conda env functions).

Co-Authored-By: QuillAid <261289082+quillaid@users.noreply.github.com>
Review fixes:
- import_pixi_dependencies now preserves python version constraint from
  pixi.toml when writing conda metadata (was silently dropped)
- startKernel and startKernelWithDeno clear envSource to prevent stale
  env source labels when switching kernel types

Test fixtures in crates/notebook/fixtures/audit-test/:
- 1-vanilla: no deps, tests P8 default-to-uv
- 2-uv-inline: notebook with uv deps
- 3-conda-inline: notebook with conda deps
- 4-both-deps: both uv+conda deps for P6 warning
- pyproject-project/: pyproject.toml + notebook for P1/P7/P9
- pixi-project/: pixi.toml + notebook for P2/P4

Co-Authored-By: QuillAid <261289082+quillaid@users.noreply.github.com>
- Derive envType from envSource when kernel is running, fixing bugs where
  both-deps notebooks showed uv panel but backend chose conda (#4) and
  pixi auto-detection showed uv panel instead of conda (#6)
- Replace 1s sleep + single connection attempt in start_with_uv_run with
  a retry loop (up to 8 attempts with increasing delays) that checks for
  process exit, emits progress events, and parses uv stderr for status
- Add NOTEBOOK_PATH and E2E_SPEC env vars to wdio.conf.js for fixture testing
- Add E2E specs for both-deps panel, pixi env detection, and pyproject startup

Co-Authored-By: QuillAid <261289082+quillaid@users.noreply.github.com>
- Increase execution queue retry from 5s (50*100ms) to 5min (600*500ms)
  to support uv run scenarios where deps need installing
- Emit "error" lifecycle event when auto-launch fails, so frontend
  transitions out of "Starting" state instead of hanging forever
- Handle "error" lifecycle event in useKernel to set kernel status

Co-Authored-By: QuillAid <261289082+quillaid@users.noreply.github.com>
@rgbkrk rgbkrk marked this pull request as draft February 20, 2026 23:02
@rgbkrk rgbkrk force-pushed the rgbkrk/audit-env-management branch from 845b6fe to e41129e Compare February 20, 2026 23:02
@rgbkrk rgbkrk changed the title Fix environment panel mismatch, uv run beach-ball, add E2E tests Audit and overhaul Python environment management Feb 20, 2026
rgbkrk and others added 10 commits February 20, 2026 18:28
The field was removed from AppSettings but two references remained
in the Default impl and test, causing CI compilation failures.

Co-Authored-By: QuillAid <261289082+quillaid@users.noreply.github.com>
Adds a conda-env-project directory with an environment.yaml and
test notebook, following the same pattern as the pixi-project and
pyproject-project fixtures.

Co-Authored-By: QuillAid <261289082+quillaid@users.noreply.github.com>
- AGENTS.md: Add environment system overview, detection priority
  chain, trust system notes, and key files reference
- contributing/environments.md: Architecture guide covering caching,
  prewarming, project file detection, frontend hooks, and testing
- docs/environments.md: User-facing guide for inline deps, project
  files, cache cleanup, and troubleshooting
- docs/sharing.md: User-facing guide for the two sharing models
  (inline portable vs project-level reference)

Co-Authored-By: QuillAid <261289082+quillaid@users.noreply.github.com>
The pixi-env-detection spec requires the app to open a notebook
next to pixi.toml so the backend can auto-detect it. Run it
separately with the correct NOTEBOOK_PATH, and exclude it from
the default test run where no fixture path is set.

Co-Authored-By: QuillAid <261289082+quillaid@users.noreply.github.com>
- Move environment.yml detection after pyproject/pixi to match
  documented priority: inline → pyproject → pixi → env.yml → prewarmed
- Return "conda:env_yml" instead of generic "conda" so toolbar shows
  the correct source label
- Add setEnvSource("conda:env_yml") in frontend startKernelWithEnvironmentYml
- Add data-testid="notebook-toolbar" to toolbar header for E2E assertions
- Run pyproject-startup and both-deps-panel E2E specs with their
  required fixture notebooks in CI
The --exclude CLI flags didn't match absolute spec paths, so all 13
specs ran in the default run (including fixture-specific ones without
their NOTEBOOK_PATH). Fixture-specific runs also failed because
E2E_SPEC relative paths didn't resolve.

Fix: move exclusion logic into wdio.conf.js using the exclude config
with absolute paths, and resolve E2E_SPEC with path.resolve().
The rich-outputs spec hung in CI — the app never loaded for the 10th
sequential launch through the same tauri-driver instance. Fix by
restarting tauri-driver before each wdio invocation and adding a
15-minute step timeout so hung specs can't block CI indefinitely.
start_with_uv_run hardcoded Command::new("uv") which fails with
"No such file or directory" when uv is bootstrapped (not on system
PATH). Use tools::get_uv_path() to resolve the correct binary,
matching what uv_env.rs does everywhere else.

Also extend E2E step timeout from 15 to 25 minutes to accommodate
4 sequential wdio runs including the pyproject spec which needs
uv to install deps.
Having uv on PATH is the realistic user scenario. The bootstrapping
path is better tested as a unit test rather than gating E2E tests
on it.
pyproject fails because uv run exits with status 2 resolving deps
in the CI sandbox. both-deps fails because inline deps are untrusted
on a fresh CI machine (no trust key). Both tests are kept for local
use and can be enabled once CI has proper fixture infrastructure.
@rgbkrk rgbkrk marked this pull request as ready for review February 21, 2026 06:37
@rgbkrk rgbkrk merged commit b1208ab into main Feb 21, 2026
5 checks passed
@rgbkrk rgbkrk deleted the rgbkrk/audit-env-management branch February 21, 2026 06:37
@rgbkrk rgbkrk added daemon runtimed daemon, kernel management, sync server editor CodeMirror, syntax highlighting, editor behavior labels Mar 14, 2026
@rgbkrk rgbkrk added frontend Webview, React, TypeScript UI test Test infrastructure and coverage labels Mar 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

daemon runtimed daemon, kernel management, sync server editor CodeMirror, syntax highlighting, editor behavior frontend Webview, React, TypeScript UI test Test infrastructure and coverage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant