Skip to main content

Defining Actions

Actions are the core building blocks of plugins. Each action represents a discrete unit of work that can be executed, tracked, and composed into pipelines.

Prerequisites

Read the Plugin System Overview to understand core concepts before defining actions.

Overview​

Synapse SDK provides two approaches to define actions:

ApproachBest ForFeatures
Function-based (@action)Simple, stateless operationsMinimal boilerplate, direct function call
Class-based (BaseAction)Complex workflows, multi-step processesState management, helper methods, step orchestration

Function-Based Actions​

Use the @action decorator for simple, single-function actions that don't require state management.

Decorator Syntax​

@action(
name: str | None = None, # Action name (defaults to function name)
description: str = '', # Human-readable description
params: type[BaseModel] | None = None, # Pydantic model for input validation
result: type[BaseModel] | None = None, # Pydantic model for result validation
category: PluginCategory | None = None, # Plugin category (optional)
)

Parameters​

ParameterTypeRequiredDescription
namestrNoAction identifier. Defaults to function name
descriptionstrNoHuman-readable description
paramstype[BaseModel]NoPydantic model for input validation (recommended)
resulttype[BaseModel]NoPydantic model for result validation
categoryPluginCategoryNoCategory for grouping actions

Example​

from pydantic import BaseModel, Field
from synapse_sdk.plugins import action, RuntimeContext

class ConvertParams(BaseModel):
input_path: str
output_format: str = Field(default='yolo', description='Target format')

class ConvertResult(BaseModel):
output_path: str
file_count: int

@action(
name='convert',
description='Convert dataset to target format',
params=ConvertParams,
result=ConvertResult,
)
def convert(params: ConvertParams, ctx: RuntimeContext) -> ConvertResult:
# Access validated parameters
source = params.input_path
target_format = params.output_format

# Report progress
ctx.set_progress(0, 100)

# Your conversion logic here
output_path = do_conversion(source, target_format)

ctx.set_progress(100, 100)

return ConvertResult(output_path=output_path, file_count=42)

Function Signature Requirements:

  • First argument: params (Pydantic model instance)
  • Second argument: ctx (RuntimeContext)

Good to know: The @action decorator attaches metadata to the function (_is_action, _action_name, _action_params, etc.) for automatic discovery.

Class-Based Actions​

Use BaseAction for complex workflows that require state management, helper methods, or multi-step orchestration.

Basic Structure​

from pydantic import BaseModel, Field
from synapse_sdk.plugins import BaseAction
from synapse_sdk.plugins.enums import PluginCategory

class TrainParams(BaseModel):
epochs: int = Field(default=10, ge=1, le=1000)
learning_rate: float = Field(default=0.001, gt=0, lt=1)
batch_size: int = Field(default=32, ge=1)

class TrainResult(BaseModel):
weights_path: str
final_loss: float

class TrainAction(BaseAction[TrainParams]):
"""Train a model on the dataset."""

# Optional: override if not using config.yaml
action_name = 'train'
category = PluginCategory.NEURAL_NET

# Optional: enable result validation
result_model = TrainResult

def execute(self) -> TrainResult:
# Access validated parameters via self.params
epochs = self.params.epochs
lr = self.params.learning_rate

# Log events
self.log('train_start', {'epochs': epochs, 'lr': lr})

for epoch in range(epochs):
# Report progress
self.set_progress(epoch + 1, epochs, step='train')

loss = train_one_epoch(epoch, lr)

# Record metrics
self.set_metrics({'loss': loss, 'epoch': epoch}, step='train')

return TrainResult(weights_path='/model/weights.pt', final_loss=loss)

Class Attributes​

AttributeTypeDescription
action_namestr | NoneAction identifier (injected from config.yaml if not set)
categoryPluginCategory | NoneCategory for grouping
input_typetype[DataType] | NoneSemantic input type for pipeline compatibility
output_typetype[DataType] | NoneSemantic output type for pipeline compatibility
params_modeltype[BaseModel]Auto-extracted from generic parameter
result_modeltype[BaseModel] | NoResultResult validation schema (default: NoResult)

Instance Methods​

