shiganluo/skill/apptainer-sif-build-pitfalls
Claude Code and agent skill by shiganluo/skill
- community
- ext:[{"type":"hook","description":"Pre/post lifecycle hooks"}]
Checking that the SKILL.md file is still in the repository.
Pitfalls and patterns for building Apptainer SIF images via EnvUtil.py — PyPI detection, uv vs conda templates, CN network workarounds, system dependency traps.
Install
npx vskill@latest install shiganluo/skill/apptainer-sif-build-pitfallsSemi-extensibleMentions customization, but needs skill-specific knowledge. Read the extensible skills standard
SKILL.md
Apptainer SIF Build Pitfalls
NOTE: Overlaps with apptainer-container-build (bioinformatics). This skill focuses on EnvUtil internals; the bioinformatics skill adds annotation standardization and scTE-specific detail.
EnvUtil.py generates .def files from conda YAML and builds .sif images. Two templates exist:
Template Selection (auto-detected via is_pypi_only())
PyPI-only YAML → uv template (python:3.11-slim + uv pip install)
- Trigger: no conda deps beyond
python*/pip*, all real packages underpip:sub-section parse_conda_yaml()returnspip_dependencieslist (items underpip:key)is_pypi_only()checks:python/pipare meta-deps (filtered out via regex); remaining conda deps must be empty- Fast: ~2 min vs ~2hr conda
Mixed/conda YAML → conda template (miniconda3 + conda env create)
- Trigger: any conda-specific dep (samtools, bedtools, openms, etc.)
Critical Pitfall: PyPI packages with system deps
scte-quant is PyPI-only BUT needs samtools and zstd at runtime. If you put only pip: scte-quant in the YAML, uv template is chosen and those system tools are missing.
Fix: Add the system deps as conda deps in the YAML:
Rule: Before marking a YAML as PyPI-only, verify the pip package doesn't need system-level tools (samtools, zstd, htslib, etc.) that only conda/apt provides.
Common Fixes
set -euin every%postblock (NOT `set -euo pipefail` — the default shell in Apptainer%postissh, notbash, andpipefailis not supported insh, causingset: Illegal option -o pipefail)- Docker Hub blocked in CN:
FROM: docker.m.daocloud.io/... - openms needs BOTH
openmsANDopenms-thirdparty
CLI
Flags: --no-fakeroot, --force (default off, enables overwrite + rebuild)
Pitfall: --force implies --no-skip-existing. Without --force, existing SIFs are skipped even if you want to rebuild. The force param controls apptainer build --force (overwrite output file) while skip_existing controls the Python-level "SIF already exists" early-exit. --force sets both.
Post-install hooks (.post.sh)
EnvUtil reads <env_name>.post.sh from the YAML's directory and injects its content at the end of %post in the generated .def. Use for module-specific patches (e.g. scTE's M<->MT fix) without manually editing the .def.
The .post.sh content is raw shell — indent with 4 spaces to match %post style.
conda solver
Default template uses conda config --set solver classic (reliable). libmamba solver installation from conda-forge is unreliable in container builds — can fail silently, timeout, or produce empty SIFs. Classic solver is slow (5-10 min for dual-channel) but works every time.
Host ~/.condarc may set solver: libmamba which leaks into the container. Always explicitly set conda config --set solver classic in %post to override.
Silent build failures (CRITICAL)
apptainer build --fakeroot can return exit code 0 even when %post fails. EnvUtil's _run_streaming checks returncode but apptainer doesn't propagate %post errors reliably. Result: empty SIF (~300MB = just base image) with no error.
Detection: EnvUtil build_sif() now does two post-build checks:
- SIF size < 350MB → RuntimeError (base miniconda3 is ~300MB)
apptainer exec <sif> conda env list→ check env name present
Manual verification after build:
SIF is read-only at runtime
Cannot patch files inside a SIF with apptainer exec — all fixes must be baked into the %post section during build. If you discover a missing patch after build, you must rebuild.
find path precision in %post
When using find to locate Python package files inside conda envs, use precise paths:
Ambiguous find + head -1 is a silent failure — the patch targets the wrong file and you get no error.
M<->MT mitochondrial patch
scTE has chrM/chrMT naming mismatches in TWO places:
1. base.py split_all_chrs() — BAM processing
Direction matters:
- BED chrMT → chromosome_list has M → map MT→M
- BED chrM → chromosome_list has MT → map M→MT
Both directions must be handled.
2. scTE_build — Index building (chr_list)
scTE_build line 17: chr_list = [str(k) for k in list(range(1,50))] + ['X','Y','M'] Ensembl GTF uses 'MT' not 'M'. All MT genes are silently skipped.
Fix: Add 'MT' to chr_list AND add M<->MT normalization in readGtf and TE processing.
3. Matching installed files vs source code (CRITICAL)
The installed scTE_build in the container may differ from the source repo:
- Different variable names (
chromvschr) - Different spacing (
[str(k)vs[ str(k)) - Different line numbers
Rule: Always check the ACTUAL installed file inside the container before writing patches:
Don't assume the source repo matches what's installed.
Security
- Security scanPassed, 90 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingdevops/apptainer-sif-build-pitfalls/SKILL.md
Popularity
- 7-day trend score
- 0
Not refreshed yet.
Extension points
hookPre/post lifecycle hooks
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/shiganluo/skill/apptainer-sif-build-pitfalls)