# Speckle Impl Automate Functions

> >

- **Type:** Skill
- **Install:** `agentstack add skill-impertio-studio-speckle-claude-skill-package-speckle-impl-automate-functions`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [Impertio-Studio](https://agentstack.voostack.com/s/impertio-studio)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [Impertio-Studio](https://github.com/Impertio-Studio)
- **Source:** https://github.com/Impertio-Studio/Speckle-Claude-Skill-Package/tree/master/skills/source/speckle-impl/speckle-impl-automate-functions

## Install

```sh
agentstack add skill-impertio-studio-speckle-claude-skill-package-speckle-impl-automate-functions
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## 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)

```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

```python
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 `getattr` with fallback to handle both `elements` and `@elements` naming 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#)

```csharp
// 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#)

```csharp
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)

```python
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)

```csharp
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

1. Navigate to the Automations tab in a Speckle Enterprise project
2. Click "View Functions" then "New Function"
3. Authorize GitHub OAuth (first time only)
4. Select template: Python or C#
5. 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
6. 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

```bash
# 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#

```bash
# 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/speckle_automate_python_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](https://github.com/Impertio-Studio)
- **Source:** [Impertio-Studio/Speckle-Claude-Skill-Package](https://github.com/Impertio-Studio/Speckle-Claude-Skill-Package)
- **License:** MIT

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

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-impertio-studio-speckle-claude-skill-package-speckle-impl-automate-functions
- Seller: https://agentstack.voostack.com/s/impertio-studio
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
