Skip to main content
A scenario is a directory containing a scenario.json file and optional Ansible playbooks. All scenarios live under a shared root (auto-detected, or set with -p).

Directory Layout

scenarios/
  <category>/
    <scenario-name>/
      scenario.json       # required
      prepare.yml         # optional: Ansible setup before execution
      restore.yml         # optional: Ansible teardown after execution
      validate.yml        # optional: Ansible verification after execution
      inventory.ini       # optional: Ansible inventory (inventory.yml also accepted)
      [support files]     # config snippets, fixtures, test data, etc.
The directory names are conventions for organization: they have no special meaning to the runner. The runner walks the scenarios root recursively and indexes each scenario by the key field inside its scenario.json (the directory path is not used as the key).

scenario.json

The only required file. At minimum, five fields are needed:
{
  "key": "nginx-broken-config",
  "title": "Nginx fails to start due to config syntax error",
  "description": "Nginx has a broken config and fails to start. Agent must find the syntax error, fix it, and ensure nginx is running on port 80.",
  "ticket_title": "Nginx Broken Configuration",
  "ticket_body": "The nginx web server is not running. Investigate why nginx is failing to start, fix the configuration issue, and ensure the service is running and serving traffic on port 80."
}

Required Fields

FieldDescription
keyUnique identifier for the scenario. Used to select the scenario with -s and to key its report. Free-form; conventionally the leaf directory name (e.g. nginx-broken-config).
titleHuman-readable name shown in reports and the validate output.
descriptionInternal note describing what the scenario tests. Not sent to the agent.
ticket_titleTitle of the ticket created for the run.
ticket_bodyThe instruction sent to the agent. Write it as you would a real ticket: describe symptoms, not solutions. Supports the {{schedule_time}} placeholder, which the runner replaces with a timestamp five minutes in the future.

Optional Fields

FieldDescription
tagsString array for grouping. Pass a tag to -s to run all matching scenarios (e.g. -s nginx).
hostsTarget host definitions. See Hosts.
agentsAgent definitions. See Agents.
validationValidation rules. See Validation.

Writing Good Tickets

The ticket_body is the exact instruction the agent receives. A few guidelines:
  • Describe symptoms, not solutions. “The nginx service is not running after a configuration change” is better than “Fix the nginx config file.”
  • Be concrete. Reference the host name, service name, or observable behavior when you know it.
  • Keep it realistic. Write it as you would a real support ticket or runbook task.

Scenario Keys and Tags

The key is a free-form unique identifier defined inside scenario.json. The runner indexes every discovered scenario by this value, and you select a scenario by passing its key to -s. The key does not have to match the directory path; by convention it is the leaf directory name:
scenarios/nginx/nginx-broken-config/scenario.json
                                     └─ key: "nginx-broken-config"
Tags are free-form strings for grouping. A scenario can have multiple tags:
{
  "key": "nginx-broken-config",
  "title": "Nginx fails to start due to config syntax error",
  "description": "...",
  "tags": ["nginx", "web", "config"]
}
Run all scenarios with a given tag:
2501-runner run -s nginx
2501-runner run -s web
When a -s token does not match a key exactly, it is treated as a tag. Tags and explicit keys can be mixed:
2501-runner run -s nginx,disk-cleanup