AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Speckle Syntax Automate

skill-impertio-studio-speckle-claude-skill-package-speckle-syntax-automate · by Impertio-Studio

>

No reviews yet
0 installs
16 views
0.0% view→install

Install

$ agentstack add skill-impertio-studio-speckle-claude-skill-package-speckle-syntax-automate

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No 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 No
  • 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.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-impertio-studio-speckle-claude-skill-package-speckle-syntax-automate)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
4mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

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 →
Are you the author of Speckle Syntax Automate? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

speckle-syntax-automate

Quick Reference

Architecture: Functions vs Automations

| Concept | What It Is | Created By | Scope | |---------|-----------|------------|-------| | Function | Reusable code template (GitHub repo) | Developer | Global -- listed in Function Library | | Automation | Configured instance of a Function | Project owner / admin | Bound to one project + model |

One Function can be deployed as many Automations across different projects, each with different input configurations.

Trigger Mechanism

The ONLY trigger is version creation -- when a new version (commit) is published to a model. There is NO manual trigger, NO scheduled trigger, and NO webhook-based trigger for Automate functions.

Execution 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 AutomationContext
6. Results (pass/fail, annotations, files) attach to the version
7. Results visible in web interface and 3D viewer

SDK Packages

| Language | Package | Target | |----------|---------|--------| | Python | specklepy (includes speckle_automate) | Python 3.10+ | | C# | Speckle.Automate.Sdk (NuGet) | .NET 8.0 |

Three Outcome States

| State | Cause | Meaning | |-------|-------|---------| | Success | mark_run_success() called | Model meets all criteria | | Failed | mark_run_failed() called | Model does NOT meet criteria (intentional) | | Exception | Unhandled exception thrown | Code error or platform error |

Critical Warnings

ALWAYS explicitly call mark_run_success() or mark_run_failed() before the function returns. If neither is called and no exception occurs, the run status is ambiguous.

NEVER pass execute_automate_function a function invocation -- pass the function reference WITHOUT parentheses and the FunctionInputs CLASS (not an instance).

NEVER use plain str for sensitive inputs (API keys, tokens). ALWAYS use SecretStr (Python) or [Secret] attribute (C#) to prevent exposure in logs and UI.

NEVER pass an empty list to attach_error_to_objects() -- it produces silent failures with no visible annotations. ALWAYS verify the list contains valid object IDs before calling.

NEVER use .Result or .Wait() in C# Automate functions -- the function is async. ALWAYS use await for all async operations.

NEVER use complex nested types in FunctionInputs -- the Speckle UI renders inputs as a flat form. Keep inputs as simple scalar types (str, int, float, bool).


Python: Function Structure

Entry Point Pattern

Every Python Automate function MUST follow this exact structure:

from speckle_automate import (
    AutomateBase,
    AutomationContext,
    execute_automate_function,
)
from pydantic import Field, SecretStr

class FunctionInputs(AutomateBase):
    """Define inputs with Pydantic Field() -- generates the UI form."""
    param_name: str = Field(title="Human Title", description="Explanation")

def automate_function(
    automate_context: AutomationContext,
    function_inputs: FunctionInputs,
) -> None:
    # 1. Receive the version data
    base = automate_context.receive_version()

    # 2. Process/validate the data
    # ... your logic here ...

    # 3. Report results
    automate_context.mark_run_success("All checks passed.")

# Entry point -- MUST be at module level
if __name__ == "__main__":
    execute_automate_function(automate_function, FunctionInputs)

FunctionInputs (Python -- Pydantic)

AutomateBase inherits from Pydantic's BaseModel. All Pydantic features work:

class FunctionInputs(AutomateBase):
    # Required string
    category_filter: str = Field(
        title="Category Filter",
        description="Only check objects in this category"
    )

    # Numeric with constraints and default
    max_count: int = Field(
        default=100,
        title="Maximum Object Count",
        ge=1, le=10000
    )

    # Secret value (encrypted, hidden in logs/UI)
    api_key: SecretStr = Field(title="External API Key")

    # Boolean toggle with default
    strict_mode: bool = Field(
        default=False,
        title="Strict Mode",
        description="Fail on warnings too"
    )

Rules:

  • ALWAYS add title and description to every Field -- without them the Speckle UI shows raw field names
  • ALWAYS provide default values for optional inputs -- inputs without defaults are treated as required
  • ALWAYS use SecretStr for sensitive values (API keys, tokens, credentials)
  • The JSON Schema is auto-generated from the class and rendered as a form in Speckle

AutomationContext API (Python)

| Method | Signature | Purpose | |--------|-----------|---------| | receive_version() | () -> Base | Retrieve the root Base object for the triggering version | | attach_error_to_objects() | (category: str, object_ids: List[str], message: str) -> None | Attach error annotations visible in the 3D viewer | | attach_info_to_objects() | (category: str, object_ids: List[str], message: str) -> None | Attach informational annotations (non-error) | | mark_run_failed() | (message: str) -> None | Mark run as intentionally failed | | mark_run_success() | (message: str) -> None | Mark run as successful | | store_file_result() | (file_path: str) -> None | Upload a file artifact to the run results | | set_context_view() | () -> None | Configure 3D viewer URL for the run result |

Object Traversal Pattern

Flatten the received object hierarchy to inspect individual objects:

from specklepy.objects import Base
from typing import Iterable

def flatten_base(base: Base) -> Iterable[Base]:
    """Recursively flatten a Base object hierarchy."""
    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 getattr with fallback to handle both elements and @elements naming
  • Yields descendants before the parent (depth-first, bottom-up)
  • Returns Iterable[Base] for lazy evaluation (memory-efficient for large models)
  • Is included in the official Python template as flatten.py

C#: Function Structure

Project Setup


  
    net8.0
  
  
    
    
  

Entry Point (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);

The runner.Main() call:

  1. Parses command-line arguments
  2. Deserializes function inputs as FunctionInputs
  3. Creates the IAutomationContext
  4. Invokes function.Run with both

FunctionInputs (C# -- DataAnnotations)

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

public readonly struct FunctionInputs
{
    [Required]
    public string SpeckleTypeToCount { get; init; }

    [DefaultValue(10)]
    [Range(1, 100)]
    [Required]
    public int SpeckleTypeTargetCount { get; init; }

    [Required]
    [Secret]
    public string ExternalServiceKey { get; init; }
}

Rules:

  • ALWAYS use readonly struct for immutability
  • ALWAYS use System.ComponentModel.DataAnnotations attributes for validation
  • ALWAYS use [Secret] attribute for sensitive values (NOT SecretStr)
  • ALWAYS use { get; init; } properties

AutomateFunction Class

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("All checks passed.");
    }
}

IAutomationContext API (C#)

| Method | Signature | Purpose | |--------|-----------|---------| | ReceiveVersion() | async Task | Retrieve the root Base object | | AttachErrorToObjects() | (string category, IList objectIds, string message) | Attach error annotations | | MarkRunFailed() | (string message) | Mark run as intentionally failed | | MarkRunSuccess() | (string message) | Mark run as successful | | StoreFileResult() | (string filePath) | Upload a file artifact | | SetContextView() | () | Configure viewer context |


Python vs C# Comparison

| Aspect | Python | C# | |--------|--------|-----| | Input base class | AutomateBase (Pydantic BaseModel) | readonly struct with DataAnnotations | | Secret fields | SecretStr | [Secret] attribute | | Context type | AutomationContext (concrete class) | IAutomationContext (interface) | | Entry point | execute_automate_function(fn, InputsClass) | DI container + IAutomationRunner.Main() | | Object flattening | Manual flatten_base() generator | Flatten() extension method | | Async model | Synchronous | Full async/await | | Package | specklepy (includes automate) | Speckle.Automate.Sdk (separate NuGet) | | Target runtime | Python 3.10+ | .NET 8.0 |


Deployment Workflow

1. Create function via Speckle wizard (Automations tab)
2. Template repo cloned to your GitHub account
3. Modify function code locally
4. Push changes to GitHub
5. Create a GitHub Release
6. GitHub Actions builds Docker image and registers function
7. Function appears in Function Library
8. Users create Automations from the function

ALWAYS create a GitHub Release to publish -- pushing code alone does NOT make the function appear in the Function Library.

NEVER modify or remove SPECKLE_FUNCTION_ID and SPECKLE_FUNCTION_TOKEN environment variables in the auto-generated .github/workflows/main.yml -- removing them breaks the deployment pipeline.


Reference Links

  • [references/methods.md](references/methods.md) -- Complete API signatures for AutomationContext (Python) and IAutomationContext (C#)
  • [references/examples.md](references/examples.md) -- Working code examples for both Python and C#
  • [references/anti-patterns.md](references/anti-patterns.md) -- Common mistakes with explanations

Official Sources

  • https://docs.speckle.systems/developers/automate/introduction
  • https://docs.speckle.systems/developers/automate/quickstart
  • https://docs.speckle.systems/developers/automate/create-function
  • 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.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.