Skip to content

Template Developer Guide

A step-by-step guide for getting your processing app running on Dory — from a plain Python (or any language) app to a published template processor.

The Big Picture

Dory is a platform that streams events (from cameras and sensors) to processing apps. Your app is one of those processors. Dory does not run your code directly — it runs it as a Docker container.

Publishing a template is really just three things:

  1. Put your app in a container.
  2. Upload the container to Dory.
  3. Tell Dory "this is version 1."

Once published, your processor can be added to a lens (a named group of processors) in the Dory portal, and subscribers can use it through the SDK.

Prerequisites

  • Docker installed and running
  • The AWS CLI installed (used for the upload login; you do not need an AWS account)
  • Python 3 with the requests package (pip install requests) to run the publish tool
  • A copy of dory_util.py from this folder

All commands below are run from your app's folder, with dory_util.py reachable at the path shown. Adjust paths to wherever you placed it.


Step 1: Add a Dockerfile

In your app's folder, create a file named Dockerfile:

FROM python:3.12-slim

WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .

CMD ["python", "main.py"]

Adjust main.py to your entry script, and list your dependencies in requirements.txt.

Two things that commonly need adding:

  • The Dory processor SDK is not on PyPI. If your app imports dory (DoryApp, BaseProcessor, ...), copy the SDK repo's src/, pyproject.toml, and README.md into a dory-sdk/ folder next to your Dockerfile and install it with COPY dory-sdk/ ./dory-sdk/ + RUN pip install ./dory-sdk.
  • Computer-vision apps need system libraries that slim Python images lack. For OpenCV and RTSP capture, add before the pip installs:
