Skip to main content

Massive Python SDK

Massive lets a Python author describe a typed, static workflow graph. Pydantic models are the source of the JSON Schemas carried in the emitted workflow specification; a step receives one typed input through StepContext and returns one typed output. Python is the primary Massive authoring surface; TypeScript uses the same portable artifact protocol.

Install and run

The PyPI distribution is named massive-workflows; it installs the massive Python module and command. The platform wheel contains the matching Go control plane, while the command passes the active Python interpreter to the frontend and step runner automatically:

uv init demo && cd demo
uv add massive-workflows
uv run massive run workflow.py --project demo/double --input '{"value": 21}'

--project names the run namespace; inside a GitHub or GitLab checkout it defaults to the origin's owner/repository.

Build a static, container-target workflow for Argo with the same compiled plan:

uv run massive build workflow.py \
  --target argo \
  --output .massive/argo \
  --namespace workflows \
  --service-account massive-runner \
  --artifact-store massive-artifacts

The bundle contains the canonical workflow and deployment specifications, the compiled plan, a bundle manifest, a runtime ConfigMap, and an offline-schema-validated Argo WorkflowTemplate in both YAML and canonical JSON. Verified source packages are also exposed under runtime-assets/ as deterministic, content-addressed tar files. Their hashes and media types are recorded in bundle-manifest.json, so the same pack can be inspected or uploaded without decoding the ConfigMap. Apply and submit it with the workflow input as one JSON parameter:

kubectl apply -f .massive/argo/runtime-configmap.json
kubectl apply -f .massive/argo/workflow-template.yaml

argo submit -n workflows --from workflowtemplate/double \
  -p 'input={"value":21}' --watch

Every container image selected with container(...) must contain Python 3.12+ and the same massive-workflows release, so its default massive command can run the isolated step adapter and Python runner. Source files are verified at build time and mounted from the generated ConfigMap; they do not need to be baked into the runner image. If a container recipe supplies command=, that command must launch the Massive CLI and accept the generated runtime arguments.

Local and Argo execution support steps, exhaustive decisions/selects, and finite maps. Python workflows can reuse a typed child graph with graph.call(child, id="name"). Connect the returned handle with ordinary edges:

child = GraphBuilder(name="normalize", input_type=Request, output_type=Result, defaults=defaults)
child.edge_from(child.start).to(child.add(normalize)).to(child.end)

parent = GraphBuilder(name="pipeline", input_type=Request, output_type=Result, defaults=defaults)
called = parent.call(child, id="normalize-input")
parent.edge_from(parent.start).to(called).to(parent.end)

A child graph may be called more than once, including in a decision branch. Each called graph must have one edge leaving its start and one edge entering its end, both connected to nodes inside the child. The Python frontend expands each call into scoped step IDs such as normalize-input--normalize before emitting Graph IR 0.3. Child steps keep their own execution contracts, attempts, and artifacts; there is no retry of the whole child as one unit. Calls must be acyclic and use source files from the parent workflow's source package. The emitted plan is flat, so inspection shows the scoped steps rather than a separate child-run hierarchy.

Argo requires immutable container environments and an explicit shared S3 datastore binding. Blob/Tree file bodies are stored remotely and hydrated into private invocation directories. Ordinary JSON values still use Argo parameters; embedded plans and source archives are limited to 700 KiB. Declared application secrets require deployment bindings; network="none" fails because tasks need remote storage. See the Argo datastore setup for ConfigMap and credential bindings.

from pydantic import BaseModel

from massive import GraphBuilder, StepContext, container, execution


class Request(BaseModel):
    value: int


class Result(BaseModel):
    value: int


graph = GraphBuilder(
    name="double",
    input_type=Request,
    output_type=Result,
    defaults=execution(
        environment=container(
            "registry.example/massive-python@sha256:"
            "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
        )
    ),
)


