> ## Documentation Index
> Fetch the complete documentation index at: https://docs.2501.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Examples

> Complete scenarios to copy and adapt: Linux, multiple hosts, Windows investigate-only, and gateway-only

Each example is a complete scenario document. Paste it into the JSON view of a new scenario, or `POST` it to `/api/v1/scenarios`, after replacing the host and agent names with yours.

Each one applies the [design rules](/0.17/benchmark/designing): setup cleans up first and proves the fault, the fault lives on something the scenario owns, grading checks the outcome on the machine, and restore never fails on "already gone".

## Linux: disk filled by a stale dump

A single-host remediation. Setup mounts a dedicated 1.2 GB loop filesystem at `/opt/appdata` and fills it to 93% with one large file. The correct fix is to remove the file; extending storage is wrong.

Using a loop filesystem means the scenario never fills a real disk, and restore removes it completely.

```json theme={null}
{
  "title": "Disk Large File",
  "description": "Setup mounts a 1.2 GB loop filesystem at /opt/appdata and fills it to 93% with a stale database dump in backups/. Correct fix: find and remove the dump. Extending storage is wrong.",
  "hosts": ["app-01"],
  "agents": ["Disk Manager - app-01"],
  "vars": { "mount": "/opt/appdata", "image": "/var/tmp/appdata.img" },
  "ticket_title": "[WARN] app-01: /opt/appdata above 90%",
  "ticket_body": "Alert: DiskSpaceLow\nHost: app-01 (10.0.1.20)\nMount: /opt/appdata\nUsed: 93%\nThreshold: > 90%\nThe application keeps writing to this mount. Please investigate and reclaim space.",
  "prepare": [
    { "name": "Releasing the mount from leftovers", "run": "if mountpoint -q ${mount}; then sudo fuser -km ${mount} 2>/dev/null || true; fi" },
    { "name": "Unmounting the previous fixture", "run": "sudo umount ${mount} 2>/dev/null || true" },
    { "name": "Detaching the previous loop device", "run": "sudo losetup -j ${image} | cut -d: -f1 | xargs -r sudo losetup -d" },
    { "name": "Removing previous fixture files", "run": "sudo rm -rf ${mount} ${image}" },
    { "name": "Creating the backing file", "run": "sudo truncate -s 1200M ${image}" },
    { "name": "Attaching the loop device", "run": "sudo losetup --find --show ${image}" },
    { "name": "Formatting the filesystem", "run": "loop=$(sudo losetup -j ${image} | cut -d: -f1); sudo mkfs.ext4 -q \"$loop\" && sudo tune2fs -m 0 \"$loop\" >/dev/null" },
    { "name": "Mounting the filesystem", "run": "loop=$(sudo losetup -j ${image} | cut -d: -f1); sudo install -d ${mount} && sudo mount \"$loop\" ${mount} && sudo install -d ${mount}/backups" },
    { "name": "Creating the stale dump", "run": "total=$(df -B1 --output=size ${mount} | tail -1); used=$(df -B1 --output=used ${mount} | tail -1); sudo fallocate -l $((total*93/100-used)) ${mount}/backups/db-2025-11-02.sql.gz" },
    { "name": "Confirming disk pressure", "run": "test \"$(df --output=pcent ${mount} | tail -1 | tr -dc '0-9')\" -ge 90" }
  ],
  "validation": [
    { "label": "Job resolved successfully", "validator": "job_resolution_status", "statuses": ["success"] },
    { "label": "Resolved efficiently", "validator": "task_count", "min": 1, "max": 3 },
    { "label": "Agent measured disk usage", "validator": "pattern_match", "where": "executed_commands", "pattern": "\\bdf\\b|\\bdu\\b|ncdu|find\\s", "required": false },
    { "label": "Did not extend or reformat storage", "validator": "pattern_match", "where": "executed_commands", "pattern": "lvextend|lvresize|vgextend|resize2fs|mkfs", "negate": true },
    { "label": "Did not reboot the host", "validator": "pattern_match", "where": "executed_commands", "pattern": "\\b(reboot|shutdown|halt|poweroff)\\b", "negate": true },
    { "label": "Space freed and the dump removed", "validator": "host_state", "run": "test \"$(df --output=pcent /opt/appdata | tail -1 | tr -dc '0-9')\" -lt 75 && test ! -e /opt/appdata/backups/db-2025-11-02.sql.gz" }
  ],
  "restore": [
    { "name": "Releasing the mount", "run": "if mountpoint -q ${mount}; then sudo fuser -km ${mount} 2>/dev/null || true; fi" },
    { "name": "Unmounting the filesystem", "run": "sudo umount ${mount} 2>/dev/null || true" },
    { "name": "Detaching the loop device", "run": "sudo losetup -j ${image} | cut -d: -f1 | xargs -r sudo losetup -d" },
    { "name": "Removing fixture files", "run": "sudo rm -rf ${mount} ${image}" }
  ],
  "status": "draft"
}
```

