Skip to main content

operaton-contracts

Pydantic task contracts for Robot Framework packages served as Operaton (Camunda 7) external tasks, for example by purjo.

Documentation: https://datakurre.github.io/operaton-contracts/

One model per external task topic is the source of truth for what the task accepts and returns:

  • At runtime each Robot task validates and normalizes its process variables with Validate Task Input.
  • At build time operaton-contracts generate renders one bpmn.io element template per topic from the same models, and operaton-contracts check verifies that the templates, [tool.purjo.topics], and the Robot suites agree.
uv add "operaton-contracts[robot]"   # runtime: pydantic + robotframework
uv add --group dev "operaton-contracts[templates]"   # uv-only: jsonschema for validate

When using devenv, provide jsonschema and development tools through devenv.nix instead of duplicating them in uv's dev group.

Contracts

# OperatonTasks.py
from datetime import date
from typing import Any

from pydantic import Field
from OperatonContracts import TaskContract, template_hints


class ProcessRecordsInput(TaskContract):
    record_ids: list[str] = Field(
        alias="recordIds",
        title="Record IDs",
        min_length=1,
        json_schema_extra=template_hints(value=["${recordId}"]),
    )
    effective_date: date = Field(
        alias="effectiveDate", title="Effective date", strict=False
    )
    dry_run: bool = Field(alias="dryRun", title="Dry run", default=False)


class ProcessRecordsOutput(TaskContract):
    result: dict[str, Any] = Field(alias="result", title="Result variable")

TaskContract is strict, forbids extra fields, and strips strings. Every field needs an alias (the process variable name) and a title (the template label). Use Literal[...] for choices; Enum, Optional, and nested models are not supported in template inputs; dict[str, str] renders as a Map. template_hints(value=..., type=..., group=..., entries=...) sets template-only defaults, property types, groups, and Map entries. On outputs, only value (the target process variable, or "" for none) and group apply.

Robot tasks

*** Settings ***
Library     OperatonContracts    OperatonTasks

*** Variables ***
${BPMN:TASK}    local
@{recordIds}    @{EMPTY}
${effectiveDate}    ${EMPTY}
${dryRun}    ${False}

*** Tasks ***
Process Records
    ${input}=    Validate Task Input    ProcessRecordsInput
    Log    ${input}[recordIds]
    VAR    ${result}=    ${{{}}}    scope=${BPMN:TASK}

Validate Task Input reads ${alias} for every field, validates, and returns the values JSON-compatible (dates as YYYY-MM-DD), keyed by alias. Declare typed suite defaults (${False}, ${0}, @{EMPTY}): strict contracts reject the string "0" or "false". The library imports the contracts module from sys.path, falling back to the running suite's directory.

Element templates

# pyproject.toml of the robot package
[tool.operaton-contracts]
specs = "OperatonTasks:TEMPLATES"               # module:attribute
icon = "logo.svg"                               # optional SVG icon
reserved-topics = ["legacy.topic"]              # optional
# schema-url = "…"                              # optional; pinned default
# Append to OperatonTasks.py, after the task contracts.
from OperatonContracts.templates import TaskTemplate, TemplateGroup

TEMPLATES = (
    TaskTemplate(
        topic="records.process",
        template_id="org.example.records-process",
        name="Process Records",
        description="Process selected records.",
        filename="records-process.json",
        inputs=ProcessRecordsInput,
        outputs=ProcessRecordsOutput,
        groups=(TemplateGroup("main", "Processing"),),
        input_group="main",
        output_group="main",
    ),
)

Co-locating the specs adds no package dependency when tasks already use OperatonContracts for TaskContract and Validate Task Input. Alternatively, put the declarations in a root-level OperatonTemplates.py and set specs = "OperatonTemplates:TEMPLATES"; list that file in .wrapignore so pur wrap leaves it out of the robot package.

operaton-contracts generate   # write .operaton/element-templates/*.json
operaton-contracts check      # offline: drift and package consistency
operaton-contracts validate   # against the pinned upstream schema (network)

The generated .operaton/ templates do not have to be committed. Robot packages may add .operaton/ to .gitignore and run the operaton-contracts generate command when the modeler needs the templates. If using check in CI, generate the files first because check verifies that the on-disk templates match the contracts. Packages that keep earlier template versions with keep_versions must commit .operaton/, because those versions exist only in the committed files.

check fails when on-disk templates differ from the generated ones, when specs and [tool.purjo.topics] differ, when a topic is reserved or lacks process-variables = false, or when the suite defining a topic's task lacks a typed default for an input, the Validate Task Input call, or a VAR … scope=${BPMN:TASK} for an output. Names are matched the way Robot matches them, suites are collected recursively (skipping hidden directories, tests/, lib/, examples/, and test_*.robot), and a task name defined in more than one suite is an error.

Agent skill

The package bundles an agent skill for building robot packages with these conventions. Install it into .agents/skills/ of your project, and refresh it after upgrades with --force:

uv run operaton-contracts install-skill

See the Agent skill page.

Development

uv run --group dev --group docs make test check docs   # with uv
devenv shell -- make test check docs                   # or with devenv
make build

make docs-serve previews the documentation site, which is published to GitHub Pages from main by .github/workflows/docs.yml. The uv dependency groups provide test and documentation tools for uv-only development. When using devenv, those tools come from devenv.nix; project dependencies still come from uv.

License

Apache License 2.0; see LICENSE.

Releases are published to PyPI by .github/workflows/release.yml with trusted publishing when a v* tag matching the project version is pushed.

Metadata

Release files for operaton-contracts 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for operaton-contracts 0.4.0
File Size Uploaded
operaton_contracts-0.4.0.tar.gz 71.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for operaton-contracts 0.4.0
File Interpreter ABI Platform
operaton_contracts-0.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 134.9 kB

Release files / operaton_contracts-0.4.0.tar.gz

Download URL operaton_contracts-0.4.0.tar.gz
Size 71.4 kB
Tags Source
SHA-256 checksum
How to use checksums
e3dc13d34e6faaace4d32aab5c4152f55bda1048c16f410dbe9fec506a7fab07
BLAKE2b-256 checksum
How to use checksums
c47dd523df7492d71864a3a301ff5972ffbc57a78e06eb131d3489294c19107f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 9, 2026.

Transparency log

Release files / operaton_contracts-0.4.0-py3-none-any.whl

Download URL operaton_contracts-0.4.0-py3-none-any.whl
Size 63.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7d59750609e91c5c1a65b644f3db1e8e32b28cf0ec18fe2e078004037e8c932c
BLAKE2b-256 checksum
How to use checksums
d368dd1806157f77645b060f2595473ebef4f395360b04e39e36219ac9e2b130
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 9, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.4.0 This release

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page