async def double(context: StepContext[Request]) -> Result:
    return Result(value=context.inputs.value * 2)


node = graph.add(double)
graph.edge_from(graph.start).to(node).to(graph.end)

GraphBuilder.add and GraphBuilder.map accept synchronous and asynchronous top-level functions directly. Functions remain callable and reusable across graphs; registration attaches execution settings without changing the function. The type of node is NodeHandle[Result] in either form, so the graph's edge types still follow the value a step produces rather than its coroutine.

Reusable functions and execution settings

Keep task functions in ordinary importable modules. A composition module registers them and chooses their execution requirements:

from dataclasses import replace
from tasks import inspect
inspection = graph.add(
    inspect,
    id="inspect",
    contract=replace(graph.defaults, cpu="2", memory="4Gi"),
)

contract= on add() or map() selects the complete contract for that use; omitting it uses the graph defaults. Use dataclasses.replace(graph.defaults, ...) to change selected fields while preserving secrets and network intent. Passing a fresh execution(...) intentionally selects a complete different contract, just as registering an explicit contract does in the TypeScript SDK. Reuse one immutable Container across resource or secret configurations. The compiler owns environment identity; there is no separate author-side container plan. Task imports should not require the deployment settings used to assemble a graph.

Retries and timeouts

Set graph-wide retries and a per-attempt timeout on the defaults, and override them for a single use:

from datetime import timedelta
from massive import NonRetryableError, execution, retry

graph = GraphBuilder(
    ...,
    defaults=execution(environment=image, retry=retry(3), timeout=timedelta(minutes=30)),
)
report = graph.add(build_report, retry=retry(5, delay=timedelta(seconds=30)), timeout=timedelta(hours=2))
charge = graph.add(charge_card, retry=retry(1))  # not idempotent: run once

retry= and timeout= on add() or map() replace only those fields of the selected contract (contract= or the graph defaults), keeping its environment, resources, and secrets. retry(attempts, delay=10s, backoff=2, max_delay=10m) waits min(delay * backoff ** (n - 2), max_delay) before attempt n; retry(1) disables retries.

Step exceptions, timeouts, and crashes such as out-of-memory kills are retried. Input and output schema failures, cancellation, and NonRetryableError (or a subclass) are not; raise NonRetryableError(...) from error when another attempt cannot succeed. ctx.invocation.attempt (1-based) and max_attempts describe the current attempt, while ctx.invocation.idempotency_key stays the same across attempts so a retry can recognize side effects an earlier attempt committed.

Exhaustive decisions

Use a Pydantic discriminated union when a step chooses one of a finite set of routes. Each alternative is a BaseModel with exactly one string Literal tag, and the union is annotated with Field(discriminator=...):

from typing import Annotated, Literal

from pydantic import BaseModel, Field


class Approved(BaseModel):
    kind: Literal["approved"] = "approved"
    value: int


class Rejected(BaseModel):
    kind: Literal["rejected"] = "rejected"
    reason: str


Review = Annotated[Approved | Rejected, Field(discriminator="kind")]

decision_graph: GraphBuilder[Request, Result] = GraphBuilder(
    name="review",
    input_type=Request,
    output_type=Result,
    defaults=graph.defaults,
)


def classify(context: StepContext[Request]) -> Review:
    if context.inputs.value >= 0:
        return Approved(value=context.inputs.value)
    return Rejected(reason="negative value")


async def approve(context: StepContext[Approved]) -> Result:
    return Result(value=context.inputs.value)


def reject(context: StepContext[Rejected]) -> Result:
    return Result(value=0)


classified = decision_graph.add(classify)
approved = decision_graph.add(approve)
rejected = decision_graph.add(reject)

route = decision_graph.decision(classified, on="kind", id="review-route")
approved_input = route.case(Approved)  # CaseHandle[Approved]
rejected_input = route.case(Rejected)  # CaseHandle[Rejected]

