Portable, cloud-agnostic execution runtime for OmniBioAI tools
omnibioai-tool-runtime is a minimal, deterministic execution runtime used by
OmniBioAI’s Tool Execution Service (TES) to run individual tools across multiple execution backends, including:
- Local Docker execution
- AWS Batch
- Azure Batch
- GCP Batch (
gs://results upload) - Kubernetes Jobs
- Slurm / HPC via TES adapters
The runtime provides a strict execution contract so that:
- TES adapters stay thin and backend-specific
- Tool containers remain portable and backend-agnostic
- Results are uploaded consistently (S3 / Azure Blob / future backends)
This mirrors the design philosophy used throughout OmniBioAI: separate orchestration from execution, and execution from logic.
-
A containerized tool launcher
-
Responsible for:
- Reading tool inputs from environment variables
- Executing tool logic
- Writing
results.json - Uploading results to cloud storage
-
Cloud-agnostic (AWS / Azure supported today)
- A workflow engine
- A scheduler
- An LLM executor
- A UI layer
Those responsibilities live elsewhere in OmniBioAI.
All tools executed via omnibioai-tool-runtime must follow this contract.
| Variable | Description |
|---|---|
TOOL_ID |
Tool identifier (echo_test, blastn, etc.) |
RUN_ID |
Unique run ID (generated by adapter) |
INPUTS_JSON |
JSON-encoded tool inputs |
RESOURCES_JSON |
JSON-encoded resource request |
S3_RESULT_URI |
(AWS Batch) S3 URI to upload results |
RESULT_URI |
(Azure Batch) azureblob:// URI to upload results |
Only one of S3_RESULT_URI or RESULT_URI is expected per run.
omnibioai-tool-runtime/
├── Dockerfile
├── README.md
├── pyproject.toml
├── omni_tool_runtime/
│ ├── __init__.py
│ ├── contract.py # ToolContract + read_contract_from_env() —
│ │ # the code implementing "Execution Contract" below
│ ├── run.py # Generic entrypoint: resolves TOOL_ID ->
│ │ # tools.{tool_id}.run and calls its main()
│ ├── result_uri.py # URI parsing & dispatch
│ ├── upload_result.py # Unified upload logic
│ └── uploaders/
│ ├── s3_uploader.py
│ └── azureblob_uploader.py
├── tools/
│ ├── echo_test/ # Minimal reference implementation — see below
│ │ ├── __init__.py
│ │ └── run.py
│ ├── generic_sif_runner/ # The real, production tool — embedded in every
│ │ └── run.py # ECR/ACR/GCR image (see omnibioai-tes's README)
│ └── workflow_runner/
│ └── run.py
└── tests/
cd ~/Desktop/machine/omnibioai-tool-runtime
pytest tests/ -v --cov=.
# Coverage figures from earlier dated runs are historical snapshots; run the
# command above to measure the current checkout.
# Covers: upload_result, S3 uploader, Azure uploader,
# echo_test/generic_sif_runner/workflow_runner tools, run lifecycleThis is a minimal reference implementation — small enough to read
end-to-end as a template for a new tool. The real, production tool
embedded in every ECR/ACR/GCR image is tools/generic_sif_runner/ (see
omnibioai-tes's README); a third,
tools/workflow_runner/, also ships here.
- Reads
INPUTS_JSON - Echoes a value
- Writes
results.json - Uploads results to configured storage backend
# tools/echo_test/run.py
import json
import os
from omni_tool_runtime.upload_result import upload_result
def main():
tool_id = os.environ["TOOL_ID"]
run_id = os.environ["RUN_ID"]
inputs = json.loads(os.environ.get("INPUTS_JSON", "{}"))
text = inputs.get("text", "")
result = {
"ok": True,
"tool_id": tool_id,
"run_id": run_id,
"results": {"echo": text},
}
upload_result(result)
if __name__ == "__main__":
main()upload_result() automatically detects the backend:
| Backend | URI Example |
|---|---|
| AWS | s3://bucket/prefix/run_id/results.json |
| Azure | azureblob://account/container/path/results.json |
| GCP | gs://bucket/prefix/run_id/results.json (via google.cloud.storage) |
The runtime:
- Serializes result as JSON
- Uploads to correct backend
- Prints result to stdout (for debugging)
Adapters never upload results themselves.
From repository root:
# Build from ecosystem root (required — COPY needs omnibioai-tool-runtime/)
cd ~/Desktop/machine
docker build \
-t ghcr.io/omnibioai/omnibioai-tool-runtime:latest \
-f omnibioai-tool-runtime/Dockerfile \
.
docker push ghcr.io/omnibioai/omnibioai-tool-runtime:latestVerify:
docker images | grep omnibioai-tool-runtimedocker run --rm \
-e TOOL_ID=echo_test \
-e RUN_ID=local-test-1 \
-e INPUTS_JSON='{"text":"hello world"}' \
-e RESOURCES_JSON='{}' \
ghcr.io/omnibioai/omnibioai-tool-runtime:latestExpected:
- JSON output printed to stdout
- No upload attempted if no result URI is provided
- Image:
ghcr.io/omnibioai/omnibioai-tool-runtime:latest - Command override:
["python", "-m", "tools.echo_test.run"]S3_RESULT_URIprovided byAwsBatchAdapter- IAM Role handles S3 auth
- Image:
ghcr.io/omnibioai/omnibioai-tool-runtime:latest - Command:
python -m tools.echo_test.runRESULT_URI=azureblob://...- Managed Identity handles Blob auth
docker push ghcr.io/omnibioai/omnibioai-tool-runtime:latestaz acr login --name YOUR_ACR
docker tag ghcr.io/omnibioai/omnibioai-tool-runtime:latest YOUR_ACR.azurecr.io/omnibioai-tool-runtime:latest
docker push YOUR_ACR.azurecr.io/omnibioai-tool-runtime:latestmkdir tools/my_new_tool
touch tools/my_new_tool/__init__.py
touch tools/my_new_tool/run.pyRules:
- Must read env vars
- Must write result via
upload_result() - Must be deterministic
AWS Batch
job_definition_map:
my_new_tool: "omnibioai-my-new-tool:1"Azure Batch
tools:
my_new_tool:
image: "ghcr.io/omnibioai/omnibioai-tool-runtime:latest"
command: ["python", "-m", "tools.my_new_tool.run"]- Unified runtime image embedded in all tool Docker images
- AWS Batch support (S3 result upload)
- Azure Batch support (Azure Blob result upload)
- GCP Batch support (GCS result upload)
- Kubernetes Job support — the same image runs unmodified as a K8s Job's container; no Kubernetes-specific code lives in this repo
- Deterministic execution contract
- Reference
echo_testtool, plus the productiongeneric_sif_runnerandworkflow_runnertools - 99% test coverage
- No workflow orchestration
- No retry logic
- No state machine
- No scheduling policy
The items above describe implemented runtime behavior and intentional boundaries. Backend availability, tool identity, and scheduler policy are owned by TES adapters and structured configuration, not by this runtime README.
This runtime is intentionally boring.
That’s a feature.
- No magic
- No backend assumptions
- No hidden orchestration
- One job → one tool → one result
Everything complex belongs above this layer.
| Service | Role |
|---|---|
omnibioai-tes |
Injects env vars and submits jobs using this runtime |
omnibioai-tool-images |
Embeds this runtime in every tool Docker image |
omnibioai-studio |
Orchestrates execution backends that run this runtime |
The execution contract is implemented in omni_tool_runtime/contract.py,
run.py, result_uri.py, and upload_result.py. Backend-specific uploaders
are under omni_tool_runtime/uploaders/; the reference and embedded tools are
under tools/. TES configuration determines which tool image and backend are
selected. This repository does not define the canonical TES tool catalog.
If this runtime feels similar to:
- CWL CommandLineTool
- TES task containers
- AWS Batch single-purpose images
That’s intentional.
You’re building the correct abstraction boundary.