agentic-os
AFaffaan-m/ECC278k4,046 new stars in the last 7 days
Use when creating, migrating, or debugging pixi environments, especially for scientific Python, bioinformatics, single-cell analysis, CUDA/PyTorch, Jupyter/VS Code kernels, conda-to-pixi migration, or conda + PyPI mixed dependency issues.
Use this skill to design, migrate, and debug pixi-managed environments. The core principle is to clarify environment intent before editing pixi.toml: version constraints, project scope, package source priority, mirror/network policy, special packages, cache location, and validation tasks.
Pixi can solve dependencies automatically, but mixed conda + PyPI environments need deliberate package ownership. Most hard failures come from unclear ownership, unconstrained top-level packages, inaccessible mirrors, or non-registry packages.
Before creating or changing a pixi environment, ask these questions unless the answer is already known from repo files, user context, or error logs:
Required versions
python, cuda, pytorch, domain packages, model libraries, analysis frameworks.Environment scope
pixi.toml.pixi global for reusable CLI tools, not complex project workflows.Package source priority
Multiple environments or kernels
Mirror and network policy
pypi.org, files.pythonhosted.org, prefix.dev, or internal mirrors?Non-registry packages
Cache and storage
Validation
For analysis projects, put environment definition in the repo:
[workspace]
name = "project-name"
channels = ["conda-forge"]
platforms = ["linux-64"]
Use user/global environments mostly for standalone tools.
Choose one owner for each important package family.
Prefer conda for:
Prefer PyPI for:
opencv-python-headlessAvoid this pattern:
[dependencies]
scanpy = "*"
anndata = "*"
scipy = "*"
[pypi-dependencies]
some-framework-that-also-depends-on-scanpy = "*"
This can make conda pin versions before PyPI solves, causing conflicts.
Do not mechanically copy an entire old conda environment. Start from:
Add transitive pins only when solver output or runtime validation proves they are needed.
When migrating an existing conda/mamba environment:
conda list -p /path/to/env
conda env export -p /path/to/env --no-builds
rg -n "^(import|from) " scripts src notebooks tests --glob '*.py' --glob '*.ipynb'
rg -n "Version:|__version__|import " notebooks scripts --glob '*.ipynb'
Classify packages:
Preserve known compatibility anchors:
Leave unrelated transitive packages out of pixi.toml.
Use multiple named environments when the user needs isolation or parallel notebooks.
Use one solve group when environments should have identical package versions:
[environments]
worker-1 = { solve-group = "analysis" }
worker-2 = { solve-group = "analysis" }
worker-3 = { solve-group = "analysis" }
Use separate features when environments differ:
[feature.gpu.dependencies]
pytorch-cuda = "*"
[feature.r.dependencies]
r-base = "*"
[environments]
cpu = []
gpu = ["gpu"]
r-analysis = ["r"]
For VS Code/Jupyter kernels, add explicit kernel tasks:
[tasks]
kernel-1 = "python -m ipykernel install --user --name worker-1 --display-name 'Python (worker-1)'"
kernel-2 = "python -m ipykernel install --user --name worker-2 --display-name 'Python (worker-2)'"
kernels = "pixi run -e worker-1 kernel-1 && pixi run -e worker-2 kernel-2"
Tell VS Code users: after registration, select the kernel in VS Code; they do not need to launch notebooks through pixi run.
Use mirrors deliberately. Do not assume a mirror works for all package types.
Recommended checks:
pixi config list
sed -n '1,120p' ~/.config/uv/uv.toml 2>/dev/null
sed -n '1,120p' ~/.config/pip/pip.conf 2>/dev/null
env | rg "PIP|UV|PIXI|RATTLER|HTTP|HTTPS|PROXY"
For PyPI, prefer setting only the index URL in pixi.toml:
[pypi-options]
index-url = "https://example-mirror/simple"
Avoid unnecessary files.pythonhosted.org mirror rewrites unless verified. Some mirrors serve simple index pages but fail wheel metadata URLs.
If official PyPI times out, switch to a reachable mirror. If a mirror gives 404 for metadata, try another mirror or the official file server directly.
For conda, use .pixi/config.toml mirrors when needed:
[mirrors]
"https://conda.anaconda.org/conda-forge" = [
"https://your-conda-mirror/anaconda/cloud/conda-forge",
"https://conda.anaconda.org/conda-forge"
]
Pixi needs conda-to-PyPI name mapping when conda and PyPI dependencies are mixed. If fetching mapping from prefix.dev fails, use a local mapping file.
In pixi.toml:
[workspace]
conda-pypi-map = { "conda-forge" = "config/conda-pypi-map.json" }
Example config/conda-pypi-map.json:
{
"scikit-learn": "scikit-learn",
"matplotlib-base": "matplotlib",
"pytorch": "torch",
"torchvision": "torchvision",
"torchaudio": "torchaudio"
}
Validate it:
python -m json.tool config/conda-pypi-map.json
Keep this mapping small and project-specific. Add entries only for packages relevant to mixed solving.
If a package is not found on PyPI or conda, inspect how it was installed before guessing.
Check old environment metadata:
find /path/to/env/lib/python*/site-packages -maxdepth 3 \
\( -iname '*dist-info' -o -path '*dist-info/direct_url.json' \)
Use local path dependency when reproducible on this machine:
[pypi-dependencies]
my-package = { path = "/absolute/path/to/source" }
Use Git dependency when portability matters:
[pypi-dependencies]
my-package = { git = "https://github.com/org/repo.git", rev = "commit-sha" }
Prefer a fixed commit/tag for reproducibility.
Root cause: package is unpublished, private, named differently, or only installed from source.
Actions:
direct_url.json.Root cause: conda pinned a transitive package version that conflicts with PyPI requirements.
Actions:
Root cause: inaccessible PyPI index, file host, proxy, or mirror.
Actions:
[pypi-options] index-url.pixi clean cache --pypi -y
pixi install --all
Root cause: simple index mirror works but wheel metadata/file mirror is incomplete.
Actions:
files.pythonhosted.org mirror rewrites.Root cause: conda opencv pulls GUI/Qt/Python ABI-specific builds.
Server/headless fix:
[pypi-dependencies]
opencv-python-headless = ">=4.10,<5"
Use conda opencv only when GUI functionality is required.
Root cause: CUDA runtime, driver, PyTorch build, and channel priorities disagree.
Actions:
nvidia-smi.torch.cuda.is_available().Pixi has default cache. Do not create custom cache directories unless the user requests shared cache, has permission errors, or needs a specific storage path.
Useful commands:
pixi clean cache --pypi -y
pixi clean cache --repodata -y
pixi clean cache --mapping -y
If custom cache is needed:
PIXI_CACHE_DIR=/path/to/pixi-cache \
RATTLER_CACHE_DIR=/path/to/rattler-cache \
pixi install --all
Add a check task for complex environments. It should verify the actual success criteria, not just installation.
Examples:
[tasks]
check = "python -c \"import sys; print(sys.version)\""
For GPU Python environments:
check = "python -c \"import torch; print(torch.__version__); print(torch.version.cuda); print(torch.cuda.is_available()); print(torch.cuda.get_device_name(0) if torch.cuda.is_available() else 'NO GPU')\""
Run:
pixi run -e <environment> check
For Jupyter/VS Code workflows, verify kernel registration separately:
pixi run kernels
jupyter kernelspec list
conda-forge r-base ships with OpenBLAS, but when OPENBLAS_NUM_THREADS is unset on a
high-core server, the default thread scheduling is extremely poor — SVD on 96 cores
without explicit thread count is slower than single-threaded. This directly impacts
Seurat RunPCA() (backed by irlba() randomized SVD).
OPENBLAS_NUM_THREADS and OMP_NUM_THREADS are both unsetPREFIX=$(pixi info --manifest-path pixi-workspaces/<env>/pixi.toml 2>/dev/null | grep "Prefix location" | awk '{print $NF}')
readlink -f "$PREFIX/lib/libblas.so.3"
libopenblasp-*.so → OpenBLAS, this section applieslibflexiblas.so → different approach needed (FlexiBLAS backend switching)pixi run --manifest-path pixi-workspaces/<env>/pixi.toml \
Rscript -e '
cat("OPENBLAS_NUM_THREADS =", Sys.getenv("OPENBLAS_NUM_THREADS"), "\n")
set.seed(42); n <- 3000; X <- matrix(rnorm(n*n), n, n)
t <- system.time({ svd(X, nu=10, nv=0) })
cat("SVD(3000) time:", round(t["elapsed"], 3), "sec\n")
cat("Detected cores:", parallel::detectCores(), "\n")
'
for threads in 1 8 16 32 64; do
echo "=== OPENBLAS_NUM_THREADS=$threads ==="
OPENBLAS_NUM_THREADS=$threads OMP_NUM_THREADS=$threads \
pixi run --manifest-path pixi-workspaces/<env>/pixi.toml \
Rscript -e '
set.seed(42); n <- 3000; X <- matrix(rnorm(n*n), n, n)
t <- system.time({ svd(X, nu=10, nv=0) })
cat("SVD(3000) time:", round(t["elapsed"],3), "sec\n")
' 2>/dev/null
done
Benchmark results on AMD EPYC 7K62 (96 cores, Zen2):
| Threads | SVD(3000) Time | Speedup |
|---|---|---|
| Default (unset) | ~20 sec | 1x (baseline) |
| 1 | ~12 sec | 1.6x |
| 8 | ~3.8 sec | 5.2x |
| 16 | ~3.2 sec | 6.2x |
| 32 | ~2.9 sec | 6.8x (optimal) |
| 64 | ~3.3 sec | 6.0x (overhead degrades) |
Rule of thumb: optimal thread count ≈ 1/3 of total cores (96→32, 64→16-24, 32→8-16). Beyond the sweet spot, thread synchronization overhead degrades performance.
Add [activation.env] to the workspace pixi.toml:
[activation.env]
OPENBLAS_NUM_THREADS = "32"
OMP_NUM_THREADS = "32"
Takes effect on every pixi run or environment activation. Jupyter kernels (IRkernel)
registered via pixi run kernel also inherit these variables.
AFaffaan-m/ECC278k4,046 new stars in the last 7 days
GAgarrytan/gstack136k883 new stars in the last 7 days
ADaddyosmani/agent-skills106k3,628 new stars in the last 7 days
NEnexu-io/open-design101k1,126 new stars in the last 7 days
NEnexu-io/open-design101k1,126 new stars in the last 7 days
THthedotmack/claude-mem100k3,024 new stars in the last 7 days