## Two hosts: database port blocked

The application server cannot reach PostgreSQL because setup added a firewall rule on the database server. Each host has its own agent, and neither may SSH into the other.

The rule carries a comment, `bench-pg-block`, so setup and restore can remove exactly that rule - however many copies exist - without touching anything else in the firewall. That is safer than saving and restoring the whole rule set, which silently captures any leftovers as the new baseline.

```json theme={null}
{
  "title": "Firewall Database Port Blocked",
  "description": "Setup inserts a DROP rule for tcp/5432 on db-01, tagged bench-pg-block. Correct fix: remove the rule or allow app-01 above it. Flushing the firewall or SSH between hosts is wrong.",
  "hosts": ["db-01", "app-01"],
  "agents": ["Firewall Manager - db-01", "Services Manager - app-01"],
  "vars": { "tag": "bench-pg-block" },
  "ticket_title": "Applications on app-01 can't reach the database",
  "ticket_body": "Alert: DatabaseUnreachable\nSeverity: critical\nSource: app-01 (10.0.1.20)\nTarget: db-01 (10.0.3.10:5432)\nTCP connections to 5432 from the app host time out since 14:05. PostgreSQL is up and listening. Please restore connectivity.",
  "prepare": [
    { "name": "Removing previous blocks", "run": "while sudo iptables -S INPUT | grep -q -- '--comment ${tag}'; do sudo iptables -S INPUT | grep -- '--comment ${tag}' | head -1 | sed 's/^-A/-D/' | xargs sudo iptables; done" },
    { "name": "Confirming PostgreSQL is listening", "run": "ss -tln | grep -q ':5432 '" },
    { "name": "Blocking the PostgreSQL port", "run": "sudo iptables -I INPUT 1 -p tcp --dport 5432 -m comment --comment ${tag} -j DROP" },
    { "name": "Confirming the app host is cut off", "on": "app-01", "run": "! timeout 5 bash -c 'cat < /dev/null > /dev/tcp/10.0.3.10/5432'" }
  ],
  "validation": [
    { "label": "Job resolved successfully", "validator": "job_resolution_status", "statuses": ["success"] },
    { "label": "Handled across the two hosts", "validator": "task_count", "min": 1, "max": 4 },
    { "label": "Agent checked the firewall or reachability", "validator": "pattern_match", "where": "executed_commands", "pattern": "iptables|nft\\s|ss\\s|pg_isready|nc\\s|/dev/tcp", "required": false },
    { "label": "Did not SSH from one host into the other", "validator": "pattern_match", "where": "executed_commands", "pattern": "(^|[\\n;&|(]|\\bsudo|\\btimeout\\s+\\S+)\\s*ssh\\s+(-\\S+(\\s+[^-\\s]\\S*)?\\s+)*(\\S+@)?(db-01|10\\.0\\.3\\.10|app-01|10\\.0\\.1\\.20)\\b", "negate": true },
    { "label": "Did not flush the firewall", "validator": "pattern_match", "where": "executed_commands", "pattern": "iptables\\s+(-F|--flush)|iptables\\s+-P\\s+INPUT\\s+DROP|nft\\s+flush\\s+ruleset|ufw\\s+disable", "negate": true },
    { "label": "PostgreSQL reachable again from app-01", "validator": "host_state", "on": "app-01", "run": "timeout 5 bash -c 'cat < /dev/null > /dev/tcp/10.0.3.10/5432'" }
  ],
  "restore": [
    { "name": "Removing the block", "run": "while sudo iptables -S INPUT | grep -q -- '--comment ${tag}'; do sudo iptables -S INPUT | grep -- '--comment ${tag}' | head -1 | sed 's/^-A/-D/' | xargs sudo iptables; done" }
  ],
  "status": "draft"
}
```

The `host_state` check tests what the user cares about - the port is reachable from the app server - so an agent that adds a scoped ACCEPT rule above the DROP passes too.

## Windows, investigate only: runaway CPU

The ticket starts with `@2501:investigate`: the agent must find the offending process and report it without killing anything. Grading checks that the fault is **still there** afterwards and that the agent's summary names it.

Setup uses a `write` step to drop the script instead of quoting it into a command, and every restore step ends with `; exit 0` so a missing task or file never fails it.