decision_graph.edge_from(decision_graph.start).to(classified)
decision_graph.edge_from(approved_input).to(approved)
decision_graph.edge_from(rejected_input).to(rejected)

selected = route.select(Result, approved=approved, rejected=rejected)
decision_graph.edge_from(selected).to(decision_graph.end)

case() narrows the routed value for Pyright and for the receiving step's Pydantic input validation. Every union case must be claimed exactly once, and select() keyword names must exactly equal the discriminator tags. Every selected branch must return the declared output type. A model with multiple tags such as Literal["approved", "manual-review"] is rejected; define one model per tag so case(Model) remains unambiguous.

Only the selected branch runs. Inactive branch steps are recorded as skipped, not invoked. select() then exposes the selected branch result as an ordinary NodeHandle[Result]; at runtime it aliases the already crystallized artifact without launching another step, copying its body, or uploading it again. Declaration order does not affect the emitted graph: authors may create the select before or after adding the case edges, and emit() validates the final topology. Decisions may be nested inside a case; if the outer case is inactive, the nested classifier, decision, branches, and select are all skipped as one control region. Sync and async classification or branch steps may be mixed freely.

Exhaustive decisions execute locally and on Argo with the same routing and artifact-selection semantics. Live conformance exercises nested inactive branches.

Finite maps

Map a concrete list produced by an earlier node with one ordinary function. The returned handle is the ordered list[Result], including the empty-list case; there is no separate gather or collect call.

class Batch(BaseModel):
    values: list[Request]


map_graph = GraphBuilder(
    name="increment-batch",
    input_type=Batch,
    output_type=list[Result],
    defaults=graph.defaults,
)


def unpack(context: StepContext[Batch]) -> list[Request]:
    return context.inputs.values


def increment_item(context: StepContext[Request]) -> Result:
    return Result(value=context.inputs.value + 1)


requests = map_graph.add(unpack)
results = map_graph.map(requests, increment_item, id="increment-items", concurrency=20)
map_graph.edge_from(map_graph.start).to(requests)
map_graph.edge_from(results).to(map_graph.end)

map() accepts only a direct, concrete list[T] source and requires the mapper input to be exactly T. Its mapper is registered by map(), rather than with add(). The result preserves source order and represents an empty input as an empty list[Result]; it may feed ordinary downstream nodes, including a later map as sequential composition. concurrency defaults to 20 and must be a strict integer from 1 through 4,294,967,295. It is an upper bound: a target may apply a lower executor capacity. The local process executor currently caps a map at 32 simultaneous child processes.

Emission produces one Graph IR 0.3 map node with its input, item-input, item-output, and collected-output schemas, mapper symbol and contract, and maxConcurrency. The emitted map contract is the execution boundary; no local in-memory map behavior is part of the authoring API.

Finite maps execute through both massive run and the Argo target. Argo lowers each map to a bounded nested DAG: an indexed envelope crystallizes the input, withParam invokes the mapper under the declared concurrency limit, and a collector restores source order. Duplicate values retain distinct indexes and an empty input publishes canonical [] without invoking mapper code.

Artifact handling

Authors do not read or write object-store keys in normal step code. The runner validates the Pydantic-derived input and output schemas, canonicalizes the JSON output, writes its content-addressed body, then commits the deterministic step output manifest. A retry with the identical value converges on the same objects; a different value for an already committed attempt fails rather than overwriting it. Downstream runtime code resolves and verifies the manifest, body digest, size, content type, producer slot, and schema before decoding the value.

The important runtime categories are:

  • ArtifactValidationError: invalid slot identity, non-canonical JSON, or a value/schema problem before publication.
  • ArtifactNotFoundError: the requested output manifest has not been committed.
  • ArtifactIntegrityError: a committed manifest references missing, tampered, or incompatible data.
  • ArtifactBodyConflictError and ArtifactManifestConflictError: an immutable object already exists with different bytes or metadata.

