Scenario Format
Scenarios are JSON files that describe a time-indexed sequence of sensor states to inject into a connected device. The CLI validates them against the published JSON Schema before running.
Schema URL: https://sensorchaos.com/schema/scenario/1.0
Add "$schema": "https://sensorchaos.com/schema/scenario/1.0" to your file for autocomplete in VS Code and other JSON-aware editors.
Top-level fields
Section titled “Top-level fields”| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | Human-readable display name |
description | string | yes | One-sentence description |
version | string | yes | Schema version — always "1.0" |
duration_s | number | yes | Total scenario length in seconds |
tags | string[] | no | Searchable labels (e.g. "spoofing", "logistics") |
baseline | object | yes | Starting sensor state before the timeline begins |
timeline | array | yes | Ordered keyframes indexed by at_s |
expect | object | no | Assertions evaluated after the run (for CI) |
baseline
Section titled “baseline”Defines the initial sensor state. The engine emits these values from t=0 until the first timeline entry fires. All fields are optional — omit anything you don’t need for your scenario.
"baseline": { "location": { "lat": 51.5074, "lng": -0.1278, "accuracy_m": 6, "satellites": 10, "altitude_m": 35, "speed_mps": 0, "bearing_deg": 0 }, "accelerometer": [0.0, 0.0, 9.81], "gyroscope": [0.0, 0.0, 0.0], "magnetometer": [20.0, -5.0, -44.0], "barometer": [1013.25], "update_intervals_ms": { "location": 1000, "sensors": 50 }}baseline.location
Section titled “baseline.location”| Field | Type | Description |
|---|---|---|
lat | number | null | Latitude in decimal degrees (null = no fix) |
lng | number | null | Longitude in decimal degrees (null = no fix) |
accuracy_m | number | null | Horizontal accuracy in metres |
satellites | integer | null | Visible satellite count |
altitude_m | number | null | Altitude in metres above sea level |
speed_mps | number | null | Ground speed in m/s |
bearing_deg | number | null | Heading in degrees (0–360) |
baseline.accelerometer / gyroscope / magnetometer
Section titled “baseline.accelerometer / gyroscope / magnetometer”Three-element array [x, y, z]. Units:
- Accelerometer — m/s² (gravity component included; at rest:
[0.0, 0.0, 9.81]) - Gyroscope — rad/s
- Magnetometer — µT
baseline.barometer
Section titled “baseline.barometer”Single-element array [pressure_hPa]. Standard sea-level pressure is 1013.25.
baseline.update_intervals_ms
Section titled “baseline.update_intervals_ms”| Field | Default | Description |
|---|---|---|
location | 1000 | GPS update interval in milliseconds |
sensors | 50 | IMU/barometer update interval in milliseconds |
wifi | 5000 | Wi-Fi scan interval in milliseconds |
timeline
Section titled “timeline”An ordered array of keyframes. Each entry has the same sensor fields as baseline, plus:
| Field | Type | Required | Description |
|---|---|---|---|
at_s | number | yes | Seconds from scenario start when this keyframe fires |
note | string | no | Human-readable label shown in CLI output and reports |
Partial overrides — you only need to include the fields that change. Omitted fields are inherited from the previous keyframe (or baseline).
Linear interpolation — the engine interpolates between consecutive keyframes on each tick (default 1 Hz), so you only need to specify keyframes, not every second.
Signal loss — set lat, lng, accuracy_m (or any sensor field) to null to inject signal absence.
Field reference summary
Section titled “Field reference summary”| Scenario type | Required agent? | Fields used |
|---|---|---|
| GNSS-only | no (emulator/ADB helper) | location only |
| Multi-sensor | yes (--agent) | location + accelerometer + gyroscope + magnetometer + barometer |
expect
Section titled “expect”The expect block declares pass/fail assertions that are evaluated automatically after the scenario completes. If any assertion fails, sensorchaos run exits with code 1 — no extra flags needed. This makes it the primary hook for CI pipelines.
"expect": { "no_crash": true, "no_signal_loss": false, "max_position_error_km": 0.5, "max_injection_errors": 0, "min_resilience_score": 60}| Field | Type | Description |
|---|---|---|
no_crash | boolean | Fail if any app_crash event was recorded during the run |
no_signal_loss | boolean | Fail if any tick had null GPS (i.e. signal was absent at any point) |
max_position_error_km | number | Fail if the maximum haversine distance between injected and reported location exceeds this value (requires agent) |
max_injection_errors | integer | Fail if the number of agent injection errors exceeds this count |
min_resilience_score | number | Fail if the overall resilience score (0–100) is below this threshold |
Assertion results are printed after the run:
Assertions (3/3 passed): ✓ no_crash: 0 crashes ✓ max_injection_errors: 0 injection errors ✗ min_resilience_score: 54 (expected ≥ 60)Validation
Section titled “Validation”Validate a scenario file without running it:
sensorchaos validate path/to/my-scenario.jsonExits 0 on success, 1 with detailed error messages on failure. sensorchaos run also validates automatically before starting.