Trace an application package · 8 minutes
Open quick-start.cwl and inputs.yaml in the repository's notebooks/ directory. The snippets below explain selected parts of those files; they are not complete standalone packages.
1. Find the public interface · 2 minutes
The CWL document declares cwlVersion: v1.2. Its $graph contains a Workflow with id: main and a CommandLineTool with id: rio-bounds.
The workflow accepts geotiff and returns bounds. Its input uses a record type named URI, imported from the shared EOAP schemas:
geotiff:
type: https://raw.githubusercontent.com/eoap/schemas/main/string_format.yaml#URI
label: GeoTIFF URI
doc: URI of the GeoTIFF whose bounding geometry will be returned.
The record has one string field, value. It comes from the remote string_format.yaml schema imported by both the workflow and tool:
SchemaDefRequirement:
types:
- $import: https://raw.githubusercontent.com/eoap/schemas/main/string_format.yaml
This shared URI convention is also used in the mastering-app-package module; it is not a built-in CWL type or a universal requirement for every EOAP. Resolving the package requires access to the remote schema. Native File and Directory types have different staging semantics: the runner manages files or directories, whereas this tool reads the URI itself.
2. Supply a value · 2 minutes
The job file contains:
geotiff:
value: https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/10/T/FK/2021/7/S2B_10TFK_20210713_0_L2A/B02.tif
The nesting matters: geotiff receives a record containing value, not a bare URL string. The package also has a default GeoTIFF URI, so a job file can be omitted for the default run.
Try it on paper: change B02.tif to B01.tif in a copy of the job. Which file describes the new execution? The job file; the application package stays the same.
3. Follow the command and output · 3 minutes
The workflow connects its input to the tool:
steps:
bounds:
run: '#rio-bounds'
in:
geotiff: geotiff
out: [bounds]
The tool uses baseCommand: rio and arguments: [bounds]. Its binding extracts the URL:
inputBinding:
position: 1
valueFrom: $(self.value)
Together these construct rio bounds <GeoTIFF-URL>. The tool's stdout: bounds.json captures the command's output. Its outputBinding.glob: bounds.json collects that file, and the workflow's outputSource: bounds/bounds exposes it to the caller.
The result is GeoJSON describing the raster's bounding geometry. This example reads raster metadata; it does not produce a cropped raster. The cropping notebooks are a separate, longer exercise.
4. Identify the environment · 1 minute
Find DockerRequirement.dockerPull, NetworkAccess and the s: metadata in the complete file. The image supplies rio; network access allows the remote GeoTIFF to be read; metadata identifies the application, author, version, license and documentation.
The image localhost/rio:latest is built locally for this lesson. A shared deployment needs an image reference the target platform can retrieve, preferably pinned to a digest.
Continue to build, deploy and run, then return for the final two-minute check.
Check your understanding
Answer without running anything:
- Which class exposes the application's public inputs and outputs?
- What command runs when
geotiff.valueis supplied? - How does
bounds.jsonbecome a workflow result? - Can a cloud platform retrieve an image built only on your laptop?
Check your answers
- The
Workflownamedmain. rio bounds <the supplied URL>inside the selected container.stdoutcreates it, the tool collects it withglob, and the workflow exposes it throughoutputSource.- The platform needs an accessible registry image or an explicitly supported image-loading mechanism.
You have finished the core lesson when you can explain input → workflow → container command → output and name one platform dependency.
Optional: execute the example after the lesson
Allow extra time for installation, image download and network access. You need cwltool, Podman and access to the sample GeoTIFF. In a terminal, start at the repository root:
cd notebooks
cwltool --validate quick-start.cwl
Build the lesson image from a separate Dockerfile; the tracked notebooks/Dockerfile is a different GDAL-based example:
cat > Dockerfile.rio <<'EOF'
FROM docker.io/python:3.12-slim
RUN apt-get update && apt-get install -y --no-install-recommends libexpat1 && rm -rf /var/lib/apt/lists/*
RUN pip install --no-cache-dir rasterio==1.5.1 click==8.4.1
ENTRYPOINT []
EOF
podman build -t localhost/rio:latest -f Dockerfile.rio .
cwltool --podman --outdir results quick-start.cwl inputs.yaml
A successful run reports the bounds output and writes results/bounds.json. Inspect that file for GeoJSON geometry. Image failures usually indicate a missing local image; remote-read failures require checking the URL and network access.
For further practice, open 01 Command line, 02 Container, then 03 Package. These are optional labs outside the 20-minute route.