MethodDescription
execute()Main logic (abstract, must override)
log(event, data, file)Log structured events
set_progress(current, total, step)Report progress
set_metrics(value, step)Record metrics
autolog(framework)Enable ML framework auto-logging

Available Base Classes​

Synapse SDK provides specialized base classes for common workflow types:

Base ClassCategoryLocationUse Case
BaseActionAnysynapse_sdk.pluginsGeneric actions
BaseTrainActionneural_netsynapse_sdk.pluginsModel training
BaseInferenceActionneural_netsynapse_sdk.pluginsModel inference
BaseExportActionexportsynapse_sdk.pluginsData export
BaseUploadActionuploadsynapse_sdk.pluginsData upload
DatasetAction-synapse_sdk.plugins.actions.datasetDataset operations

Good to know: Most base classes are re-exported from synapse_sdk.plugins for convenience. DatasetAction must be imported from synapse_sdk.plugins.actions.dataset.

BaseTrainAction​

Provides helper methods for training workflows:

from synapse_sdk.plugins import BaseTrainAction
from synapse_sdk.plugins.actions.train import BaseTrainParams # Not re-exported from synapse_sdk.plugins

class MyTrainParams(BaseTrainParams):
epochs: int = 100
dataset: int # Required for get_dataset()

class MyTrainAction(BaseTrainAction[MyTrainParams]):
def execute(self) -> dict:
# Fetch dataset from backend
dataset = self.get_dataset()

# Load checkpoint if resuming
checkpoint = self.get_checkpoint()

# Train model...
model_path = train(dataset, checkpoint)

# Upload trained model
model = self.create_model(model_path, name='my-model')

return {'model_id': model['id']}

Helper Methods:

  • get_dataset() - Fetch training dataset (requires dataset field in params model)
  • get_checkpoint() - Load checkpoint model if params.checkpoint is set
  • create_model(path, **kwargs) - Upload trained model to backend
  • get_model(model_id) - Retrieve model metadata

Good to know: get_dataset() requires your params model to have a dataset: int field. If not present, a ValueError is raised with instructions to either add the field or override get_dataset().

Progress Categories:

Access via instance attribute self.progress:

  • self.progress.DATASET - Data loading phase
  • self.progress.TRAIN - Training iterations
  • self.progress.MODEL_UPLOAD - Model upload phase

Result Validation​

Enable result validation by setting result_model:

from pydantic import BaseModel
from synapse_sdk.plugins import BaseAction, NoResult

class ExportResult(BaseModel):
output_path: str
record_count: int

class ExportAction(BaseAction[ExportParams]):
# Enable validation
result_model = ExportResult

def execute(self) -> ExportResult:
# Return validated result
return ExportResult(output_path='/data/export', record_count=1000)

Good to know: If result_model is not set (defaults to NoResult), result validation is skipped. When set, results are validated but failures only log warnings (non-blocking).

Parameter Models​

Use Pydantic models to define and validate action parameters.

Field Configuration​

from pydantic import BaseModel, Field
from typing import Literal

class AugmentationConfig(BaseModel):
"""Nested configuration for data augmentation."""
flip: bool = True
rotate: float = Field(default=0.0, ge=0, le=360)

class TrainParams(BaseModel):
# Required field
dataset: int

# With default and constraints
epochs: int = Field(default=100, ge=1, le=1000, description='Training epochs')

# With choices
optimizer: Literal['adam', 'sgd', 'adamw'] = 'adam'

# Nested model
augmentation: AugmentationConfig | None = None

Validators​

from pydantic import BaseModel, field_validator

class InferenceParams(BaseModel):
confidence: float = 0.5

@field_validator('confidence')
@classmethod
def validate_confidence(cls, v: float) -> float:
if not 0 <= v <= 1:
raise ValueError('Confidence must be between 0 and 1')
return v

Discovery Modes​

Synapse SDK discovers actions through three mechanisms:

from_path()​

Load plugin configuration from config.yaml:

from synapse_sdk.plugins.discovery import PluginDiscovery

# From directory (auto-finds config.yaml)
discovery = PluginDiscovery.from_path('/path/to/plugin')