At the command boundary, descriptor errors exit 64, schema/artifact failures exit 65, a user-step exception exits 66, and a NonRetryableError exits 67 so the orchestrator does not retry it. Datastore outages are deliberately not rewritten as artifact conflicts so retry policy can recognize them as transient infrastructure failures.

The runtime derives the artifact namespace from a normalized project identity of the form sha256-<64 lowercase hex characters>; callers do not put a human repository name into an object-store path.

Releasing

From a clean checkout with Go 1.27 and uv installed, build the source archive and Linux, macOS, and Windows wheels for amd64 and arm64:

./scripts/build-python-release.sh dist/python-release

The release builder cross-compiles CGO-disabled Go control-plane binaries, assigns Python-ABI-independent platform tags, checks every wheel contains its native executable, and rebuilds a native wheel from the source distribution alone. scripts/test-python-distribution.sh <wheel> installs one wheel in a clean environment and exercises local, Argo build, and isolated Argo-step paths.

Publishing is done by the release GitHub workflow through PyPI trusted publishing. Set version in pyproject.toml, merge it, and push the matching v<version> tag; the workflow builds the artifacts once, verifies the platform wheels on Linux, macOS, and Windows, and publishes them with attestations. A manual run of the workflow publishes the same artifacts to TestPyPI.

Current scope

The graph is static: define all nodes and edges during authoring rather than creating graph structure from step results. Step inputs and outputs must be canonical JSON values representable by their Pydantic schemas. StepContext[Input] provides typed inputs, invocation metadata, and a workspace. Create service clients inside task code from deployment-bound configuration; live Python objects are not transported between workers. Python is the primary SDK; the artifact manifest protocol is shared with the other Massive runtimes.

canonical-json-v0 deliberately supports integers, but not floating-point numbers. Massive emits Pydantic's validation schema for workflow and step inputs, and its serialization schema for workflow and step outputs. This matches the runtime boundary: inputs are parsed into Python values with TypeAdapter.validate_python, while outputs are validated and then converted with dump_python(mode="json") before publication.

emit() still checks the serialization shape for both directions before it accepts an input validation schema. That prevents a bare float input from appearing portable merely because Pydantic can validate it: its serialized shape is JSON number, which v0 cannot carry. Decimal passes this check because its serialized shape is a string.

That distinction makes Decimal useful without inventing a second wire format. Pydantic accepts a Decimal input in its validation schema and serializes the output as a JSON string, so an output such as Decimal("10.5") is stored as {"value":"10.5"}. A following Decimal-typed step can validate that string again. The published validation schema deliberately retains Pydantic's number-or-string input shape; canonical-json-v0 framing is an additional, authoritative constraint that rejects a fractional JSON number before schema validation. Actual float/number output schemas are rejected at emit() because their serialized values cannot be represented by v0; use Decimal, a string, or a scaled integer instead.

Any and unconstrained mappings are also rejected at emit() in v0. They can admit floats that no runtime can encode consistently. Prefer a concrete model, list[int], dict[str, int], or another explicit JSON shape. Models configured with Pydantic extra="allow" are rejected for the same reason; prefer the default behavior or extra="forbid" for workflow payloads.

Use Massive's recursive JsonValue type when a result deliberately carries open-ended metadata while retaining the portable wire constraint:

from massive import JsonValue


class Result(BaseModel):
    metadata: dict[str, JsonValue]

This permits nested strings, safe integers, booleans, nulls, arrays, and objects, but keeps floating-point values out of the schema and runtime payload.

These author-time checks intentionally cover the Pydantic-generated schema forms Massive emits; they do not attempt to solve arbitrary JSON Schema satisfiability. Runtime canonicalization remains the authoritative final boundary before an artifact is published.

Frontend emitter

Run a zero-config Python workflow through the same compiler, orchestrator, and artifact protocol used by every Massive frontend:

