Registering Algorithms

How to publish algorithms to the Elements Platform

Registering Algorithms

Once you've created your algorithm manifest and container image, the final step is registering it with the Elements Platform. This makes your algorithm available for use in computations and analyses.

Overview

Registration involves two steps:

  1. Create an Algorithm - Register the top-level Algorithm object
  2. Create an Algorithm Version - Register a specific version with its manifest

Prerequisites

Before registering, ensure you have:

  • ✅ A complete algorithm manifest
  • ✅ A container image pushed to a public registry
  • ✅ The Elements SDK installed and authenticated
  • ✅ Verified all referenced Data Types exist

Step 1: Create Algorithm

First, create the top-level Algorithm object:

Using the SDK

from elements.sdk.elements_sdk import ElementsSDK

sdk = ElementsSDK()

# Create algorithm
algorithm = await sdk.algorithm.create(
    name="device-visits",
    display_name="Device Visits",
    author="Your Organization"
)

print(f"Algorithm created with ID: {algorithm.id}")

Using the API

from elements_api.async_client import ElementsAsyncClient

client = ElementsAsyncClient(host, port, secure=True, token=api_token)

# Create request
create_request = client.models.algorithm_pb2.AlgorithmCreateRequest(
    name="device-visits",
    display_name="Device Visits",
    author="Your Organization"
)

# Create algorithm
response = await client.api.algorithm.create(create_request)
algorithm_id = response.algorithm.id

print(f"Algorithm created with ID: {algorithm_id}")

Parameters

  • name (required) - Unique identifier for the algorithm (kebab-case)
  • display_name (required) - Human-readable name shown in UI
  • author (required) - Organization or person who created it

Step 2: Register Algorithm Version

Next, register a specific version with its manifest:

Using the SDK

import json

# Load manifest from file
with open('manifest.json') as f:
    manifest = json.load(f)

# Create algorithm version
version = await sdk.algorithm_version.create(
    algorithm_id=algorithm.id,
    manifest=manifest
)

print(f"Algorithm version created with ID: {version.id}")
print(f"Version: {version.manifest['metadata']['version']}")

Using the API

from google.protobuf import struct_pb2
import json

# Load and convert manifest
with open('manifest.json') as f:
    manifest_dict = json.load(f)

manifest_struct = struct_pb2.Struct()
manifest_struct.update(manifest_dict)

# Create request
create_version_request = client.models.algorithm_version_pb2.AlgorithmVersionCreateRequest(
    algorithm_id=algorithm_id,
    manifest_struct=manifest_struct
)

# Register version
response = await client.api.algorithm_version.create(
    create_version_request,
    timeout=30
)

version_id = response.algorithm_version.id
print(f"Algorithm version created with ID: {version_id}")

Validation

When you register an Algorithm Version, the platform validates:

Manifest Schema

The manifest must conform to the schema for the specified manifest_version:

✅ Valid:   {"manifest_version": "0.1.0", ...}
❌ Invalid: {"manifest_version": "999.0.0", ...}

Data Types

All referenced Data Types must exist:

✅ Valid:   "data_type_name": "pings"  (exists)
❌ Invalid: "data_type_name": "my_custom_type"  (doesn't exist)

If validation fails, create the Data Type first:

# Create missing Data Type
await sdk.data_type.create(
    name="my_custom_type",
    description="Description of custom type",
    schema={...}
)

Resource Requests

Resource values must be valid:

✅ Valid:   "gpu": 0, "memory_gb": 5, "cpu_millicore": 200
❌ Invalid: "gpu": "none", "memory_gb": -1, "cpu_millicore": "low"

Container Image

The image must be specified correctly:

✅ Valid:   "image": "myorg/algorithm:1.0.0"
✅ Valid:   "image": "myorg/algorithm@sha256:abc..."
❌ Invalid: "image": "localhost/algorithm:1.0.0"  (not publicly accessible)

Parameters

Parameters must have valid types and defaults:

✅ Valid:   {"name": "threshold", "type": "float", "default": 0.5}
❌ Invalid: {"name": "threshold", "type": "float", "default": "medium"}

Handling Validation Errors

If validation fails, you'll receive a detailed error message:

try:
    version = await sdk.algorithm_version.create(
        algorithm_id=algorithm.id,
        manifest=manifest
    )
except Exception as e:
    print(f"Validation failed: {e}")
    # Example error: "Data Type 'custom_pings' not found"
    # Fix: Create the Data Type or use existing one

Common errors and fixes:

ErrorCauseFix
Data Type 'X' not foundReferenced Data Type doesn't existCreate Data Type first or use existing one
'gpu' must be integerInvalid resource typeChange to integer value
Parameter 'X' missing 'default'No default valueAdd default value to parameter
Image 'X' inaccessibleContainer image not publicly availablePush image to public registry

Versioning Strategy

Creating New Versions

Algorithm Versions are immutable once created. To update an algorithm:

Scenario 1: Bug fix or performance improvement

# Increment version in manifest
manifest['metadata']['version'] = '1.0.1'  # Was 1.0.0

# Update container image
manifest['container_parameters']['image'] = 'myorg/algo:1.0.1'

# Register new version
version = await sdk.algorithm_version.create(
    algorithm_id=algorithm.id,  # Same algorithm
    manifest=manifest
)

Scenario 2: New feature (backwards compatible)

# Increment minor version
manifest['metadata']['version'] = '1.1.0'  # Was 1.0.1

# Add new parameter (with default for backwards compatibility)
manifest['parameters'].append({
    'name': 'new_feature_enabled',
    'type': 'boolean',
    'default': False  # Default maintains old behavior
})

# Register new version
version = await sdk.algorithm_version.create(
    algorithm_id=algorithm.id,
    manifest=manifest
)

Scenario 3: Breaking change

# Increment major version
manifest['metadata']['version'] = '2.0.0'  # Was 1.1.0

# Change output data type
manifest['outputs']['output_data_types'] = ['new_visits_format']

# Register new version
version = await sdk.algorithm_version.create(
    algorithm_id=algorithm.id,
    manifest=manifest
)

Deprecating Versions

Mark old versions as deprecated when they should no longer be used:

# Deprecate old version
await sdk.algorithm_version.deprecate(
    algorithm_version_id=old_version_id
)

print(f"Version {old_version_id} marked as deprecated")

Deprecated versions:

  • Still work in existing computations
  • Show a warning in the UI
  • Should not be used for new computations

Deactivating Versions

Deactivate versions that should no longer be used at all:

# Deactivate version
await sdk.algorithm_version.deactivate(
    algorithm_version_id=version_id
)

print(f"Version {version_id} deactivated")

Deactivated versions:

  • Cannot be used in new computations
  • Existing computations continue to work
  • Can be reactivated if needed

Querying Algorithms

List All Algorithms

# List all algorithms
algorithms = await sdk.algorithm.list()

for algo in algorithms:
    print(f"{algo.name} - {algo.display_name}")

Get Algorithm Details

# Get specific algorithm
algorithm = await sdk.algorithm.get(
    algorithm_id=algorithm_id
)

print(f"Name: {algorithm.name}")
print(f"Author: {algorithm.author}")
print(f"Created: {algorithm.created_at}")

List Algorithm Versions

# List all versions of an algorithm
versions = await sdk.algorithm_version.list(
    algorithm_id=algorithm.id
)

for version in versions:
    manifest = version.manifest
    version_num = manifest['metadata']['version']
    print(f"Version {version_num}: {version.id}")

Get Specific Version

# Get version details
version = await sdk.algorithm_version.get(
    algorithm_version_id=version_id
)

manifest = version.manifest
print(f"Version: {manifest['metadata']['version']}")
print(f"Image: {manifest['container_parameters']['image']}")
print(f"Parameters: {len(manifest['parameters'])}")

Complete Registration Example

Here's a complete end-to-end example:

from elements.sdk.elements_sdk import ElementsSDK
import json

async def register_algorithm():
    sdk = ElementsSDK()

    # Load manifest
    with open('device_visits_manifest.json') as f:
        manifest = json.load(f)

    # Check if algorithm already exists
    try:
        algorithms = await sdk.algorithm.list()
        existing = next(
            (a for a in algorithms if a.name == "device-visits"),
            None
        )

        if existing:
            print(f"Algorithm exists: {existing.id}")
            algorithm_id = existing.id
        else:
            # Create new algorithm
            algorithm = await sdk.algorithm.create(
                name="device-visits",
                display_name="Device Visits",
                author="Your Organization"
            )
            print(f"Created algorithm: {algorithm.id}")
            algorithm_id = algorithm.id

    except Exception as e:
        print(f"Error checking existing algorithms: {e}")
        return

    # Register version
    try:
        version = await sdk.algorithm_version.create(
            algorithm_id=algorithm_id,
            manifest=manifest
        )

        print(f"✅ Successfully registered algorithm version")
        print(f"   Version ID: {version.id}")
        print(f"   Version: {manifest['metadata']['version']}")
        print(f"   Image: {manifest['container_parameters']['image']}")

        return version.id

    except Exception as e:
        print(f"❌ Failed to register version: {e}")
        return None

# Run registration
version_id = await register_algorithm()

Testing After Registration

After registering, test your algorithm:

  1. Create a test configuration (see Running Algorithms)
  2. Run on a small AOI and short time range
  3. Verify output format and correctness
  4. Check resource usage vs. manifest
# Quick test
test_config = await sdk.algorithm_config.create(
    algorithm_version_id=version_id,
    name="test-config",
    params={
        'data_sources': [...],
        'parameters': {...}
    }
)

# Create small test computation
# (See Running Algorithms guide for complete steps)

Best Practices

  1. Test before registering - Validate manifest and test container locally
  2. Use specific image tags - Avoid latest, use 1.0.0 or digests
  3. Version consistently - Follow semantic versioning
  4. Document versions - Keep release notes for each version
  5. Deprecate gracefully - Give users time to migrate before deactivating

Next Steps