Install
$ agentstack add skill-impertio-studio-speckle-claude-skill-package-speckle-impl-automate-functions ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
speckle-impl-automate-functions
Quick Reference
Functions vs Automations
| Concept | What It Is | Created By | Scope | |---------|-----------|------------|-------| | Function | Reusable code template defining execution logic | Developer | Global — listed in Function Library | | Automation | Configured instance of a Function bound to a model | Project owner / admin | Project-specific — triggers on version creation |
Trigger Flow
1. User publishes new version to a model
2. Speckle Server detects version creation event
3. Server finds all automations bound to that model
4. For each automation, Speckle spins up a Docker container
5. Function code executes with access to the new version data
6. Results (pass/fail, annotations, files) attach to the version
7. Results appear in the Speckle web UI and 3D viewer
SDK Packages
| Language | Package | Target | Input Class | |----------|---------|--------|-------------| | Python | specklepy (3.1.0+, includes automate) | Python 3.10+ | AutomateBase (Pydantic) | | C# | Speckle.Automate.Sdk (NuGet, 3.4.0-alpha.20) | .NET 8.0 | readonly struct with DataAnnotations |
AutomationContext Methods
| Method (Python) | Method (C#) | Purpose | |----------------|-------------|---------| | receive_version() | ReceiveVersion() | Retrieve the root Base object for the triggering version | | attach_error_to_objects(category, object_ids, message) | AttachErrorToObjects(category, objectIds, message) | Annotate specific objects with errors in the 3D viewer | | mark_run_success(message) | MarkRunSuccess(message) | Explicitly mark the run as successful | | mark_run_failed(message) | MarkRunFailed(message) | Explicitly mark the run as failed (intentional validation failure) | | store_file_result(file_path) | StoreFileResult(filePath) | Attach a file artifact to the run results | | set_context_view() | SetContextView() | Configure the 3D viewer URL for the run result |
Critical Warnings
ALWAYS call either mark_run_success() or mark_run_failed() before the function exits. If neither is called and no exception occurs, the run status is ambiguous and unreliable.
NEVER pass an empty list to attach_error_to_objects(). Empty or invalid object IDs produce silent failures with no visible annotations in the viewer.
NEVER use plain str for sensitive inputs (API keys, tokens). ALWAYS use SecretStr (Python) or [Secret] attribute (C#) to prevent exposure in logs and the Speckle UI.
NEVER modify or delete the auto-generated .github/workflows/main.yml environment variables (SPECKLE_FUNCTION_ID, SPECKLE_FUNCTION_TOKEN). Removing these breaks the deployment pipeline completely.
NEVER expect a function to appear in the Function Library without creating a GitHub release. Pushing code to the repository alone is NOT sufficient for publishing.
ALWAYS provide title and description on every input field. Without metadata, the Speckle UI shows raw field names that are meaningless to end users.
Python Function Template
Project Structure
my-automate-function/
├── main.py # Function entry point
├── flatten.py # Object traversal utility
├── pyproject.toml # Dependencies (specklepy)
├── Dockerfile # Container image definition
├── tests/ # Local test suite
│ └── test_function.py
├── .env.example # Environment variable template
└── .github/
└── workflows/
└── main.yml # CI/CD — auto-generated by wizard
Entry Point Pattern (Python)
from speckle_automate import (
AutomateBase,
AutomationContext,
execute_automate_function,
)
from pydantic import Field, SecretStr
class FunctionInputs(AutomateBase):
param_name: str = Field(title="Parameter", description="Describe this input")
def automate_function(
automate_context: AutomationContext,
function_inputs: FunctionInputs,
) -> None:
base = automate_context.receive_version()
# ... validation logic ...
automate_context.mark_run_success("Validation passed.")
if __name__ == "__main__":
execute_automate_function(automate_function, FunctionInputs)
CRITICAL: Pass automate_function WITHOUT parentheses and FunctionInputs as a CLASS (not an instance). The Automate runtime handles instantiation and injection.
flatten_base Traversal
from specklepy.objects import Base
from typing import Iterable
def flatten_base(base: Base) -> Iterable[Base]:
"""Recursively flatten a Base object hierarchy (depth-first, bottom-up)."""
elements = getattr(base, "elements", getattr(base, "@elements", None))
if elements is not None:
for element in elements:
yield from flatten_base(element)
yield base
This function:
- Uses
getattrwith fallback to handle bothelementsand@elementsnaming conventions - Yields descendants before the parent (depth-first, bottom-up order)
- Returns
Iterable[Base]for lazy evaluation — memory-efficient for large models - Is included in the official Python template as
flatten.py
C# Function Template
Project Structure
MyAutomateFunction/
├── MyAutomateFunction/
│ ├── AutomateFunction.cs # Function logic
│ ├── FunctionInputs.cs # Input schema definition
│ ├── Program.cs # DI entry point
│ └── MyAutomateFunction.csproj # .NET 8.0, NuGet refs
├── TestAutomateFunction/ # Integration tests
│ └── TestAutomateFunction.cs
├── Dockerfile # Multi-stage build
└── .github/
└── workflows/
└── main.yml # CI/CD — auto-generated by wizard
Entry Point Pattern (C#)
// Program.cs
using Microsoft.Extensions.DependencyInjection;
using Speckle.Automate.Sdk;
var serviceCollection = new ServiceCollection();
serviceCollection.AddAutomateSdk();
serviceCollection.AddSingleton();
var serviceProvider = serviceCollection.BuildServiceProvider();
var runner = serviceProvider.GetRequiredService();
var function = serviceProvider.GetRequiredService();
return await runner.Main(args, function.Run);
Function Class (C#)
using Speckle.Automate.Sdk;
using Speckle.Sdk.Models.Extensions;
public class AutomateFunction
{
public async Task Run(
IAutomationContext automationContext,
FunctionInputs functionInputs)
{
var rootObject = await automationContext.ReceiveVersion();
var allObjects = rootObject.Flatten().ToList();
// ... validation logic ...
automationContext.MarkRunSuccess("Validation passed.");
}
}
CRITICAL: The C# SDK uses IAutomationContext (interface), NOT a concrete class. The Flatten() extension method from Speckle.Sdk.Models.Extensions replaces the manual flatten_base() pattern used in Python.
Input Schema Definition
Python (Pydantic)
class FunctionInputs(AutomateBase):
category_filter: str = Field(
title="Category Filter",
description="Only check objects in this category"
)
max_count: int = Field(
default=100, title="Maximum Count", ge=1, le=10000
)
api_key: SecretStr = Field(title="External API Key")
strict_mode: bool = Field(
default=False, title="Strict Mode",
description="Fail on warnings too"
)
C# (DataAnnotations)
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
public readonly struct FunctionInputs
{
[Required]
public string CategoryFilter { get; init; }
[DefaultValue(100)]
[Range(1, 10000)]
public int MaxCount { get; init; }
[Required]
[Secret]
public string ApiKey { get; init; }
[DefaultValue(false)]
public bool StrictMode { get; init; }
}
ALWAYS keep inputs flat and simple. Deeply nested objects, lists of objects, or union types may NOT render correctly in the Speckle UI form.
Error Reporting
Three Outcome States
| State | Cause | Meaning | |-------|-------|---------| | Success | mark_run_success() called | Model meets all criteria | | Failed | mark_run_failed() called | Intentional validation failure — model does NOT meet criteria | | Exception | Unhandled exception / crash | Code error or platform failure |
Result Visibility
- 3D Viewer: Doughnut icon on the model with green/red pass/fail indicators
- Project Dashboard: Automation status indicators
- Run Cards: Detailed messages, annotated objects, file artifacts
- Object Annotations:
attach_error_to_objects()highlights specific objects in the viewer, grouped by category
File Artifacts
Call store_file_result("report.pdf") to attach files to run results. Common artifact types:
- PDF compliance reports
- CSV data exports
- JSON analysis results
- Log files
Files are stored alongside the run and downloadable from the run card in the Speckle UI.
GitHub Actions CI/CD
Auto-Generated Workflow
The deployment wizard creates .github/workflows/main.yml with:
- Build step (pip install / dotnet build)
- Docker container image creation
- Container push to Speckle registry
- Function version registration with Speckle Automate
Environment Variables (Injected by Wizard)
| Variable | Purpose | |----------|---------| | SPECKLE_FUNCTION_ID | Identifies the function in the Speckle registry | | SPECKLE_FUNCTION_TOKEN | Authentication token for publishing |
Deployment Flow
1. Create function via wizard (creates GitHub repo from template)
2. Modify function code locally or in Codespaces
3. Push changes to GitHub
4. Create a GitHub Release (REQUIRED for publishing)
5. GitHub Actions workflow triggers automatically:
a. Builds Docker image
b. Pushes image to Speckle registry
c. Registers function version
6. Function appears in Function Library
7. Users create Automations using the function
ALWAYS create a GitHub release to publish. The workflow triggers on release creation, NOT on push.
Function Creation Wizard
Steps
- Navigate to the Automations tab in a Speckle Enterprise project
- Click "View Functions" then "New Function"
- Authorize GitHub OAuth (first time only)
- Select template: Python or C#
- Configure metadata:
- Name (required) — descriptive identifier
- Description (required) — supports Markdown
- Avatar/Logo (optional)
- Source Application (optional) — target app compatibility
- Tags (optional) — categorical identifiers
- GitHub Organization — personal or organizational account
- Wizard automatically clones the template and injects CI/CD configuration
Requirements
- Speckle Enterprise plan on app.speckle.systems (Automate is NOT available on free plans)
- GitHub account with OAuth authorization for Speckle
- Repository access for the Speckle OAuth app
Local Testing
Python
# Install dependencies
pip install -e ".[dev]"
# Run tests
pytest tests/
# Local execution (with environment variables)
cp .env.example .env
# Edit .env with your Speckle credentials
uv run python main.py
C#
# Build
dotnet build
# Run tests
dotnet test TestAutomateFunction/
ALWAYS test locally before creating a GitHub release. Use the template's test infrastructure to verify function logic.
Key Differences: Python vs C#
| Aspect | Python | C# | |--------|--------|-----| | Input class | AutomateBase (Pydantic) | readonly struct with DataAnnotations | | Secret fields | SecretStr | [Secret] attribute | | Context type | AutomationContext (concrete) | IAutomationContext (interface) | | Entry point | execute_automate_function() | DI container + IAutomationRunner.Main() | | Object flattening | Manual flatten_base() function | Flatten() extension method | | Async pattern | Synchronous (Python GIL) | Full async/await | | Package | specklepy (includes automate) | Speckle.Automate.Sdk (separate NuGet) |
Reference Links
- [references/methods.md](references/methods.md) -- API signatures for AutomationContext, AutomateBase, FunctionInputs
- [references/examples.md](references/examples.md) -- Complete function examples from template to deployment
- [references/anti-patterns.md](references/anti-patterns.md) -- What NOT to do, with WHY explanations
Official Sources
- https://docs.speckle.systems/developers/automate/introduction.md
- https://docs.speckle.systems/developers/automate/quickstart.md
- https://docs.speckle.systems/developers/automate/create-function.md
- https://github.com/specklesystems/speckleautomatepython_example
- https://github.com/specklesystems/SpeckleAutomateDotnetExample
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: Impertio-Studio
- Source: Impertio-Studio/Speckle-Claude-Skill-Package
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.