# Or explicit path
discovery = PluginDiscovery.from_path('/path/to/plugin/config.yaml')

# List available actions (returns keys from config.yaml's actions section)
actions = discovery.list_actions() # e.g., ['train', 'infer', 'export']

# Get action class
action_cls = discovery.get_action_class('train')

Good to know: list_actions() returns the action names defined in config.yaml. The actual list depends on your plugin's configuration.

from_module()​

Discover actions by introspecting a Python module:

import my_plugin
from synapse_sdk.plugins.discovery import PluginDiscovery
from synapse_sdk.plugins.enums import PluginCategory

# Auto-discover @action functions and BaseAction subclasses
discovery = PluginDiscovery.from_module(my_plugin)

# Optional: specify name and category
discovery = PluginDiscovery.from_module(
my_plugin,
name='my-plugin',
category=PluginCategory.NEURAL_NET,
)

Good to know: from_module() scans for functions with _is_action=True attribute (from @action) and classes that subclass BaseAction.

discover_actions()​

Static analysis of source files (AST parsing):

from synapse_sdk.plugins.discovery import PluginDiscovery

# Discover without importing modules
actions = PluginDiscovery.discover_actions('/path/to/plugin')
# Returns: {'train': {'entrypoint': '...', 'input_type': '...', 'output_type': '...'}}

config.yaml Configuration​

Define plugin metadata and actions in config.yaml:

Basic Structure​

# Plugin metadata
name: YOLOv8 Training Plugin
code: yolov8
version: 0.1.0
category: neural_net

# Description
description: Train and deploy YOLOv8 object detection models
readme: README.md

# Data configuration
data_type: image
tasks:
- image.object_detection
- image.instance_segmentation

# Dependencies
package_manager: pip # or 'uv'
wheels_dir: wheels

# Environment variables
env:
LOG_LEVEL: INFO

# Actions
actions:
train:
entrypoint: plugin.train:TrainAction
method: job
description: Train a YOLOv8 model

infer:
entrypoint: plugin.inference:InferenceAction
method: task
description: Run inference on images

Actions Section​

FieldTypeRequiredDescription
entrypointstrYesModule path to action (module.path:ClassName)
methodstrNoExecution method: job, task, or serve
descriptionstrNoHuman-readable description
input_typestrNoSemantic input type (auto-synced from code)
output_typestrNoSemantic output type (auto-synced from code)

Execution Methods​

MethodStartupIsolationUse Case
taskUnder 1 secondProcess-levelQuick parallel tasks (default)
job~30 secondsFull isolationLong-running, heavy workloads
serveVariableContainerHTTP inference endpoints

Complete Example​

name: Image Classification Plugin
code: image-classifier
version: 1.0.0
category: neural_net
description: Train and deploy image classification models

data_type: image
tasks:
- image.classification

package_manager: pip
package_manager_options: []
wheels_dir: wheels

env:
CUDA_VISIBLE_DEVICES: '0'
LOG_LEVEL: INFO

runtime_env:
py_modules:
- ./plugin

actions:
train:
entrypoint: plugin.train:TrainAction
method: job
description: Train classification model
input_type: dm_v2_dataset
output_type: model_weights

infer:
entrypoint: plugin.inference:InferenceAction
method: task
description: Classify images
input_type: image_file
output_type: predictions

export:
entrypoint: plugin.export:ExportAction
method: task
description: Export model to ONNX
input_type: model_weights
output_type: onnx_model

What to Use and When​

SituationRecommended ApproachWhy
Simple data transformationFunction-based (@action)Minimal boilerplate, single function
Stateless utility operationsFunction-based (@action)No state management needed
Model training workflowClass-based (BaseTrainAction)Built-in dataset/model helpers
Model inferenceClass-based (BaseInferenceAction)Model loading helpers
Multi-step orchestrationClass-based with setup_steps()Step registry, rollback support
Progress tracking with phasesClass-basedProgress categories
Shared state across methodsClass-basedInstance attributes

Tip: Start with function-based actions for simple tasks. Migrate to class-based when you need state management, helper methods, or step orchestration.