Running Scenarios Outside the Editor
A scenario you save in the Editor is an ordinary .json file. It can be run without the
Editor window open — with a single command, from a scheduler, or through Prefect. The robot
does exactly what you would see in the Editor; it simply draws nothing on screen.
| Need | Use |
|---|---|
| Scheduled runs while the Editor stays open on a workstation or VM | Orchestrator |
| Runs with no Editor window at all — CI, a server, an external scheduler | this page |
Running one command
Besides the scenario you need a robot profile — the one you save in the
Open Environment dialog, which is also a .json file.
aiviro-editor run --scenario invoices.json --profile robot_profile.json
Both options are required.
| Option | Effect |
|---|---|
--scenario PATH | The .json scenario to run. Required. |
--profile PATH | The robot profile to run it against. Required. |
--prod / --test | Production or test mode. --prod is the default, so a scenario runs live unless you pass --test. |
--run-log PATH | Writes a run-log .zip (action states plus logs) to that path. It opens in the Editor's log viewer via File → Open external log. |
--vault-file PATH | A .vault file exported from the Editor, supplying the run's secrets. See Secrets without a keyring. |
--config PATH | A YAML or JSON file of variable names and values, seeded into the run before it starts. See Per-environment values. |
Two options apply to the command as a whole and can also come from the environment:
| Option | Environment variable | Effect |
|---|---|---|
--log-to-console, -l | AIVIRO__LOG_TO_CONSOLE | Logs to the console — what you want in CI output. |
--debug | AIVIRO__DEBUG | Enables debug-only UI. Not useful headless. |
Running aiviro-editor with no subcommand launches the desktop GUI.
Exit codes
The command exits with 0 on success and 1 on failure, so it drops into any scheduler
or shell script. On failure it also prints Scenario failed: <summary> to standard error.
aiviro-editor run --scenario invoices.json --profile robot_profile.json --run-log run.zip || echo "failed"
Interactive actions do not work headless. A scenario containing Input Form fails with Interactive action encountered in headless mode — without a window there is nobody to ask. Gate such actions with Enabled (Test) so they never run in production.
Paths to the scenario and the profile can be absolute, or relative to the directory you run the command from.
Secrets without a keyring
A headless run used to have no access to the Vault: every secret resolved to an empty value, so any scenario that needed a credential could not run outside the Editor at all.
--vault-file closes that gap. In the Editor, Export Vault in the Secure Vault
dialog writes a .vault file; pass it to the run and its secrets are held in memory for
that run only:
aiviro-editor run --scenario invoices.json --profile robot_profile.json --vault-file secrets.vault
Nothing is written to the machine's keyring, so a CI worker or a container stays clean and does not need a keyring at all — which is what made containers awkward before.
Every secret is also available to the scenario as a variable under its key name, so a value you keep in the Vault can be read the same way an ordinary variable is.
If a secret the scenario asks for is missing from the file, the run logs a warning and carries on rather than stopping — so check the log of the first headless run of a scenario, not just its exit code.
A .vault file is your credentials in a portable file. Keep it out of git, hand it to the
run from your CI system's secret store, and delete it afterwards.
Per-environment values
--config seeds variables into the run before it starts, which is how you point one
scenario at a test and a production environment without editing the scenario itself:
# config-test.yaml
invoice_folder: C:\data\test\invoices
portal_url: https://test.example.com
account_number: "123456789"
aiviro-editor run --scenario invoices.json --profile robot_profile.json --config config-test.yaml
JSON works too — the file may be either format. Keys are variable names, values are what those variables start out as.
Both files are validated before the robot is touched: a malformed config or vault file is rejected with a clear message rather than failing half-way into a run that has already opened an application.
Scheduled runs through Prefect
For recurring runs the scenario is wrapped in a Prefect flow. Copy this template into a file
under your project's flows/ directory — for example flows/flow_invoices.py — and adjust
the values listed below it.
import aiviro
from aiviro.modules.prefect_v3.storage import AiviroGitDockerStorage
from aiviro_editor.headless.runner import run_editor_scenario
from prefect import flow
from src import get_file_path, get_work_dir
SCENARIO_FILE = "scenarios/invoices.json"
PROFILE_FILE = "data/robot_profile.json"
@flow(log_prints=True, name="Invoice processing")
def main() -> None:
result = run_editor_scenario(
get_file_path(SCENARIO_FILE),
profile=get_file_path(PROFILE_FILE),
is_prod=True,
)
if not result.success:
raise RuntimeError("Scenario failed: " + result.error_summary)
if __name__ == "__main__":
main.from_source(
source=AiviroGitDockerStorage(project_path=get_work_dir(), git_branch="main"),
entrypoint="flows/flow_invoices.py:main",
).deploy(
name="main",
work_pool_name="aiviro-local",
work_queue_name="default",
cron="0 6 * * *",
job_variables={aiviro.AIVIRO_DEBUG_KEY: "0"},
)
What to change in your copy
| Value | Meaning |
|---|---|
SCENARIO_FILE, PROFILE_FILE | Paths to the scenario and the robot profile. Written from the project root, with forward slashes /, because the server reads them. |
name on @flow | The name the flow appears under in Prefect. |
entrypoint | Must match the file's location and name exactly, or the server will not find it. |
git_branch | The branch the scenario is taken from. |
cron | When to run. None means manual runs only. |
is_prod | True for a live run, False for a test run. |
The scenario and the profile must be saved in the project and committed to git — at run time the server reads them from there, not from your computer.
The Python API
run_editor_scenario is a one-shot wrapper and takes more than the template shows:
| Parameter | Meaning |
|---|---|
scenario | Path to the .json, or an already loaded scenario. |
profile | Path to the profile, or a loaded profile object. |
robot | An existing robot to run against, instead of profile. Exactly one of profile / robot must be given. |
is_prod | True (default) for production, False for test. |
run_log_path | Where to write the run-log .zip. |
wait_after | Seconds to wait after the scenario finishes. |
config_variables | Variables seeded into the run before it starts — the API equivalent of --config. |
vault_export | An exported Vault supplying the run's secrets — the API equivalent of --vault-file. |
It returns a result with success, error_summary and run_log_path.
To run several scenarios against one robot, use EditorRunner directly instead of
calling run_editor_scenario repeatedly — it connects the robot once and reuses it, which
saves the whole connection and start-up cost per scenario.
Checklist before going headless
- Every credential is in the Vault, and the run can reach it: either the
keys exist in the keyring of the machine that will run the scenario, or you pass an
exported
.vaultfile with--vault-file, which needs no keyring at all. - No Input Form or other interactive action runs in production.
- The scenario ends with reporting — see Make the scenario survive unattended runs.
--run-logis set, so a failed run leaves something to read.- The robot profile on the target machine has the right address, credentials and display.