RUN apt-get update && apt-get install -y --no-install-recommends \
    libgl1 libglib2.0-0 ffmpeg && rm -rf /var/lib/apt/lists/*

Also prefer opencv-python-headless over opencv-python, and if you use PyTorch, install the CPU-only wheels (pip install torch --index-url https://download.pytorch.org/whl/cpu) — the default wheel silently bundles ~5GB of CUDA libraries your container can't use.

Step 2: Build and Test Locally

The image must be built for linux/amd64. Dory runs processors on amd64 hosts. This matters especially on Apple Silicon (M1/M2/M3) Macs, which build arm64 images by default — an arm64 image will push fine but fail to start on Dory. Always pass --platform linux/amd64.

docker build --platform linux/amd64 -t my-template:latest .
docker run --rm my-template:latest

If your app starts up and runs in the container the same way it does on your machine, the hard part is done.

A RabbitMQ publisher not configured warning during local runs is normal — Dory injects the DORY_RABBITMQ_* environment variables when it runs your container for real.


Step 3: Register Your Processor in Dory

This is a one-time step that tells Dory "a processor called my-template exists."

Easiest path: use the portal. At portal.streetscapes.ai, create the template under your organization's templates page and generate its credentials there — that covers Steps 3 and 4 in a couple of clicks, and you can skip straight to Step 5. The CLI commands below are the equivalent for scripted setups.

The CLI path requires an admin user token — if you don't have one, ask your Dory administrator to run this step (and Step 4) for you.

export DORY_ACCESS_TOKEN="<your admin token>"

python3 dory_util.py create \
  --name "My Template" \
  --slug my-template

The --slug is your processor's permanent ID — lowercase, hyphenated. You'll use it everywhere below.

Verify it exists:

python3 dory_util.py list

Step 4: Create Publisher Credentials

Also one-time, also admin. This creates a machine login (an "M2M app client") that is allowed to upload images for your processor — and only your processor.

The name must be exactly template-<slug>-publisher. That naming convention is how Dory maps the credentials to your processor.

python3 dory_util.py m2m-create \
  --client-name template-my-template-publisher \
  --organization-id <your-org-uuid> \
  --m2m-scope "template_registry/push template_processors/read:self template_processors/write:self"

The output includes a clientId and clientSecret. Save them now — the secret is only shown once.

Step 5: Set Your Publish Credentials

From here on you act as the publisher, not the admin:

unset DORY_ACCESS_TOKEN   # important: the admin token would otherwise take priority

export DORY_CLIENT_ID="<clientId from Step 4>"
export DORY_CLIENT_SECRET="<clientSecret from Step 4>"

The tool exchanges these for a token automatically on every command. Don't set DORY_SCOPE — the token then carries all scopes the credentials have, which is what you want. (Requesting a scope the client doesn't hold makes Cognito reject the whole token request with invalid_grant.)

Step 6: Push and Publish

One command builds nothing new — it takes the image you built in Step 2, uploads it to Dory's registry, and registers it as a version:

python3 dory_util.py push-image \
  --tag v1.0.0 \
  --local-image my-template:latest \
  --register-version \
  --make-current

What each flag does:

Flag Meaning
--tag v1.0.0 The version label for this upload
--local-image Which local Docker image to upload (skips rebuilding)
--register-version Record this tag as a version in Dory
--make-current Make it the active version Dory runs

You do not need to create the container registry (ECR repo) first — Dory creates it automatically on your first push.

Declare your event types or subscribers can't use you. A version's supportedTags (tag UUIDs for the event types your processor emits, e.g. person) determines which subscriptions a lens containing your template can serve. dory_util.py push-image doesn't set it, so register with the raw API call (or re-register after pushing):

python3 dory_util.py raw --method POST --path /template-processors/self/versions \
  --json-body '{"tag":"v1.0.0","supportedTags":["<tag-uuid>"],"isActive":true}'

Without it, subscribers get "No processor templates in lens ... support the requested event types."

Prefer to build and push in one go? Drop --local-image and the tool runs docker build in the current directory itself:

python3 dory_util.py push-image --tag v1.0.0 --register-version --make-current

Note: the tool's built-in build does not pass --platform, so on Apple Silicon it produces an arm64 image. On those machines, build yourself with --platform linux/amd64 (Step 2) and use --local-image, or set export DOCKER_DEFAULT_PLATFORM=linux/amd64 first.

Step 7: Verify

python3 dory_util.py versions --slug my-template

You should see v1.0.0 listed and marked active. Your processor is now published. To make it usable by subscribers, add it to a lens in the Dory portal (Lenses page) — subscribers then reference that lens alias in the SDK.


Publishing an Update

Day-to-day, after the one-time setup, releasing a new version is just:

docker build --platform linux/amd64 -t my-template:latest .

python3 dory_util.py push-image \
  --tag v1.1.0 \
  --local-image my-template:latest \
  --register-version \
  --make-current

Use a new --tag each release. Drop --make-current if you want to register a version without switching live traffic to it.

Publishing from CI (GitHub Actions)

To publish automatically on push instead of from your laptop:

  1. Copy publish_template_version.sh into your app repo.
  2. Copy github_workflow/publish-template-version.yml into .github/workflows/.
  3. Add a repo secret DORY_TEMPLATE_PUBLISH_CREDENTIALS_JSON:
{"DORY_CLIENT_ID":"...","DORY_CLIENT_SECRET":"..."}

See README.md in this folder for the full list of script inputs.

Troubleshooting

Error Likely cause
M2M app client is not mapped to a template publisher The app client name doesn't follow template-<slug>-publisher
M2M app client is not active for the requested organization The client was deactivated, or belongs to a different org
This endpoint requires an M2M app client token You're pushing with a user token — unset DORY_ACCESS_TOKEN and use client credentials
Path slug 'self' is only valid for M2M app client tokens Same as above — push-image only works with publisher credentials
Token request failed Wrong DORY_CLIENT_ID/DORY_CLIENT_SECRET, or missing DORY_SCOPE
Required command not found: aws / docker Install the AWS CLI / Docker
Push succeeds but processor never starts (exec format error) Image was built for arm64 (common on Apple Silicon) — rebuild with --platform linux/amd64 and push again

Add --debug to any dory_util.py command to see the full HTTP traffic (tokens redacted).