Skip to main content

cytario-app-sdk

PyPI version Python License: MIT CI Release

A CLI and Python library for Cytario analysis applications — register apps in an OCI Distribution v1.1 registry and run them inside Cytario compute containers.

The SDK has two responsibilities:

  1. Registration (register command) — attaches an app-definition (parameter schema, input/output data roles) to a container image as an OCI Image Format annotation (org.cytario.appdef.v1) on the image manifest, then PUTs the manifest back under its original tag. Because the annotation is part of the manifest content, the manifest's immutable content digest binds the definition to the exact image — pinning the image by digest also pins the definition.

  2. In-container runtime (run command + broker / runtime libraries) — when Cytario's compute plugin submits an analysis job, the running container receives a broker endpoint, a job-scoped token, and resolved S3 URIs for its inputs and outputs. The SDK obtains short-lived storage credentials from the broker, downloads the inputs, spawns the algorithm, and uploads the results.

Application access (who may see/run an app, who may edit its saved configs) is not part of the app-definition. Entitlement is governed by the catalog connection's access scope on the Cytario side, not by anything carried in the registry image.

Install

pip install cytario-app-sdk            # registration only
pip install "cytario-app-sdk[runtime]" # + boto3 for in-container use

Or with uv:

uv tool install cytario-app-sdk

Quick start — registering an app

cytario-app-sdk --registry https://harbor.example.com \
  --user 'robot$cytario-catalog' \
  --secret <robot-token> \
  register examples/cellseg.yaml

Connection settings (registry endpoint, user, secret) can be supplied on the command line or via a YAML config file consumed by typer-config:

# cytario-app-sdk.yaml
registry: https://harbor.example.com
user: robot$cytario-catalog
secret: <robot-token>
cytario-app-sdk --config cytario-app-sdk.yaml register examples/cellseg.yaml

Validate an app-definition without pushing anything:

cytario-app-sdk --config cytario-app-sdk.yaml register --dry-run examples/cellseg.yaml

App-definition YAML

# examples/cellseg.yaml
schemaVersion: 1
applicationId: cellseg
name: Cell Segmentation
description: Runs Cellpose on a 16-bit OME-TIFF.
image:
  repository: cytario/cellseg
  tag: "1.0.0"
parameterSchema:
  - name: diameter
    label: Diameter
    type: number
    required: false
    default: 30
    description: Cellpose diameter estimate in pixels.
dataRoles:
  - name: image
    kind: input
  - name: segmentation
    kind: output

register fetches the container image manifest (by tag or digest), builds the app-definition document, attaches it as the org.cytario.appdef.v1 annotation on the manifest, and PUTs the manifest back under the original tag. The new manifest digest (returned by the registry) pins both the image and the definition. The Cytario runtime reads the annotation back via GET /v2/<name>/manifests/<ref>; no Harbor-specific calls are made.

Running inside a Cytario compute container

When the Cytario compute plugin submits an analysis job, the running container receives these environment variables:

Variable Description
CYTARIO_BROKER_ENDPOINT Full URL of the credential-broker endpoint (e.g. https://app.cytario.com/api/plugin/broker).
CYTARIO_BROKER_TOKEN Job-scoped offline-capable grant token the broker validates against the running-jobs ledger.
CYTARIO_INPUT_URIS JSON array of s3://bucket/key URIs for the job's input files.
CYTARIO_OUTPUT_URI s3://bucket/key URI (prefix) for the job's output.
AWS_BATCH_JOB_ID The provider job identifier (injected by AWS Batch).

The container calls the broker with its token + job id to obtain short-lived STS credentials (≤ 1 hour, scoped to the submitting user's organization and the job's validated output prefix), then uses those credentials to read inputs and write outputs. The SDK provides two ways to handle this:

Wrapper mode (broker-unaware algorithms)

The SDK is the container entrypoint — it downloads inputs, spawns the algorithm as a subprocess, and uploads outputs on success. The algorithm only reads/writes local files; it never touches S3 or the broker.

# Dockerfile
FROM python:3.12-slim
RUN pip install "cytario-app-sdk[runtime]"
COPY process.py /app/process.py
ENTRYPOINT ["cytario-app-sdk", "run", "--"]
CMD ["python", "/app/process.py"]
# Equivalent to the Dockerfile above, invoked manually:
cytario-app-sdk run --input-dir /data/in --output-dir /data/out -- python /app/process.py

Options:

Option Default Description
--input-dir /data/in Local directory to download inputs into.
--output-dir /data/out Local directory to upload outputs from.
--upload-on-failure off Upload outputs even when the algorithm exits non-zero.
--pass-through-env off Keep CYTARIO_BROKER_* env vars in the subprocess (for hybrid algorithms).
--refresh-margin 300 Broker credential refresh margin in seconds.

The wrapper strips CYTARIO_BROKER_TOKEN and CYTARIO_BROKER_ENDPOINT from the subprocess environment by default so a broker-unaware algorithm cannot accidentally leak them. Pass --pass-through-env to keep them (for hybrid algorithms that import the SDK and call the broker themselves).

Library mode (broker-aware algorithms)

The algorithm's Python code imports the SDK and calls the broker directly. This is the path for algorithms that stream from S3 (cellpose, OME-TIFF readers, zarr stores) and want full control over their boto3 usage.

from cytario_app_sdk.broker import BrokerClient

broker = BrokerClient.from_env()
creds = broker.credentials()

import boto3

s3 = boto3.client(
    "s3",
    aws_access_key_id=creds.access_key_id,
    aws_secret_access_key=creds.secret_access_key,
    aws_session_token=creds.session_token,
)
# stream from s3://...

Or use the convenience that returns a boto3.Session whose credentials refresh from the broker transparently on every API call:

from cytario_app_sdk.broker import BrokerClient, broker_boto3_session

broker = BrokerClient.from_env()
session = broker_boto3_session(broker)
s3 = session.client("s3")
s3.download_file("my-bucket", "key", "/local/path")

The broker_boto3_session factory wires a RefreshableCredentials whose refresh callback calls broker.refresh(), so boto3's own refresh-before-call logic is the driver — the algorithm never needs to manage credential lifetimes manually.

For manual S3 sync (download/upload recursive), use the runtime module:

from cytario_app_sdk.broker import BrokerClient, broker_boto3_session
from cytario_app_sdk.runtime import download_inputs, upload_outputs
from pathlib import Path

broker = BrokerClient.from_env()
session = broker_boto3_session(broker)
s3 = session.client("s3")

# Download inputs declared in CYTARIO_INPUT_URIS
download_inputs(s3, ["s3://bucket/inputs/"], Path("/data/in"))

# Run your algorithm here...

# Upload outputs to CYTARIO_OUTPUT_URI
upload_outputs(s3, Path("/data/out"), "s3://bucket/outputs/")

Credential lifecycle

The broker mints STS credentials with a ≤ 1 hour lifetime. The grant token (CYTARIO_BROKER_TOKEN) has a longer lifetime — the realm's maximum offline-session validity (typically hours). The SDK refreshes credentials on demand: whenever the cached credentials expire within the refresh margin (5 minutes by default), a fresh mint is requested from the broker. A job running longer than the realm max cannot refresh anymore; this is the spec's accepted, risk-assessed limitation.

If the job is cancelled or reaches a terminal state, the Cytario reconciler removes the job's ledger row, and the broker rejects subsequent calls with a GrantRevoked error — storage access ceases within one credential lifetime of revocation.

Development

This project uses uv and targets Python 3.10+.

uv sync                          # install deps into .venv
uv run cytario-app-sdk --help    # run the CLI
uv run ruff check --fix && uv run ruff format
uv run pytest

See CONTRIBUTING.md for the full contributor guide and the Releases page for release history. Versions are cut automatically with python-semantic-release — in no-commit mode, so no release commits land on main.

License

Released under the MIT License. By contributing, you agree that your contributions will be licensed under the MIT License.

Metadata

Release files for cytario-app-sdk 4.0.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 cytario-app-sdk 4.0.0
File Size Uploaded
cytario_app_sdk-4.0.0.tar.gz 136.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for cytario-app-sdk 4.0.0
File Interpreter ABI Platform
cytario_app_sdk-4.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 176.8 kB

Release files / cytario_app_sdk-4.0.0.tar.gz

Download URL cytario_app_sdk-4.0.0.tar.gz
Size 136.3 kB
Tags Source
SHA-256 checksum
How to use checksums
a4468b589328897f3686fdc7c2f43c3da03ed3a0200f1a702a3b4f131734afb7
BLAKE2b-256 checksum
How to use checksums
6940cb8f2d6232a4dbd9779a6ca94a345a5ecef4514fcd80eb5787081b73b8f3
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 Sep 23, 2026.

Transparency log

Release files / cytario_app_sdk-4.0.0-py3-none-any.whl

Download URL cytario_app_sdk-4.0.0-py3-none-any.whl
Size 40.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
cb1f9f6db7ba9d8f98ebccc2e4f5d99f07f4f36555934b72d40c2da8c7592d73
BLAKE2b-256 checksum
How to use checksums
bb6c677a1de8816a3d109e87a46ae6685acead89c2611f478b7ebbec3b692e7d
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 Sep 23, 2026.

Transparency log

Release history Release notifications | RSS feed

4.2.0

2 release files

4.1.2

2 release files

4.1.1

2 release files

4.1.0

2 release files

4.0.1

2 release files

This release

4.0.0 This release

2 release files

3.3.1

2 release files

3.3.0

2 release files

3.2.0

2 release files

3.1.0

2 release files

3.0.0

2 release files

2.0.0

2 release files

1.1.0

2 release files

1.0.3

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.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