Scenario Recipe Schema

This page documents the canonical upload contract for scenario recipes. It is language-agnostic: the schema is described as JSON with per-field expectations. The source of truth lives in packages/types/src/schemas/scenarios.ts (ScenarioRecipesFileSchema).

The file is posted as the JSON body of:

POST /v1/setup/setups/:setupId/scenario-recipe-versions

Top-level shape

{
"version": 1,
"source": {
"discoverPath": "string",
"scenariosPath": "string"
},
"validationMode": "sdk-check" | "endpoint-lifecycle",
"recipes": [ /* at least one ScenarioRecipe */ ]
}
FieldTypeRequiredNotes
versioninteger, must equal 1yesContract version. Currently only 1 is accepted. Not a string.
sourceobjectyesProvenance pointers. Additional keys are preserved.
source.discoverPathstringyesPath (relative to the application repo) to the discovery output, e.g. autonoma/discover.json. Required - omitting it causes Zod to fail with expected string, received undefined.
source.scenariosPathstringyesPath to the human-readable scenarios document, e.g. autonoma/scenarios.md.
validationMode"sdk-check" | "endpoint-lifecycle"yesHow Autonoma validated the recipes before upload. sdk-check = checkScenario/checkAllScenarios. endpoint-lifecycle = real HTTP up/down.
recipesarray, minimum length 1yesOne entry per scenario. See below.

ScenarioRecipe (one entry in recipes[])

{
"name": "string",
"description": "string",
"create": { /* arbitrary model graph, see below */ },
"variables": { /* optional, see below */ },
"validation": {
"status": "validated",
"method": "checkScenario" | "checkAllScenarios" | "endpoint-up-down",
"phase": "ok",
"up_ms": 0,
"down_ms": 0
}
}
FieldTypeRequiredNotes
namestringyesStable identifier. Must match the scenario name used in the LLM-facing docs.
descriptionstringyesHuman-readable summary of the scenario state.
createobjectyesThe model graph passed to the SDK’s createScenario / up flow. Keys are model names; values are arrays or objects of seeded rows. Extra keys are preserved.
variablesobject (map of name → definition)noPer-recipe dynamic values. See Variable definitions below.
validationobjectyesProof that the recipe was validated. All fields must be present.
validation.statusliteral string "validated"yes
validation.methodone of "checkScenario", "checkAllScenarios", "endpoint-up-down"yesWhich validator produced this result.
validation.phaseliteral string "ok"yes
validation.up_msnon-negative integernoMilliseconds the up phase took.
validation.down_msnon-negative integernoMilliseconds the down phase took.

Variable definitions

variables is a map from variable name to a tagged union discriminated by the strategy field. Exactly one of the three shapes below is valid per entry. Unknown strategy values are rejected.

literal

Emits a fixed scalar on every run.

{
"strategy": "literal",
"value": "admin@example.com"
}
FieldTypeRequiredNotes
strategyliteral "literal"yes
valuestring | number | boolean | nullyesAny JSON scalar. Objects and arrays are not allowed.

derived

Derives a deterministic value from the test run ID (so every invocation of the same test gets the same value, but different runs get different values).

{
"strategy": "derived",
"source": "testRunId",
"format": "user-{shortId}@example.com"
}
FieldTypeRequiredNotes
strategyliteral "derived"yes
sourceliteral "testRunId"yesOnly testRunId is supported today.
formatstringyesTemplate. The token {shortId} is replaced with a short hash of the run ID.

faker

Generates a fresh random value per run using Faker.

{
"strategy": "faker",
"generator": "internet.email"
}
FieldTypeRequiredNotes
strategyliteral "faker"yes
generatordotted Faker method pathyese.g. internet.email, person.firstName, commerce.productName.

Full example

{
"version": 1,
"source": {
"discoverPath": "autonoma/discover.json",
"scenariosPath": "autonoma/scenarios.md"
},
"validationMode": "sdk-check",
"recipes": [
{
"name": "adminWithTwoProjects",
"description": "Organization with an admin user and two projects.",
"create": {
"Organization": [{ "id": "org-1", "name": "Acme" }],
"User": [
{
"id": "user-1",
"email": "{adminEmail}",
"role": "admin",
"organizationId": "org-1"
}
],
"Project": [
{ "id": "proj-1", "name": "Alpha", "organizationId": "org-1" },
{ "id": "proj-2", "name": "Beta", "organizationId": "org-1" }
]
},
"variables": {
"adminEmail": {
"strategy": "derived",
"source": "testRunId",
"format": "admin-{shortId}@acme.test"
}
},
"validation": {
"status": "validated",
"method": "checkScenario",
"phase": "ok",
"up_ms": 142,
"down_ms": 61
}
}
]
}

Common rejection reasons

  • expected string, received undefined under source.discoverPath - the source object is missing discoverPath. Both discoverPath and scenariosPath are required.
  • Discriminated union error under recipes[n].variables.<name> - an unknown or missing strategy key. Use exactly one of "literal", "derived", "faker".
  • version must be literal 1 - don’t send "1" or "1.0". Integer 1.
  • recipes must contain at least 1 element - empty arrays are rejected.
  • validation.status / validation.phase mismatch - both are fixed literals ("validated" / "ok"). Any other value fails.
Link copied