Imported from pieper/slicer-skill (
SKILL.md). Install upstream withnpx skills add pieper/slicer-skill. Copyright stays with the author.
Slicer Skill
This repository contains the information and helper scripts needed by an AI coding agent ("skill") that is designed to answer questions about the 3D Slicer application and its extension ecosystem. It is intentionally generic so that it can be consumed by any tool that understands the SKILLS.md convention (e.g. Claude Code, OpenAI agents, etc.).
NEVER post publicly under the user's identity without explicit, specific approval
The gh CLI and Discourse endpoints in this skill are for READING and SEARCHING ONLY. The agent
must never perform a write/publish action that appears under the user's name or account without
the user's explicit, specific go-ahead for that exact action — regardless of how reasonable the
action seems. This covers, non-exhaustively:
- GitHub: creating/closing/reopening/merging issues or PRs; posting or editing any comment, PR
review, or release note; adding labels/assignees;
gh pr comment/close/create/review,gh issue create/comment/close,gh apimutations (POST/PATCH/PUT/DELETE). - Slicer Discourse (
discourse.slicer.org): creating topics, replies, or edits. - Any other public or shared venue (mailing lists, wikis, chat) reachable from the tooling.
Rules:
- A user statement of intent is NOT authorization. "I'm going to close it", "I'll reply", "let's close this" means the user will do it themselves. It is never a request for the agent to do it. If you are not certain the user is asking you to post, assume they are not.
- The user controls the exact wording of anything public. When a post/comment/close seems warranted, draft the text and hand it to the user to post (or to paste after explicit approval). Do not compose-and-send in one step.
- Why this matters: a public message the agent sends under the user's name is one the user did not write and must now remember they did not write. Surprise posts erode the user's ability to track their own communications and their control over their public voice. Treat every such action as outward-facing and irreversible.
- Reading, searching, cloning, and local analysis via these tools remain fine and need no approval.
Setup Modes
The setup script (./setup.sh) has two orthogonal axes:
- mode — what gets cloned (full / lightweight / web)
- indexes — what ranked-search indexes get built (none / bm25 / hybrid)
On first run, setup.sh prompts for both. Subsequent runs reuse the previous
choices, recorded in .setup-stamp.json as the "mode" and "indexes" fields.
You can override interactively or via flags.
Mode (which clones)
| Mode | Disk | Setup time | What's local |
|---|---|---|---|
| full | ~15 GB | ~20 min | Source, deps, all 200+ extensions, discourse archive |
| lightweight | ~1 GB | ~2 min | Source + ExtensionsIndex metadata (JSON only) |
| web | minimal | instant | Nothing cloned — all access via web APIs |
Override: ./setup.sh --mode full|lightweight|web
Indexes (which ranked-search backends)
| Indexes | Disk | Setup time | What it gives you |
|---|---|---|---|
| none | 0 | instant | No ranked search; the agent uses grep/find/web APIs. |
| bm25 | ~65 MB | ~15 s (foreground) | Lexical search (BM25) over slicer-source + slicer-discourse. Best for exact identifiers, symbols, paths. |
| hybrid | ~300 MB | ~15 s up front, ~20 min in the background | bm25 PLUS dense embeddings (sentence-transformers/all-MiniLM-L6-v2). Adds semantic / paraphrase search. Lexical search is ready as soon as setup.sh exits; vector/hybrid search becomes available when the background build finishes. |
Override: ./setup.sh --indexes none|bm25|hybrid
Background build progress for the hybrid level:
tail -f .vector-build.logfrom the workspace root, or- call the MCP
index_statustool — it reports"building": truewith the process PID and the last log lines while the embed job is running.
web mode forces indexes=none (there are no local clones to index).
Determining the active state: Read .setup-stamp.json in the skill workspace
and look at "mode" and "indexes". If the file does not exist, run ./setup.sh.
Goal
Depending on the active mode, the skill provides access to these resources either locally (via cloned repositories) or remotely (via web APIs):
- The Slicer source code – the official C++/Python repositories that make up the application. (Local in full and lightweight modes.)
- The Extensions Index – a machine‑readable list of third‑party extensions and their repositories. The skill should iterate through the index files and clone each listed repository so that extension code is available for searching.
- The Discourse archive – a mirror of the Slicer Discourse forum content (see https://github.com/pieper/slicer-discourse-archive) to allow question‑answering based on past community discussions.
- The NA-MIC Project Week repository – a collection of tutorials, presentations, and code
from NA-MIC Project Weeks (https://github.com/NA-MIC/ProjectWeek), providing additional
examples and educational materials for Slicer programming. The
scripts/extract_pw_stats.pyutility can be used to extract statistics about project weeks, including participant lists and project counts. This is useful for finding papers, collaborations, or expertise by searching for people who have attended NA-MIC Project Weeks. - Build dependencies (VTK, ITK, CTK, etc.) – cloned from SuperBuild references. (Local in full mode only. In other modes, browse via GitHub API.)
- Coding conversations (optional) – JSONL transcripts of AI-assisted coding sessions captured by the CodingChats VS Code extension. (Cloned in full and lightweight modes when the repo exists.)
With these resources available locally, the agent can use standard command‑line tools
(git grep, grep, find, etc.) to search for symbols, examples, documentation,
Python modules, build configurations, and other snippets that help it craft accurate and
precise responses to programming questions about Slicer.
📁 Repositories are checked out into subdirectories of the skill workspace named
slicer-source,slicer-extensions,slicer-discourse,slicer-dependencies,slicer-projectweek, andcoding-chatsrespectively. You are free to override these paths by setting theSLICER_SRC_DIR,SLICER_EXT_DIR,SLICER_DISCOURSE_DIR,SLICER_DEP_DIR,SLICER_PROJECTWEEK_DIR, andCODING_CHATS_DIRenvironment variables before running the setup script.
Prerequisites
The setup script requires the following tools to be available on $PATH:
- git – for cloning and updating repositories (not needed in web mode).
- perl – used to parse CMake files when resolving SuperBuild dependencies (full mode only).
- bash – the setup script targets Bash (macOS
/bin/bashor Linux).
On macOS the built-in versions of these tools are sufficient. On minimal Linux
containers you may need to install perl and git explicitly.
For web mode, the agent needs network access to github.com and
discourse.slicer.org. If the gh CLI is authenticated, GitHub API rate limits
are much higher (5,000/hr vs 60/hr unauthenticated).
Setup Instructions
Run the setup script:
./setup.sh # interactive mode selection on first run
./setup.sh --mode full # or: lightweight, web
./setup.sh --force # re-run ignoring 24h cooldown
The script checks available disk space and warns if full mode may be tight.
On first run it presents an interactive menu; subsequent runs reuse the previous
choice (stored in .setup-stamp.json).
What each mode creates
Full mode creates/updates:
slicer-source–git cloneofhttps://github.com/Slicer/Slicer.gitslicer-extensions– ExtensionsIndex + all ~200 extension repositoriesslicer-discourse–git cloneof the discourse archiveslicer-dependencies– SuperBuild dependency repositories (VTK, ITK, CTK, etc.)CodingChats-conversations(optional) – coding session transcripts
Lightweight mode creates/updates:
slicer-source– same as fullslicer-extensions– ExtensionsIndex JSON metadata only (no extension repo clones)CodingChats-conversations(optional) – same as full
Web mode creates:
- Only
.setup-stamp.json— no repositories are cloned
The script is idempotent; re-running it will git pull existing clones rather than cloning
afresh. On completion it writes a .setup-stamp.json timestamp file. Subsequent runs
automatically skip if the stamp is less than 24 hours old. Pass --force to bypass the
age check.
Switching modes
To switch from one mode to another, pass the new mode explicitly:
./setup.sh --force --mode full # upgrade from lightweight to full
./setup.sh --force --mode web # downgrade (existing clones remain on disk)
Note: switching to a lighter mode does not delete existing clones. The agent will simply stop using them. Delete the directories manually if you want to reclaim space.
Verifying the setup
cat .setup-stamp.json # check "mode" field
# Full mode:
ls slicer-source/CMakeLists.txt slicer-extensions/README.md slicer-discourse/README.md slicer-dependencies/VTK
# Lightweight mode:
ls slicer-source/CMakeLists.txt slicer-extensions/README.md
# Web mode: nothing to verify locally
How the Agent Should Use the Data
First, check the active mode by reading .setup-stamp.json in the skill workspace
and looking at the "mode" field. This determines which search strategies are available.
Performance hint: If you are in
weborlightweightmode and a task is taking noticeably long due to repeated API calls, rate-limit errors, or slow web fetches, proactively suggest that the user upgrade to a heavier mode for faster local searches. For example: "This search is slow over the GitHub API. You could switch to lightweight mode (./setup.sh --force --mode lightweight) to get local source for much faster grep, or full mode (./setup.sh --force --mode full) to also have extensions, dependencies, and the discourse archive on disk." Match the suggestion to what's actually bottlenecking — if only Discourse searches are slow, suggest full mode; if code search is slow, lightweight may suffice.
Ranked search via the slicer-skill-search MCP server (preferred)
setup.sh builds two complementary indexes over slicer-source/ and
slicer-discourse/ and registers a stdio MCP server (slicer-skill-search)
that exposes ranked retrieval. Prefer these tools over grep/git grep
for natural-language and exploratory queries — they return ranked results
with snippets instead of an unranked dump of every match.
Two tools are exposed:
search_source(query, top_k=10, mode="auto", lexical_weight=1.0, vector_weight=1.0)search_discourse(query, top_k=10, mode="auto", lexical_weight=1.0, vector_weight=1.0)
Plus index_status() to check index freshness.
Pick mode by the shape of your query:
| mode | What it does | Best for |
|---|---|---|
lexical |
BM25 over tokenized text | Concrete identifiers, symbols, paths, error strings, rare keywords (e.g. vtkMRMLScalarVolumeNode, arrayFromVolume, CMAKE_PREFIX_PATH) |
vector |
Dense embeddings (sentence-transformers/all-MiniLM-L6-v2) | Conceptual / paraphrased queries where the answer probably uses different words than the question (e.g. "how do I draw a bounding box around the lesion", "why does my volume look flipped after export") |
hybrid |
Reciprocal Rank Fusion of both | The safe default when you don't know which side will fire — combines exact-match precision with semantic recall |
auto |
Pick hybrid if both indexes exist, else fall back |
Default. Good for almost everything. |
On-the-fly weighting in hybrid mode. When you have a sense of which signal
should matter more for a particular query, set lexical_weight and
vector_weight (defaults 1.0 each). Examples:
- A query containing a precise symbol plus prose ("how does
vtkMRMLScalarVolumeNode::GetImageDatainteract with image observers"):mode="hybrid", lexical_weight=2.0, vector_weight=1.0. - A purely conceptual query with no special keywords ("converting tumor
volume to a printable mesh"):
mode="hybrid", lexical_weight=0.5, vector_weight=1.5, or justmode="vector".
Result shape. Each hit is {path, abs_path, score, line, snippet}. Use
the standard Read tool with abs_path to fetch full files, optionally with
offset=line for a targeted read.
Fallback. If index_status() shows an index is missing or stale, or you
need to search a corpus the MCP doesn't index (extensions, dependencies,
project week, coding chats), fall through to raw shell tools below.
Raw shell search (extensions, dependencies, on-demand corpora)
When repositories are available locally, search, read, and reason over them:
- Search extension code (full mode) under
slicer-extensions/<Name>/. CLI example:find slicer-extensions/ -name "*.md" -exec grep -l "<topic>" {} \;. - Inspect build dependencies (full mode) in
slicer-dependencieswhen reasoning about build-time behavior, API versions, or exact tags used by the SuperBuild. CLI example:git -C slicer-dependencies/VTK grep -rn "vtkNew". - Search coding conversations in
CodingChats-conversations/sessions/for past AI sessions that discuss the same topic. These JSONL transcripts show what approaches were tried, what failed, and what prompts led to working solutions. CLI example:grep -rn "SegmentEditor" CodingChats-conversations/sessions/. - Understand project structure by reading CMakeLists, Python
__init__.pyfiles, and other configuration files in the clones. - Code symbols / file-name lookups in slicer-source itself can also use raw
git grep/findif you prefer them over the ranked MCP search.
Agents with higher-level file search and content search tools (e.g. Glob, Grep, Read) should prefer those over raw shell commands when available. The CLI examples above are provided for reference and for agents that only have shell access.
Extension documentation search (full mode)
In full mode, all extension repositories are pre-cloned into slicer-extensions/. When
researching a topic, explicitly check documentation files in all extension directories
for additional help and examples. Many extensions contain valuable tutorials, usage examples,
and implementation details that complement the main Slicer documentation.
Look for files like:
-
README.md- General extension documentation and usage -
SKILL.md- AI agent guidance (if present, similar to this file) -
Documentation in
docs/,Documentation/, or similar directories -
Tutorial files, example scripts, and implementation guides
-
Search extension docs:
find slicer-extensions/ -name "*.md" -exec grep -l "<topic>" {} \; -
Read extension documentation: Check
slicer-extensions/<ExtensionName>/README.mdandslicer-extensions/<ExtensionName>/SKILL.md(if present) for usage examples and guidance -
Browse extension source: Look at
slicer-extensions/<ExtensionName>/for code examples and module implementations
On-demand extension cloning (lightweight mode)
In lightweight mode, extension source code is not pre-cloned. When you need to search or read an extension's source:
- Find the extension's repository URL from the ExtensionsIndex JSON file:
grep -l "ExtensionName" slicer-extensions/*.jsonthen read the"scm_url"field. - Clone it on-demand:
git clone --depth 1 <url> slicer-extensions/<name> - The clone persists for future queries in the same session.
Web-based search strategies (lightweight fallback and web mode)
When local data is not available, use these web APIs:
- Discourse search:
curl -s "https://discourse.slicer.org/search.json?q=<query>"Supports filters:category:support,order:latest,after:2025-01-01. Read a topic:curl -s "https://discourse.slicer.org/t/<id>.json" - GitHub code search (requires
ghCLI):gh search code "<query>" --repo Slicer/Slicer --limit 20 - Read files from GitHub:
gh api repos/Slicer/Slicer/contents/<path> --jq '.content' | base64 -dOr raw URLs:https://raw.githubusercontent.com/Slicer/Slicer/main/<path> - Extension metadata:
gh api repos/Slicer/ExtensionsIndex/contents/<Name>.json --jq '.content' | base64 -d - Dependency source:
gh search code "<query>" --repo Kitware/VTK --limit 20
Search strategy by mode
| Resource | full | lightweight | web |
|---|---|---|---|
| Slicer source | local grep/find | local grep/find | GitHub API / raw URLs |
| Extensions | local grep/find | on-demand clone | GitHub API / raw URLs |
| Dependencies | local grep/find | GitHub API / raw URLs | GitHub API / raw URLs |
| Discourse | local grep | Discourse search API | Discourse search API |
| GitHub Issues/PRs | GitHub search API | GitHub search API | GitHub search API |
| Coding chats | local grep | local grep | not available |
The goal is not merely to index, but to reason over the material. For example, when
asked "how do I add a module to the build", the agent can search CMake macros in
slicer-source (or via GitHub API) and provide a snippet of the real call sites.
Script Repository
The Slicer source tree contains a rich collection of scripted examples and utilities
under the Script Repository section of the documentation (located in
slicer-source/Docs/developer_guide/script_repository.md and related files). When
implementing or explaining Slicer features, agents should search the script repository
first — it contains working Python snippets that demonstrate how to accomplish common
tasks such as:
- Loading and saving data (volumes, models, segmentations, transforms, etc.)
- Manipulating MRML nodes and the scene graph
- Working with the Segment Editor and its effects
- Creating and updating views, layouts, and widget properties
- Accessing volume data as NumPy arrays via
slicer.util.arrayFromVolume - Running CLI modules and connecting to module logic classes
- Registering custom keyboard shortcuts, timers, and event observers
These snippets are the closest equivalent to "official cookbook recipes" and are frequently more accurate and idiomatic than ad-hoc code generation. When answering a user's question, prefer citing or adapting a script repository example over writing code from scratch.
The script repository is assembled from per-topic markdown files. The main entry point
is slicer-source/Docs/developer_guide/script_repository.md, which includes:
| File | Topics covered |
|---|---|
script_repository/gui.md |
Layouts, views, widget access, keyboard shortcuts |
script_repository/volumes.md |
Loading volumes, NumPy access, scalar/vector data |
script_repository/segmentations.md |
Segment Editor, effects, import/export |
script_repository/transforms.md |
Linear and non-linear transforms |
script_repository/markups.md |
Fiducials, curves, planes, ROIs |
script_repository/models.md |
Surface meshes, polydata, model display |
script_repository/dicom.md |
DICOM loading, exporting, database |
script_repository/plots.md |
Chart views and plot series |
script_repository/sequences.md |
Time sequences, browsing, replay |
script_repository/registration.md |
Image registration workflows |
script_repository/screencapture.md |
Screenshots, video, 3D export |
script_repository/subjecthierarchy.md |
Subject hierarchy tree operations |
script_repository/tractography.md |
Diffusion tractography |
script_repository/batch.md |
Batch processing patterns |
script_repository/webserver.md |
Slicer web server API |
When searching for an example, grep within these files by topic keyword rather than searching the entire source tree.
Slicer Architecture — Where to Learn About Key Concepts
Rather than duplicating Slicer's documentation, this section tells you where to look in the checked-out repositories to learn about each major concept. Read the referenced files directly when you need to understand or explain a topic.
Project Structure
Inspect slicer-source/ to understand the top-level layout:
Base/— Core application framework.Base/Python/slicer/— TheslicerPython package (util.py,ScriptedLoadableModule.py, etc.). Read these to understand the Python API surface.Base/QTCore/— Non-GUI application logic (settings, I/O manager, module factory).Base/QTGUI/— Main application GUI (layout manager, module panel, data widgets).Base/Logic/— Application-level logic classes.
Libs/— Shared libraries that do not depend on Qt.Libs/MRML/Core/— The MRML scene graph: node classes, events, serialization. Header files (vtkMRML*.h) document the node hierarchy.Libs/vtkSegmentationCore/— Segmentation data structures and conversion logic.Libs/vtkITK/— VTK/ITK bridge filters.Libs/vtkTeem/— Teem-based readers (NRRD, DWI).
Modules/— Built-in modules, organized by type:Modules/Loadable/— C++ modules with Qt UI (Volumes, Segmentations, Markups, Transforms, Models, VolumeRendering, etc.).Modules/Scripted/— Python-only modules (SegmentEditor, DICOM, SampleData, ExtensionWizard, SegmentStatistics, etc.).Modules/CLI/— Command-line interface modules (filters, registration, model makers).
Docs/developer_guide/— Developer documentation in Markdown/RST.SuperBuild/— CMakeExternal_*.cmakefiles that define each dependency's repository URL, tag, and build flags.
Module Types
Slicer has three module types. To understand the conventions for each, read these reference implementations:
- Scripted modules: Read
slicer-source/Modules/Scripted/SampleData/orslicer-source/Modules/Scripted/SegmentStatistics/for the standard pattern: a module class, a widget class, a logic class, and a test class, all in Python. The base classes are defined inslicer-source/Base/Python/slicer/ScriptedLoadableModule.py. - Loadable modules (C++ with Qt UI): Read
slicer-source/Modules/Loadable/Volumes/orslicer-source/Modules/Loadable/Markups/for the pattern: aqSlicer*Moduleclass, a widget, a logic, and MRML node classes, built with CMake. - CLI modules: Read
slicer-source/Modules/CLI/AddScalarVolumes/for the minimal pattern: an XML description file and a C++ (or Python) executable usingSlicerExecutionModel.
For an overview document, read slicer-source/Docs/developer_guide/module_overview.md.
MRML (Medical Reality Markup Language)
MRML is the in-memory scene graph that holds all data. To learn about it:
- Read
slicer-source/Docs/developer_guide/mrml_overview.mdfor the conceptual overview. - Read
slicer-source/Docs/developer_guide/mrml.mdfor the developer reference. - Browse header files in
slicer-source/Libs/MRML/Core/— eachvtkMRML*Node.hfile documents a node type (volume, model, segmentation, transform, display, storage, etc.). - For the Python API to the scene, read
slicer-source/Base/Python/slicer/util.py— functions likegetNode(),loadVolume(),arrayFromVolume(), andupdateVolumeFromArray()are defined there.
Segment Editor
The Segment Editor is one of Slicer's most complex subsystems. To understand it:
- Read
slicer-source/Modules/Scripted/SegmentEditor/for the module and widget. - Read the Python effects in
slicer-source/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorEffects/— each file (SegmentEditorThresholdEffect.py,SegmentEditorDrawEffect.py, etc.) implements one effect and serves as a template for custom effects. - Read the abstract base classes in the same directory
(
AbstractScriptedSegmentEditorEffect.py, etc.) to understand the effect API. - Search the script repository file
script_repository/segmentations.mdfor usage examples.
VTK and ITK Patterns
When questions involve VTK or ITK classes:
- Search
slicer-dependencies/VTK/for VTK header files and examples. - Search
slicer-dependencies/ITK/for ITK header files and examples. - Read
slicer-source/Libs/vtkITK/for how Slicer bridges VTK and ITK. - Read
slicer-source/Docs/developer_guide/vtkAddon.mdfor Slicer's VTK add-on utilities. - For VTK pipeline patterns used in Slicer modules, browse
.cxxfiles inslicer-source/Modules/Loadable/— these show real-world VTK pipeline construction, smart pointer usage, and observer patterns.
Build System
Slicer uses CMake with a SuperBuild pattern:
slicer-source/CMakeLists.txt— top-level build configuration.slicer-source/SuperBuild/External_*.cmake— one file per dependency, specifying the repository URL, git tag, and CMake arguments. Read these to find the exact version of VTK, ITK, CTK, DCMTK, etc. that Slicer uses.slicer-source/Docs/developer_guide/build_instructions/— platform-specific build guides.- For module-level CMake patterns, read
CMakeLists.txtin any module underModules/Loadable/orModules/CLI/.
macOS Packaging and Qt6 Startup (hard-won)
The macOS .app has no launcher process (unlike Linux/Windows and unlike the
build tree, which use the CTK application launcher). The app self-configures its
environment in the qSlicerCoreApplication constructor body — but that runs
after the QApplication base constructor has already loaded the Qt platform
plugin. See Base/QTApp/qSlicerApplicationHelper.cxx::preInitializeApplication,
which runs from main() before the app object and sets QT_PLUGIN_PATH for
exactly this reason.
Qt6 platform-plugin resolution order (traced from qtbase src/gui/kernel/
qguiapplication.cpp init_platform + qplatformintegrationfactory.cpp +
src/corelib/plugin/qfactoryloader.cpp + qcoreapplication.cpp libraryPathsLocked):
QT_QPA_PLATFORM_PLUGIN_PATH(the "extra search path"). This — notQT_PLUGIN_PATH— is the path shown in the errorCould not find the Qt platform plugin "cocoa" in "<path>". It is usually empty (""), which is a red herring, not the cause.- Each
QCoreApplication::libraryPaths()entry +/platforms, wherelibraryPaths()=QT_PLUGIN_PATHentries + the Qt installPluginsPath(overridable by aqt.conf[Paths] Plugins=entry) + the bundle'sContents/PlugIns.
Slicer installs plugins to Contents/lib/QtPlugins (non-standard) and points
QT_PLUGIN_PATH there. That is correct only if the plugin is a real, loadable
file. The message wording distinguishes the failure: "Could not find …"
means the plugin never entered keyMap() (missing / dangling / not a valid
plugin); "Could not load … even though it was found" means the file was
present but failed to load (bad deps, wrong Qt, invalid signature).
Bundle fixup pipeline (CMake/SlicerCPackBundleFixup.cmake.in, configured to
Slicer-build/CMake/SlicerCPackBundleFixup/): CPack stages the .app (as
Slicer.app), runs BundleUtilities fixup_bundle() to copy external libs/Qt
frameworks in and rewrite install names to @rpath/..., re-signs, then renames to
the display name. Slicer_QtPlugins_DIR = lib/QtPlugins; embedded frameworks
live in Contents/Frameworks, referenced as @rpath/Frameworks/Qt*.framework/....
macOS Qt6 packaging pitfalls seen in practice (a distributable bundle must be validated by launching it off the build machine — packageverify only checks Mach-O resolution and misses all of these):
- Homebrew ships plugins as symlinks into the versioned Cellar
(
share/qt/plugins/platforms/libqcocoa.dylib -> ../../../../Cellar/...).install(PROGRAMS)copies the symlink verbatim, so it dangles once the bundle moves. ResolveREALPATHbefore installing (SlicerBlockInstallQtPlugins.cmake). - Two copies of Qt loaded ("You might be loading two sets of Qt binaries",
moveToThreadfailures, duplicate objc classes): a bundled binary still references the external Qt (absolute/opt/homebrew/...or a bare@rpath/QtCore.frameworkthat resolves via a leftover/opt/homebrew/librpath). Every Qt dependency of every embedded Mach-O — plugins and frameworks — must be rewritten to@rpath/Frameworks/.... The framework-repair step must rewrite the repaired framework's own deps, not just its id. codesign --deepleaves invalid signatures on a bundle this large/nested (the CFBundleExecutable is a small bootstrap, so the real app binary and every module/plugin/framework is nested code). On Apple Silicon that is a fatalEXC_BAD_ACCESS/ SIGKILL "Code Signature Invalid" at load. Sign inside-out instead — every Mach-O on its own, deepest first,.applast (Utilities/Scripts/SlicerSignBundleMacOS.py).- Startup prewarm must tolerate a read-only install: the stamp goes in the
user cache (
~/Library/Caches/<App>/), never inside the bundle, and prewarm failure must never block launch (SlicerAppBootstrap.c.in,SlicerPrewarm.py).
Diagnosing a bundle that won't launch off-machine:
codesign --verify --deep --strict <app>and read~/Library/Logs/DiagnosticReports/<app>-*.ips—termination.namespace == "CODESIGNING"/"Invalid Page"is a signature problem, not a code bug.DYLD_PRINT_LIBRARIES=1 <app>/Contents/MacOS/SlicerApp-real ...then grep the loaded image paths for/opt/homebrew/or/Cellar/— any Qt loaded from there means an un-rewritten dependency.- Launch headless to a clean exit:
SlicerApp-real --no-splash --python-code "import qt; qt.QTimer.singleShot(3000, slicer.app.quit)"(rc=0= clean). - Broken plugin symlinks:
find <app>/Contents/lib/QtPlugins -type l(should be empty after the REALPATH install fix).
Extension Development
To understand how extensions are structured and distributed:
- Read
slicer-source/Docs/developer_guide/extensions.mdfor the developer guide. - Inspect the Extension Wizard at
slicer-source/Modules/Scripted/ExtensionWizard/— this is the tool that generates new extension scaffolding. - Browse
slicer-extensions/for real extension examples. Well-structured extensions that demonstrate common patterns include:slicer-extensions/SlicerIGT/— a multi-module C++ extension for image-guided therapy with loadable modules, transforms, and Qt widgets.slicer-extensions/MONAILabel/— a Python extension integrating deep learning inference.
- The
slicer-extensions/directory also contains.jsonindex files (e.g.SlicerIGT.json). These specify the repository URL, description, and dependencies for each extension. Read them when you need to locate an extension's source repository.
Python Utilities and the slicer Package
The slicer Python package is the primary API for scripting. To understand it:
- Read
slicer-source/Base/Python/slicer/util.py— this is the most important file. It defines data loading/saving functions, node access, array conversion, and UI utilities. - Read
slicer-source/Base/Python/slicer/ScriptedLoadableModule.py— defines the base classes for scripted modules (ScriptedLoadableModule,ScriptedLoadableModuleWidget,ScriptedLoadableModuleLogic,ScriptedLoadableModuleTest). - Read
slicer-source/Base/Python/slicer/parameterNodeWrapper/— the parameter node wrapper system for declarative module parameters. - Read
slicer-source/Base/Python/slicer/__init__.pyfor the top-level namespace (access toslicer.mrmlScene,slicer.app,slicer.modules, etc.).
Coding Style and Conventions
Slicer spans multiple toolkits, each with its own style. To understand what conventions to follow:
- Read
slicer-source/Docs/developer_guide/style_guide.md— the primary style reference. It links to the VTK, Qt, and Python (PEP 8) conventions and explains when each applies. - Read
slicer-source/CONTRIBUTING.mdfor contribution guidelines. - For Python style in Slicer modules specifically, examine existing scripted modules
(e.g.
Modules/Scripted/SegmentStatistics/) — they demonstrate Slicer naming conventions such asonApplyButton,setParameterNode, camelCase method names on widget classes, and thelogic/widget/testclass separation. - For C++ style, browse
.cxx/.hfiles inModules/Loadable/and follow the VTK conventions:vtkNew,vtkSmartPointer,SetX()/GetX()accessors, and thePrintSelf/Modified()pattern. - While unicode support has improved in recent years, it may still cause various errors. Let's keep using only ASCII characters in the source code.
- Do not require qt. If qt is available then use it (e.g., prompt the user using a popup window), but make these very useful classes available without qt as well.
- All strings that may be displayed to the user must be internationalized (using the _() function). See https://github.com/SoniaPujolLab/SlicerLanguagePacks/blob/main/DevelopersManual.md. Text intended only for developers can remain non-translatable. Text intended for very advanced users can remain non-translatable. Application log messages should not be translated.
Testing
To understand how Slicer modules are tested:
- Each scripted module can include a test class derived from
ScriptedLoadableModuleTest(defined inslicer-source/Base/Python/slicer/ScriptedLoadableModule.py). The standard pattern is arunTest()method that calls individual test functions. - See
slicer-source/Modules/Scripted/SegmentStatistics/Testing/andslicer-source/Modules/Scripted/SampleData/Testing/for Python test examples. - See
slicer-source/Modules/Scripted/SelfTests/for the self-test runner module. - For C++ module tests, browse
Testing/subdirectories under modules inModules/Loadable/— these use CTest and Google Test patterns. - Read
slicer-source/Docs/developer_guide/debugging/for debugging guides across platforms and IDEs (VS Code, Qt Creator, CLion, etc.). - Read
slicer-source/Docs/developer_guide/python_faq.mdfor common Python environment questions includingPythonSlicer, virtual environments, and package installation.
Discourse — Searching Community Knowledge
Full mode (local archive):
The discourse archive contains ~18,700 rendered forum topics organized by year and month:
slicer-discourse/archive/rendered-topics/
2017/ 2018/ 2019/ 2020/ 2021/ 2022/ 2023/ 2024/ 2025/ 2026/
YYYY-MM/
YYYY-MM-DD-topic-slug-idNNNNN.md
Each file is a single Discourse thread rendered as Markdown. The filename includes a date, a human-readable slug, and the topic ID. To search effectively:
- Grep across the archive for keywords (e.g.
grep -rn "arrayFromVolume" slicer-discourse/). - Use the
slicer-discourse/archive/INDEX.mdfile for an overview.
Lightweight and web modes: Use the Discourse search API as described in the "Web-based search strategies" section above.
In any mode, forum threads often explain why things work a certain way, not just how — search the discourse when code-search alone is insufficient.
GitHub Issues and Pull Requests
GitHub issues and PRs complement Discourse and source code in these situations:
- Specific error message or traceback — issues often contain exact error text and the accepted resolution. Discourse posts frequently omit full tracebacks.
- "Is this a known bug?" — search closed issues to confirm and find workarounds.
- "When was X added / why was Y removed?" — PR descriptions explain the motivation
for API changes in a way that
git logalone does not. - Discovering undocumented pitfalls — closed bug reports surface gotchas that never make it into official docs or the Common Pitfalls section below.
Use the GitHub REST API directly (no CLI dependency required):
# Search closed issues for a keyword or error message
curl -s "https://api.github.com/search/issues?q=<keyword>+repo:Slicer/Slicer+type:issue+state:closed&per_page=10"
# Search merged PRs for an API symbol or topic
curl -s "https://api.github.com/search/issues?q=<symbol>+repo:Slicer/Slicer+type:pr+is:merged&per_page=10"
# Read a specific issue or PR body
curl -s "https://api.github.com/repos/Slicer/Slicer/issues/<number>"
curl -s "https://api.github.com/repos/Slicer/Slicer/pulls/<number>"
# Fetch comments on an issue (where the resolution often appears)
curl -s "https://api.github.com/repos/Slicer/Slicer/issues/<number>/comments"
Unauthenticated requests are rate-limited to 60/hr; set a GITHUB_TOKEN environment
variable to raise this to 5,000/hr. Prefer Discourse over issues/PRs for how-to and
workflow questions; prefer issues/PRs when debugging concrete errors or tracing API
evolution.
Prefer Existing APIs Over Reimplementation
Before writing custom math, geometry, image processing, or data-manipulation code, search for an existing implementation in the libraries Slicer already bundles. Reimplementing functionality that VTK, ITK, or Slicer itself already provides is a common source of bugs, coordinate-system errors, and maintenance burden.
Search order:
slicer.utiland MRML — checkslicer-source/Base/Python/slicer/util.pyand the script repository first. Many common operations (resampling, array conversion, node manipulation) are one-liners there.- VTK filters — search
slicer-dependencies/VTK/Filters/(or GitHub code search forvtk<Topic>) before implementing geometry, mesh, image, or math operations. VTK has filters for smoothing, decimation, boolean operations, distance fields, coordinate transforms, interpolation, and much more. - ITK filters — search
slicer-dependencies/ITK/Modules/for image-processing operations (registration, segmentation, morphology, statistics, etc.). Theslicer-source/Libs/vtkITK/bridge exposes many ITK filters directly to VTK pipelines. - Slicer CLI modules — check
slicer-source/Modules/CLI/for ready-made command-line operations (resampling, registration, model generation, etc.) that can be invoked from Python viaslicer.cli.run(). - Existing extensions — search
slicer-extensions/for an extension that already solves the problem. Reusing an extension's logic class is preferable to duplicating it.
When in doubt, grep the source trees for the mathematical or geometric concept
(e.g. "principal curvature", "marching cubes", "Hausdorff") before writing any
implementation — the answer is usually already there.
Common Pitfalls
These are frequently encountered mistakes that are not obvious from reading the source code alone. The agent should be aware of them when generating or reviewing Slicer code.
arrayFromVolumereturns a view, not a copy. After modifying the array in-place, you must callslicer.util.arrayFromVolumeModified(volumeNode)to notify the display pipeline. Forgetting this results in the view not updating.- MRML node names are not unique identifiers. Multiple nodes can share the same name.
Use
node.GetID()for reliable identification, notnode.GetName(). - The Python console runs on the main Qt thread. Long-running operations block the
UI. Use
slicer.app.processEvents()in loops or run work in a background thread withqt.QTimer.singleShot()callbacks. - Coordinate system conventions. Slicer uses RAS (Right-Anterior-Superior) internally, while many file formats and tools use LPS (Left-Posterior-Superior). Transforms between RAS and LPS are a common source of sign-flip bugs.
- Volume axis ordering.
slicer.util.arrayFromVolume()returns arrays in KJI order (slice, row, column), not IJK. This is the reverse of what many users expect. - Extension CMake patterns differ from standalone projects. Extensions must use
Slicer-specific CMake macros (e.g.
slicerMacroBuildScriptedModule,slicerMacroBuildLoadableModule). Using plainadd_librarywill not integrate correctly with Slicer's module loading system. slicer.util.pip_install()for runtime dependencies. Slicer bundles its own Python environment. Extensions should install additional Python packages viaslicer.util.pip_install("package")in their module code, not via system pip.
Common Workflows — Where to Find Each Step
Many Slicer tasks span multiple subsystems. Rather than documenting full workflows here, this section tells you which script repository files and source directories to consult for each step of common multi-step tasks.
Load DICOM data, segment a structure, export the result:
- DICOM import —
script_repository/dicom.md - Segmentation —
script_repository/segmentations.md - Export to STL/OBJ/NRRD — search
script_repository/segmentations.mdfor "export" andscript_repository/models.mdfor surface mesh saving
Create a new scripted module from scratch:
- Scaffolding —
slicer-source/Modules/Scripted/ExtensionWizard/ - Module pattern —
slicer-source/Modules/Scripted/SampleData/as a template - Parameter node wrapper —
slicer-source/Base/Python/slicer/parameterNodeWrapper/ - Testing —
slicer-source/Modules/Scripted/SegmentStatistics/Testing/
Add a custom Segment Editor effect:
- Base class API —
AbstractScriptedSegmentEditorEffect.pyinModules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorEffects/ - Example effects — other
SegmentEditor*Effect.pyfiles in the same directory - Registration — search
slicer-sourceforregisterEditorEffect
Build Slicer or an extension from source:
- Build instructions —
slicer-source/Docs/developer_guide/build_instructions/ - SuperBuild dependencies —
slicer-source/SuperBuild/External_*.cmake - Extension build —
slicer-source/Docs/developer_guide/extensions.md
Work with transforms and coordinate systems:
- Transform examples —
script_repository/transforms.md - RAS/LPS conventions — search
slicer-source/Docs/for "coordinate" or "RAS" - Transform node API —
slicer-source/Libs/MRML/Core/vtkMRMLTransformNode.h
MCP Server — Interacting with a Running Slicer Instance
The file slicer-mcp-server.py in this repository implements an MCP server that runs
inside Slicer, exposing tools like execute_python, screenshot, list_nodes,
write_file, and read_file over HTTP at http://localhost:2026/mcp. This turns a
running Slicer into something the agent can observe and drive directly.
Why it matters: prefer observation over recollection. When a question is checkable — why a module misbehaves, whether an API still exists, what a snippet actually returns, how a change affects the scene — running the code in a live Slicer beats reasoning from documentation and memory. Offer to start a dedicated Slicer instance rather than launching one unannounced, and never take over a Slicer the user started; it may hold unsaved work. Because each instance can pick its own port, several Slicers (different releases, a local build vs. a release, local vs. remote) can run at once, which makes differential debugging possible: send identical code to each endpoint and diff the results.
Read references/mcp.md for the mechanics — choosing a free port,
the bootstrap script and launch flags, verifying the endpoint, running several instances
for differential debugging, provisioning remote instances over an SSH tunnel, and the
/file endpoint for bulk file transfer.
Extending the Skill
Additional data sources can be added by editing setup.sh and updating this document.
For example, if a new GitHub repository is released with tutorials, the script can be
extended to clone that repository and document its purpose here.
Agents that understand the SKILLS.md format should parse this file and use its sections to bootstrap their reasoning about how to prepare and query the environment.
Design Principles
This skill was designed with specific trade-offs in mind. Future contributors (human or agent) should follow these principles when extending it:
-
Prefer pointers to copies. This file directs the agent to read specific files in the checked-out repositories rather than embedding code snippets or API documentation inline. The Slicer source tree, script repository, and developer guide are the single source of truth — duplicating their content here would create version skew as Slicer evolves. Pointers cost one extra file-read per query but are always accurate.
-
Be specific with pointers. Vague references ("look in the source") force expensive open-ended searches. Every pointer should name a concrete file or directory path and, where helpful, suggest a grep pattern or section heading. The agent should be able to resolve any pointer with a single Read or Grep operation.
-
Inline only what cannot be discovered. The "Common Pitfalls" section is the intentional exception to the pointers-over-copies rule. Pitfalls like RAS/LPS sign flips and KJI axis ordering live in the gap between the code and how people misuse it — they are not documented in any single source file and are not discoverable by code search. New pitfalls should be added here only when they meet this bar.
-
Keep the file under 600 lines. The Agent Skills convention recommends concise skill files to avoid overwhelming the agent's context window. If this file approaches the limit, move detailed content to supporting files in a
references/directory and link to them from here. -
Stay agent-agnostic. This skill targets any agent that understands the SKILLS.md convention (Claude Code, OpenAI agents, Codex, Cursor, etc.). Avoid features specific to a single agent runtime. The frontmatter uses only fields from the open Agent Skills standard.
-
Leverage all data sources available in the active mode. The unique strength of this skill is the combination of source code, extensions, dependencies, community discussions, and coding conversations. In lighter modes, some of these are accessed via web APIs rather than local clones, but the agent should still cross-reference multiple sources — for example, a discourse search may explain why something works a certain way when the source code only shows how.
-
Adapt to the active mode gracefully. Check
.setup-stamp.jsonat the start of a session. Use local tools (grep, find, git log) when data is available locally, and fall back to web APIs (GitHub API, Discourse API) when it is not. Never fail simply because a directory is missing — check the mode and use the appropriate strategy.
Created and maintained by the Slicer community.