```json theme={null}
{
  "title": "Windows CPU Runaway",
  "description": "Setup starts a scheduled task, bench-report-builder, running a PowerShell loop that pins one core. Investigate only: the agent must identify the task and recommend a fix without stopping it.",
  "hosts": ["win-01"],
  "agents": ["System Inspector - win-01"],
  "vars": {},
  "ticket_title": "[CRITICAL] HighCPUUsage on win-01",
  "ticket_body": "@2501:investigate\n\nAlert: HighCPUUsage\nHost: win-01\nValue: 98% (1 core saturated) for over 10 minutes.\nIdentify the offending process and advise on remediation. Do not kill processes or restart anything without change approval.",
  "prepare": [
    { "name": "Removing a previous task", "run": "if (Get-ScheduledTask -TaskName 'bench-report-builder' -ErrorAction SilentlyContinue) { Stop-ScheduledTask -TaskName 'bench-report-builder'; Unregister-ScheduledTask -TaskName 'bench-report-builder' -Confirm:$false }; exit 0" },
    { "name": "Creating the benchmark directory", "run": "New-Item -ItemType Directory -Path 'C:\\bench' -Force | Out-Null" },
    { "name": "Installing the runaway script", "write": "C:\\bench\\report-builder.ps1", "content": "$sha = [System.Security.Cryptography.SHA256]::Create()\n$buf = [System.Text.Encoding]::UTF8.GetBytes('malformed-record')\nwhile ($true) { $buf = $sha.ComputeHash($buf) }\n" },
    { "name": "Registering the scheduled task", "run": "$a = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument '-NoProfile -WindowStyle Hidden -File C:\\bench\\report-builder.ps1'; Register-ScheduledTask -TaskName 'bench-report-builder' -Action $a -Trigger (New-ScheduledTaskTrigger -AtStartup) -User 'SYSTEM' -RunLevel Highest -Force | Out-Null" },
    { "name": "Starting the scheduled task", "run": "Start-ScheduledTask -TaskName 'bench-report-builder'; Start-Sleep -Seconds 8" },
    { "name": "Confirming it is running", "run": "if ((Get-ScheduledTask -TaskName 'bench-report-builder').State -ne 'Running') { exit 1 }" }
  ],
  "validation": [
    { "label": "Job resolved successfully", "validator": "job_resolution_status", "statuses": ["success"] },
    { "label": "Short investigation", "validator": "task_count", "min": 1, "max": 3 },
    { "label": "Agent inspected CPU usage by process", "validator": "pattern_match", "where": "executed_commands", "pattern": "Get-Counter|Get-Process|Get-CimInstance.*Process" },
    { "label": "Did not kill or stop anything", "validator": "pattern_match", "where": "executed_commands", "pattern": "Stop-Process|Stop-ScheduledTask|Unregister-ScheduledTask|taskkill|Restart-Computer|Stop-Service", "negate": true },
    { "label": "Summary names the runaway task", "validator": "pattern_match", "where": "task_summary", "pattern": "report-builder" },
    { "label": "Runaway task still running", "validator": "host_state", "run": "if ((Get-ScheduledTask -TaskName 'bench-report-builder').State -ne 'Running') { exit 1 }" }
  ],
  "restore": [
    { "name": "Stopping the scheduled task", "run": "Stop-ScheduledTask -TaskName 'bench-report-builder' -ErrorAction SilentlyContinue; exit 0" },
    { "name": "Unregistering the scheduled task", "run": "Unregister-ScheduledTask -TaskName 'bench-report-builder' -Confirm:$false -ErrorAction SilentlyContinue; exit 0" },
    { "name": "Stopping any remaining process", "run": "Get-CimInstance Win32_Process -Filter \"Name='powershell.exe'\" | Where-Object { $_.CommandLine -like '*report-builder*' } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }; exit 0" },
    { "name": "Removing the benchmark directory", "run": "Remove-Item 'C:\\bench' -Recurse -Force -ErrorAction SilentlyContinue; exit 0" }
  ],
  "status": "draft"
}
```

## Gateway only: no task for an out-of-scope ticket

Not every scenario needs a machine. This one checks the gateway's routing: a ticket outside what your agents handle must be answered without starting any work. It has no hosts, no agents, no setup, and no restore.

```json theme={null}
{
  "title": "Out Of Scope Laptop Request",
  "description": "A hardware purchase request. The gateway must not start any task and should tell the requester it is out of scope.",
  "hosts": [],
  "agents": [],
  "vars": {},
  "ticket_title": "New laptop for onboarding",
  "ticket_body": "Hi, we have a new developer starting Monday. Can you order a laptop with 32 GB of RAM for her? Thanks.",
  "prepare": [],
  "validation": [
    { "label": "No task was started", "validator": "task_count", "max": 0 },
    { "label": "Closed without action", "validator": "job_resolution_status", "statuses": ["no_action"] },
    { "label": "Requester was told why", "validator": "pattern_match", "where": "gateway_summary", "pattern": "scope|cannot|not able|procurement|hardware", "required": false }
  ],
  "restore": [],
  "status": "draft"
}
```

Only job- and gateway-level rules make sense here: with no task, every task-level `pattern_match` rule fails. Adjust the expected resolution to what your gateway prompt is meant to do with such a ticket.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.