Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
Algorithm IDs follow the pattern provider:algorithm_name:
Provider
Prefix
Example
Native QGIS (C++)
native:
native:buffer
QGIS (legacy Python)
qgis:
qgis:regularpoints
GDAL/OGR
gdal:
gdal:warpreproject
GRASS GIS
grass:
grass:v.buffer
PDAL (point clouds)
pdal:
pdal:info
Processing Models
model:
model:my_workflow
Custom plugin
{provider_id}:
myplugin:myalgorithm
Key Parameter Types
Parameter Class
Purpose
Read Method
QgsProcessingParameterFeatureSource
Vector input
parameterAsSource()
QgsProcessingParameterRasterLayer
Raster input
parameterAsRasterLayer()
QgsProcessingParameterNumber
Numeric value
parameterAsDouble() / parameterAsInt()
QgsProcessingParameterEnum
Dropdown choice
parameterAsEnum()
QgsProcessingParameterField
Attribute field
parameterAsString()
QgsProcessingParameterExpression
QGIS expression
parameterAsExpression()
QgsProcessingParameterCrs
CRS selection
parameterAsCrs()
QgsProcessingParameterExtent
Bounding box
parameterAsExtent()
QgsProcessingParameterBoolean
Toggle
parameterAsBool()
QgsProcessingParameterFeatureSink
Vector output
parameterAsSink()
QgsProcessingParameterRasterDestination
Raster output
(returned as path)
Critical Warnings
NEVER call processing.run() without wrapping it in try/except QgsProcessingException. Algorithm failures raise exceptions that MUST be caught.
NEVER use hardcoded algorithm IDs from external providers (GRASS, SAGA, OTB) without first verifying availability via QgsApplication.processingRegistry().algorithmById(). These providers may not be installed.
NEVER show GUI elements (message boxes, dialogs) from within processAlgorithm(). Algorithms run in background threads by default. ALWAYS use the feedback object for all user communication.
NEVER manually load output layers inside processAlgorithm() using QgsProject.instance().addMapLayer(). ALWAYS return the output ID and let the Processing framework manage results.
NEVER use hardcoded temp paths like /tmp/result.gpkg. ALWAYS use 'memory:' or QgsProcessing.TEMPORARY_OUTPUT for intermediate results.
ALWAYS check feedback.isCanceled() at the top of every loop iteration in custom algorithms. Failure to check causes unresponsive cancellation.
ALWAYS report progress in custom algorithms using feedback.setProgress() with a percentage (0-100).
ALWAYS declare all outputs in initAlgorithm(). Undeclared outputs are invisible to the Processing framework and cannot be used in models or chains.
Decision Tree
Which approach to use?
Need to run an existing algorithm?
├── Yes → processing.run("provider:algorithm", params)
│ ├── Need result in project? → processing.runAndLoadResults()
│ └── Need non-blocking? → QgsProcessingAlgRunnerTask
│
Need to create a custom algorithm?
├── For a QGIS plugin? → QgsProcessingAlgorithm subclass + QgsProcessingProvider
├── Standalone script? → @alg decorator (saved to Processing Scripts folder)
└── Quick prototype? → @alg decorator
Need to run same algorithm on many inputs?
└── Batch processing loop with processing.run() per iteration
Output type selection
Where should the output go?
├── Intermediate result (not saved) → 'memory:' or QgsProcessing.TEMPORARY_OUTPUT
├── Persistent file → '/path/to/output.gpkg' (vectors) or '/path/to/output.tif' (rasters)
└── Add to project automatically → processing.runAndLoadResults()
from qgis.core import QgsApplication, QgsProcessingException
import processing
defsafe_run(algorithm_id, params, context=None, feedback=None):
"""Run an algorithm after verifying it exists."""
registry = QgsApplication.processingRegistry()
if registry.algorithmById(algorithm_id) isNone:
raise QgsProcessingException(
f'Algorithm "{algorithm_id}" not found. 'f'Check that the required provider is installed and enabled.'
)
return processing.run(algorithm_id, params,
context=context, feedback=feedback)
Pattern 6: Batch Processing
import os
import processing
input_dir = '/data/input/'
output_dir = '/data/output/'
input_files = [f for f in os.listdir(input_dir) if f.endswith('.gpkg')]
for input_file in input_files:
input_path = os.path.join(input_dir, input_file)
output_path = os.path.join(output_dir, f'buffered_{input_file}')
try:
processing.run("native:buffer", {
'INPUT': input_path,
'DISTANCE': 50,
'OUTPUT': output_path
})
except QgsProcessingException as e:
print(f"Failed for {input_file}: {e}")
Common Operations
Discover Available Algorithms
from qgis.core import QgsApplication
registry = QgsApplication.processingRegistry()
# List all providersfor provider in registry.providers():
print(provider.id(), provider.name())
# List algorithms from a providerfor alg in registry.algorithms():
if alg.provider().id() == 'native':
print(alg.id(), alg.displayName())
# Look up a specific algorithm
alg = registry.algorithmById('native:buffer')
if alg:
print(alg.shortHelpString())
Custom Algorithm Required Methods
Method
Required
Purpose
name()
YES
Unique ID (lowercase, no spaces)
displayName()
YES
User-visible name
initAlgorithm(config)
YES
Define parameters
processAlgorithm(parameters, context, feedback)
YES
Core logic
createInstance()
YES
Return new instance of the algorithm
group() / groupId()
Recommended
Category in toolbox
shortHelpString()
Recommended
Help text in dialog
tags()
Optional
Search keywords
flags()
Optional
e.g., FlagNoThreading
Register Custom Provider in Plugin
# In plugin __init__.py or main modulefrom qgis.core import QgsApplication
from .provider import MyPluginProvider
classMyPlugin:
def__init__(self, iface):
self.provider = NonedefinitGui(self):
self.provider = MyPluginProvider()
QgsApplication.processingRegistry().addProvider(self.provider)
defunload(self):
QgsApplication.processingRegistry().removeProvider(self.provider)
Plugin metadata.txt MUST include: hasProcessingProvider=yes
Threading Flags
If your algorithm uses GUI elements or non-thread-safe APIs, set FlagNoThreading: