Tutorial: Running the Multi-Actor Container Demos
In this tutorial, we will run a multi-actor demo scenario end to end with Docker Compose. By the end of this tutorial, we will have:
- started a fleet of isolated Vultron actor containers, each representing a distinct Coordinated Vulnerability Disclosure (CVD) participant,
- chosen a scenario and watched its actors exchange messages across container boundaries, and
- read the structured output that tells us which step ran, which check passed, and which causal gate held.
What we will learn
These scenarios use trigger-based puppeteering. The demo runner calls trigger endpoints on each actor's own container, so each actor's behavior tree and outbox logic run end to end. Each actor makes its own decisions, and activities flow from the sender's outbox to the receiver's inbox over HTTP across the Docker network. No messages are injected by hand. This is the full Vultron Protocol in action, not a simulation.
Prerequisites
You need the following tools installed before we begin:
- Docker (version 20.10 or later)
- Docker Compose (version 2.x; included with Docker Desktop)
- Git (to clone the repository)
You do not need Python installed locally; the containers include everything required.
Step 1 — Clone the repository
First, let's get a local copy of the Vultron project:
git clone https://github.com/CERTCC/Vultron.git
cd Vultron
Tip
If you already have a local clone, cd into the repository root and run git pull to make sure you are up to date.
Step 2 — Create the environment file
Before running any docker compose command, create a local .env file from the provided example:
cp docker/.env.example docker/.env
This sets the Docker Compose project name, which the container, network, and volume names are derived from.
Step 3 — Choose a scenario
Every scenario is selected by the DEMO environment variable.
The table below is rendered from the scenario registry at build time, so the DEMO values it lists are exactly the ones the demo runner accepts.
| Scenario | DEMO value |
Participants | Notable protocol feature |
|---|---|---|---|
| RCCV-extension | rccv-extension |
Reporter + C1 + C2 + Vendor | Second coordinator suggests vendor |
| RCCV-handoff | rccv-handoff |
Reporter + C1 → C2 + Vendor | Ownership transfer between two coordinators |
| RCV | rcv |
Reporter + Coordinator + Vendor | Coordinator-mediated report and vendor onboarding |
| RCV embargo | rcv-embargo |
Reporter + Coordinator + Vendor | Embargo revision after submission and deliberate termination |
| RCV-reject | rcv-reject |
Reporter + Coordinator + Vendor (Vendor rejects) | Invite rejection path |
| RCVCV | rcvcv |
Reporter + C1 + V1 + C2 + V2 | Actor-suggestion flow (ADR-0026) |
| RCVV embargo | rcvv-embargo |
Reporter + Coordinator + Vendor1 + Vendor2 | Embargo revision cycle, late second vendor, and accidental collapse |
| rv | rv |
Reporter + Vendor | Baseline two-actor CVD |
| RVCV-extension | rvcv-extension |
Reporter + Vendor1 + Coordinator + Vendor2 | Coordinator-suggested second vendor |
| RVCV-handoff | rvcv-handoff |
Reporter + Vendor1 → Coordinator + Vendor2 | Case-ownership transfer to coordinator |
| RVV | rvv |
Reporter + Vendor1 + Vendor2 | Direct invitation of a second vendor |
Each scenario is self-contained. The demo runner resets every container's state, seeds the actor records and their peer registrations, runs the workflow, verifies the final state, and exits. The Demo Scenario Narratives explain what each scenario demonstrates and why its steps happen in the order they do.
Step 4 — Run the scenario
From the repository root, run the compose stack with DEMO set to the value you chose:
DEMO=rcv docker compose -f docker/docker-compose-multi-actor.yml \
up --abort-on-container-exit --exit-code-from demo-runner
If you leave DEMO unset, the runner executes the rv scenario.
Run the rv Demo walks through that run milestone by milestone.
Docker builds the images on the first run, which takes a few minutes. Subsequent runs reuse the cached images and start immediately. Once the images exist, compose:
- starts the actor containers (
reporter,vendor,coordinator,case-actor,actor5, andactor6), whether or not the chosen scenario uses them all, - waits until every actor container passes its
/health/readyprobe, - starts
demo-runner, which resets state, seeds actors, drives the workflow, verifies each milestone, and exits, and - stops the whole stack when
demo-runnerexits, propagating its exit code.
Every scenario uses case-actor: it hosts the Case Actor that manages each case and holds its canonical ledger.
Success indicator
Every scenario ends with its own banner, <SCENARIO> DEMO COMPLETE ✓, followed by a note on what it demonstrated.
A default rv run, for example, ends with:
rv DEMO COMPLETE ✓ (VFDPxa full lifecycle)
A non-zero exit code from demo-runner means a step or check failed; see Step 5.
Step 5 — Read the output
Each step of a scenario is wrapped in a demo_step, demo_check, or demo_gate context manager that prints a structured lifecycle marker:
| Symbol | Meaning |
|---|---|
| 🚥 | A workflow step has started |
| 🟢 | The step completed successfully |
| 🔴 | The step raised an exception |
| 📋 | A verification check has started |
| ✅ | The verification check passed |
| ❌ | The verification check failed |
| 🚧 | A causal gate (a precondition for later steps) has started |
| 🔓 | The gate's precondition held |
| 🔒 | The gate failed; the steps that depend on it were skipped |
Watch for 🔴, ❌, and 🔒 markers to diagnose a failure.
A gate waits for evidence that an earlier step's effect has been committed by the actor that owns it, rather than for a fixed delay, so a 🔒 names the protocol effect that never arrived.
To examine the logs of one container after a run:
docker compose -f docker/docker-compose-multi-actor.yml logs vendor
To watch one actor's case ledger while a scenario runs, tail its ledger stream. Look up the host port Docker assigned to the actor's container, then open the stream with the case's id:
docker compose -f docker/docker-compose-multi-actor.yml port vendor 7999
curl -N "http://localhost:<port>/api/v2/actors/vendor/demo/cases/<case-id>/log/stream"
The stream first replays every ledger entry the actor holds for that case, then sends each new entry as the actor records it.
Each event's id: is the entry's logIndex, and its data: is the entry as JavaScript Object Notation (JSON), the same form …/log returns.
Add ?since=<logIndex> to skip the entries you have already seen.
When the server shuts down, the stream sends a final event: close.
The stream and the …/log endpoints exist only in prototype mode, and they are demo tooling: participants never use them to replicate a ledger.
Step 6 — Clean up
Named Docker volumes persist the SQLite databases between runs. Remove all volumes after a session to start fresh next time:
docker compose -f docker/docker-compose-multi-actor.yml down -v
Running scenarios from the integration test script
The integration test script builds the images, runs one scenario, checks the exit code, and removes all volumes automatically:
# From the repository root:
./integration_tests/demo/run_multi_actor_integration_test.sh rv
./integration_tests/demo/run_multi_actor_integration_test.sh rcv
./integration_tests/demo/run_multi_actor_integration_test.sh rvcv-handoff
A passing run ends with the script's own summary line:
[multi-actor-integration] SUCCESS: scenario 'rv' passed.
Tip
The integration test script uses PROJECT_NAME=vultron-it by default so its containers do not conflict with a running development stack.
Override PROJECT_NAME to run scenarios in parallel:
PROJECT_NAME=vultron-it-two DEMO=rv \
./integration_tests/demo/run_multi_actor_integration_test.sh
PROJECT_NAME=vultron-it-three DEMO=rcv \
./integration_tests/demo/run_multi_actor_integration_test.sh
What we accomplished
We have:
- started a multi-container Vultron stack and run a multi-actor CVD workflow across isolated participant containers,
- observed trigger-based puppeteering, where each actor's own behavior tree and outbox logic drive the workflow end to end, and
- read the step, check, and gate markers that show what the protocol did at each stage.
Next steps
- Follow one run in detail — Run the
rvDemo explains each phase and milestone of the default scenario. - Understand what each scenario shows — the Demo Scenario Narratives describe every scenario's case in CVD terms, step by step.
- Read the message-level trace — the
rvDemo Protocol Reference lists every activity thervrun exchanges and the ledger entries it produces. - Explore the single-container demos — see Run the Receive-Report Demo and Running the Other Demos to step through individual protocol exchanges.
- Read the scenario source — the scripts are in
vultron/demo/scenario/; the shared helpers are invultron/demo/helpers/. - Consult the Docker README —
docker/README.mddocuments port mappings, environment variable overrides, and manual seed commands for debugging individual containers.
Reading path: You want to work on the Vultron reference implementation
This page is part of Run it.
Before this page:
After this page: