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:
- Put your app in a container.
- Upload the container to Dory.
- 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
requestspackage (pip install requests) to run the publish tool - A copy of
dory_util.pyfrom 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'ssrc/,pyproject.toml, andREADME.mdinto adory-sdk/folder next to your Dockerfile and install it withCOPY 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.
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:
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-imagedoesn'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:
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¶
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:
- Copy
publish_template_version.shinto your app repo. - Copy
github_workflow/publish-template-version.ymlinto.github/workflows/. - Add a repo secret
DORY_TEMPLATE_PUBLISH_CREDENTIALS_JSON:
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).