massive run path/to/workflow.py --project demo/double --input '{"value": 21}'

When a module exports more than one graph, select it explicitly with workflow.py#graph_export. The CLI invokes the Python frontend as an isolated process, validates its canonical WorkflowSpec, compiles it with the Go compiler, and invokes each Python step in a separate runner process. Local execution does not call the in-memory GraphBuilder directly.

The Python frontend emits a portable WorkflowSpec from a Python workflow file:

massive-python-frontend emit path/to/workflow.py[#graph_export]

The command writes only canonical WorkflowSpec JSON to stdout. Diagnostics are written to stderr and return exit status 2. The massive run CLI uses this process seam internally; workflow authors normally invoke massive run instead.

Workflow packages and resources

The source package root is the entry file's parent directory, with package ID python-main. Without configuration, it includes root-level *.py files. For nested modules and non-Python assets, put a pyproject.toml beside the entrypoint:

[project]
name = "my-analysis"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["massive-workflows==0.1.0", "httpx>=0.28,<1"]

[tool.massive.source]
include = ["workflow.py", "analysis/**/*.py", "analysis/prompts/*.txt", "rules/*.yaml"]

Includes are directory-relative pathlib glob patterns and replace the default ["*.py"]. Include the entrypoint and all local modules/resources it needs. Unknown Massive configuration fields, selected symlinks, and patterns escaping the directory are rejected. Parent project configuration is not inherited; workflows in separate directories can carry different dependencies and assets. Multiple exports in one directory share that directory's package configuration.

pyproject.toml and uv.lock, when present, are always included in the source manifest. Changes to their bytes or any included resource change package identity. This records intended dependency inputs; it does not verify installed packages.

Use importlib.resources.files("analysis") or paths relative to __file__ to load packaged resources. The runner imports from a verified extracted archive, not from the original checkout. Avoid **/*: do not package .env, credentials, virtual environments, large datasets, or caches.

Third-party packages belong in [project].dependencies, not source includes. Create and commit a lock with uv lock. Then, from the workflow directory:

uv sync --locked
uv run --locked massive run workflow.py --project example/analysis --input '{}'

The launching Python environment runs both the frontend and each step. Massive does not install dependencies automatically. For Argo, build an immutable runner image with the same locked dependencies and Massive version. Local execution currently uses the active interpreter, not the container declared in the contract.

See the packaged map example for a nested module, a text resource, and ordered collection into a typed result.

Secrets

CI or the platform owns obtaining and rotating credentials. Never place their values in project metadata, lockfiles, source includes, or execution contracts. Local Python processes currently inherit the launching environment; secret preflight and selective task binding are not implemented locally. Argo binds logical secret references through massive build --secret-bindings bindings.json. Only steps declaring a reference receive its Kubernetes secretKeyRef. See application secret bindings for file format, reserved environment names, and failure behavior.

The contract is logical requirements in the workflow and concrete bindings in deployment configuration. See the binding design for the distinction between declarations, bindings, and enforcement.

Files and directory snapshots

Use Blob for an opaque file and Tree for a directory. They compose inside Pydantic models, lists, map results, and decision payloads:

from pathlib import Path
from pydantic import BaseModel
from massive import Blob, StepContext, Tree

class Checkout(BaseModel):
    files: Tree
    revision: str

class Report(BaseModel):
    file: Blob

def inspect(ctx: StepContext[Checkout]) -> Report:
    root = ctx.inputs.files.path()
    report = ctx.workspace / "report.txt"
    report.write_text(f"Inspected revision {ctx.inputs.revision}")
    return Report(file=Blob.from_path(report))

# Register the ordinary function directly.
inspection = graph.add(inspect)

Create a snapshot with Tree.from_path(directory) or Blob.from_path(file). Keep its source files available and unchanged until the step returns: Massive checks their captured hashes during publication. Bodies enter the configured filesystem or S3-compatible store before the task output manifest is committed. Only versioned hash/size references cross graph edges; file bytes never become Argo parameters. Repository checkout, revision selection, and credentials remain ordinary application logic; directory transport needs no Git-specific serializer.

path() lazily downloads and verifies a handle into invocation-local hydration scratch, separate from the author-writable ctx.workspace. The runner removes scratch after execution. Each consumer receives an isolated writable copy; edits cannot change upstream artifacts or another map item. Returning the same handle forwards the original snapshot. Return a new Tree.from_path(root) or Blob.from_path(path) to publish edits explicitly.

Trees preserve regular files, executable bits, and empty directories, including hidden entries such as .git if present. They reject symlinks and special files. Timestamps, ownership, and other permission bits do not affect identity. Snapshot a deliberately selected directory; there is no implicit ignore file. The current implementation targets POSIX filesystems and buffers one file at a time in memory; streaming, download quotas, and garbage collection are future work.

Outside a runner, pass an explicit ArtifactFiles(store, scratch) as Pydantic's context to model_dump_json when publishing and model_validate_json when binding references. Unbound handles can be inspected and serialized, but cannot hydrate. Use a dedicated datastore root or S3 prefix for each security boundary.

The artifact example runs a directory snapshot through parallel processes and collects file reports. The wire contract defines identity and retention requirements. Python currently provides hydration; TypeScript can forward the JSON references but has no corresponding file-handle API.

Inspect a past local run without executing author code:

massive inspect <run-id> --project <project> --store <store> --json

The current run journal includes step attempts, decisions, ordered map items, and result references. Project identity is required so matching run IDs remain isolated. Obsolete journal transports are rejected; no compatibility reader is retained. The same CLI supports TypeScript through separately installed frontend and runner adapters.

Temporary output files

Use ctx.workspace for files created by a task:

def render(ctx: StepContext[str]) -> Blob:
    output = ctx.workspace / "report.txt"
    output.write_text(ctx.inputs)
    return Blob.from_path(output)

Each invocation receives a fresh writable directory separate from its source and hydrated input files. It stays alive through output validation and Blob/Tree publication, and is removed on success or failure. Paths inside it are temporary; return typed artifact handles when another task needs the contents. Workspace cleanup does not terminate detached child processes or impose a disk quota. Abrupt process termination can leave local scratch behind. Local task adapters own ordinary descendants through a process group (Linux/macOS) or job (Windows). Tasks must await child work before returning. Adapter completion or context cancellation terminates descendants still in that group; this is not a sandbox against code deliberately detaching from a Unix process group. Captured task output is limited to 1 MiB with an explicit truncation marker, and inherited output pipes have a bounded drain period. CLI signal handling and durable cancellation journals remain separate work; forcibly killing the CLI is not a graceful cancellation API.

Metadata

Release files for massive-workflows 0.1.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 massive-workflows 0.1.0
File Size Uploaded
massive_workflows-0.1.0.tar.gz 419.9 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for massive-workflows 0.1.0
File
massive_workflows-0.1.0-py3-none-win_arm64.whl Python 3 none Windows ARM64 Details
massive_workflows-0.1.0-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details
massive_workflows-0.1.0-py3-none-manylinux_2_17_x86_64.whl Python 3 none Linux glibc 2.17+ x86-64 Details
massive_workflows-0.1.0-py3-none-manylinux_2_17_aarch64.whl Python 3 none Linux glibc 2.17+ ARM64 Details
massive_workflows-0.1.0-py3-none-macosx_13_0_x86_64.whl Python 3 none macOS 13.0+ x86-64 Details
massive_workflows-0.1.0-py3-none-macosx_13_0_arm64.whl Python 3 none macOS 13.0+ ARM64 Details

Total release size: 36.3 MB

Release files / massive_workflows-0.1.0.tar.gz

Download URL massive_workflows-0.1.0.tar.gz
Size 419.9 kB
Tags Source
SHA-256 checksum
How to use checksums
bd2146e1ec41c1a47bbedfd71f29dcdff9abc4a52bb5038d6bb4195c8b680d12
BLAKE2b-256 checksum
How to use checksums
9abd7792869c2187650bc6199e7fc318f07e4bcf138b3a9f868b7b084e26fed3
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 7, 2026.

Transparency log

Release files / massive_workflows-0.1.0-py3-none-win_arm64.whl

Download URL massive_workflows-0.1.0-py3-none-win_arm64.whl
Size 5.6 MB
Tags Python 3 Windows ARM64
SHA-256 checksum
How to use checksums
e3c7228e058da3e7745148c6fbb2a6ce18f67567c0b0d5c31d80b754aaf166e6
BLAKE2b-256 checksum
How to use checksums
910f4460cc4f9228177837af8d6d390c264b55cb9ccb8e2321d4ab3db2031f4a
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 7, 2026.

Transparency log

Release files / massive_workflows-0.1.0-py3-none-win_amd64.whl

Download URL massive_workflows-0.1.0-py3-none-win_amd64.whl
Size 6.4 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
1ee934bc3d9acf805286ce2accafd0db8a52d30c6f59209c48b717ac178b8883
BLAKE2b-256 checksum
How to use checksums
0c0ac9271c773319066334dcc31f77fab5754baabd8a697427ef94e59244b8b3
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 7, 2026.

Transparency log

Release files / massive_workflows-0.1.0-py3-none-manylinux_2_17_x86_64.whl

Download URL massive_workflows-0.1.0-py3-none-manylinux_2_17_x86_64.whl
Size 6.2 MB
Tags Linux glibc 2.17+ x86-64 Python 3
SHA-256 checksum
How to use checksums
7246ec85d31da2ee6c03dd89500a0db479f266becaeff3576e6def6413832af1
BLAKE2b-256 checksum
How to use checksums
96f7471648c969cc3c6cca80cf546719e88d5a3347f1338a847bdf1af57dfb0a
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 7, 2026.

Transparency log

Release files / massive_workflows-0.1.0-py3-none-manylinux_2_17_aarch64.whl

Download URL massive_workflows-0.1.0-py3-none-manylinux_2_17_aarch64.whl
Size 5.6 MB
Tags Linux glibc 2.17+ ARM64 Python 3
SHA-256 checksum
How to use checksums
dc752c743eaa20ed48f8745207e880cd8b00c18dc02d5534ff9b969b02faa069
BLAKE2b-256 checksum
How to use checksums
3d63e813fd9aea24a4da007463a207d0ee81d41c8cb808f139c12dafdefbbc83
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 7, 2026.

Transparency log

Release files / massive_workflows-0.1.0-py3-none-macosx_13_0_x86_64.whl

Download URL massive_workflows-0.1.0-py3-none-macosx_13_0_x86_64.whl
Size 6.3 MB
Tags Python 3 macOS 13.0+ x86-64
SHA-256 checksum
How to use checksums
853d003b6cbef615296426ed328b5a356f42a0b926a9547eed493a46f1cef1b5
BLAKE2b-256 checksum
How to use checksums
e0ca02bba4d5d46d3350250a6aca064cc1c362703a964de42da555c8c1300151
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 7, 2026.

Transparency log

Release files / massive_workflows-0.1.0-py3-none-macosx_13_0_arm64.whl

Download URL massive_workflows-0.1.0-py3-none-macosx_13_0_arm64.whl
Size 5.8 MB
Tags Python 3 macOS 13.0+ ARM64
SHA-256 checksum
How to use checksums
b328cdeb65411215c0b68a98ab31cc43194c1baf294fdc9b37195ee948187ebe
BLAKE2b-256 checksum
How to use checksums
563f28f12e040982695d3e09c3e3f9fa61df972012e85e47c7ae7d8628ef87b9
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 7, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

7 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