prepare.yml, restore.yml, validate.yml, and Ansible inventory
Three optional Ansible playbooks can live in a scenario directory. The runner discovers and invokes them automatically at the right point in the execution cycle.
Runs before the agent executes. Use it to introduce the failure condition the scenario is benchmarking.Before prepare.yml runs, the runner silently executes restore.yml with errors suppressed. This clears leftover state from any previous failed run so each execution starts from a known baseline: even when the prior run was interrupted mid-way.If prepare.yml itself fails, execution is aborted and the scenario is marked as failed.
---- name: Deploy broken nginx configuration hosts: all become: true tasks: - name: Ensure nginx is installed apt: name: nginx state: present update_cache: true - name: Write a config with a syntax error (missing semicolon after listen 80) copy: dest: /etc/nginx/sites-available/default content: | server { listen 80 root /var/www/html; index index.html; } - name: Attempt reload: this will fail, which is intentional systemd: name: nginx state: restarted ignore_errors: true
Runs after validation, during cleanup. Use it to reset the host to a clean baseline.Restore failures are non-fatal: the runner logs a warning and continues. Write your restore playbooks defensively with ignore_errors: true on steps that may fail on an already-clean host.
Runs after execution as part of the validation phase. Use it to verify that the agent’s actions actually worked: service status, file contents, port availability, process list.Declared in scenario.json as an ansible validator:
{ "label": "Nginx is healthy", "validator": "ansible", "ansiblePath": "validate.yml"}
A non-zero exit code fails the resolution gate and marks the scenario as failed.
---- name: Verify nginx is healthy hosts: all become: true tasks: - name: Config syntax is valid command: nginx -t - name: Service is active command: systemctl is-active nginx - name: Port 80 is responding uri: url: http://localhost:80 status_code: [200, 301, 302]
The runner needs an Ansible inventory to know which hosts to target and how to reach them. Place an inventory.ini file in the scenario directory: the runner detects it automatically and passes it to every ansible-playbook call for that scenario.Standard Ansible INI format:
The hostnames must match the logical names used in scenario.json so the runner can correlate them correctly.
If no inventory.ini is present, ansible-playbook runs without an explicit inventory. Your playbooks won’t be able to reach any hosts. Always include inventory.ini when your scenario has playbooks.
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"2501.ai","colors":{"primary":"#121212","light":"#FAFAFA","dark":"#121212"},"logo":{"light":"https://mintcdn.com/2501/gMl_w8qww9Zl47hO/logo/light.png?fit=max\u0026auto=format\u0026n=gMl_w8qww9Zl47hO\u0026q=85\u0026s=eeeb37b3ca386a00dde53b3e6235adce","dark":"https://mintcdn.com/2501/gMl_w8qww9Zl47hO/logo/dark.png?fit=max\u0026auto=format\u0026n=gMl_w8qww9Zl47hO\u0026q=85\u0026s=4d0ac2514d479eb43fe361193d12c495","href":"/0.7/getting-started/welcome"},"favicon":"https://mintcdn.com/2501/gMl_w8qww9Zl47hO/favicon.png?fit=max\u0026auto=format\u0026n=gMl_w8qww9Zl47hO\u0026q=85\u0026s=884be98d09b5672f470de49ac6430f22","appearance":{"default":"light"},"background":{"color":{"light":"#FAFAFA","dark":"#121212"}},"navbar":{"links":[{"href":"mailto:hello@2501.ai","label":"Contact"},{"href":"https://github.com/2501-ai","label":"Github"},{"href":"https://2501.ai/","label":"Website"}]},"footer":{"socials":{"website":"https://www.2501.ai/","github":"https://github.com/2501-ai","linkedin":"https://www.linkedin.com/company/99099126"}},"styling":{"latex":false},"navigation":{"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"2501","hasAudioNarration":false,"actualSubdomain":"2501","customDomains":["docs.2501.ai"],"gitSource":{"type":"github","owner":"2501-ai","repo":"2501","deployBranch":"main","contentDirectory":"apps/public-docs","isPrivate":true,"mountPath":"","label":""},"chroma":{"liveDeploymentHistoryId":"6ae99559e644b2af9be4bb4b","collectionId":"a64b271a-a494-467a-96af-8f22a7bf9363","schemaVersion":"v3","latestBuiltDeploymentHistoryId":"6ae99559e644b2af9be4bb4b"},"entitlements":{},"buildId":"6aebb9cd2f18591a5a52a439","clientVersion":"0.0.4067","searchFilterCounts":[{"language":"default","tag":"Reference","count":966},{"language":"default","tag":"API","count":498},{"language":"default","tag":"Configure","count":303},{"language":"default","tag":"Guides","count":195},{"language":"default","tag":"Docs","count":189},{"language":"default","tag":"Benchmark","count":175},{"language":"default","tag":"Deploy","count":125},{"language":"default","tag":"Agents","count":121},{"language":"default","tag":"Integration","count":119},{"language":"default","tag":"Concepts","count":111}]},"assistantConfig":{},"basePath":"","hasChatPermissions":false,"hasWebMcpPermissions":false,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"rbac-expansion","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"full-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"vite-origin","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-sso-scim","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-signup","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-dual-write","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-enabled","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"approve-review-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"sso-setup-deadline-banner","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-serve","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"googleFontsInlined":false},"customCss":[],"page":{"pagePath":"0.3.0/scenario-runner/playbooks","slug":"/0.3.0/scenario-runner/playbooks","pageMetadata":{"title":"Playbooks","description":"prepare.yml, restore.yml, validate.yml, and Ansible inventory","href":"/0.3.0/scenario-runner/playbooks"},"description":{"compiledSource":"\"use strict\";\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n p: \"p\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsx(_components.p, {\n children: \"prepare.yml, restore.yml, validate.yml, and Ansible inventory\"\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx,jsxs:_jsxs}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){const _components={code:`code`,hr:`hr`,p:`p`,pre:`pre`,span:`span`,strong:`strong`,..._provideComponents(),...props.components},{CodeBlock,Heading,Warning}=_components;if(!CodeBlock)_missingMdxReference(`CodeBlock`,true);if(!Heading)_missingMdxReference(`Heading`,true);if(!Warning)_missingMdxReference(`Warning`,true);return _jsxs(_Fragment,{children:[_jsx(_components.p,{children:`Three optional Ansible playbooks can live in a scenario directory. The runner discovers and invokes them automatically at the right point in the execution cycle.`}),`\n`,_jsx(_components.hr,{}),`\n`,_jsx(Heading,{level:`2`,id:`execution-flow`,children:`Execution Flow`}),`\n`,_jsx(CodeBlock,{numberOfLines:`41`,language:`text`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`text`,children:_jsxs(_components.code,{language:`text`,numberOfLines:`41`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`2501-runner run -s \u003cscenario>`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` │`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` ▼`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`┌───────────────┐`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`│ Pre-flight │ verify DB, gateway/engine, ansible availability`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`└───────┬───────┘`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` │`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` ▼`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`┌───────────────┐`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`│ Provision │ resolve host + agent from DB, flush agent memory`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`└───────┬───────┘`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` │`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` ├─── restore.yml ──► silent pre-clean (errors suppressed)`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` │`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` ▼`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`┌───────────────┐`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`│ Prepare │ run prepare.yml → introduce the failure condition`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`└───────┬───────┘ (abort if fails)`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` │`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` ▼`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`┌───────────────┐`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`│ Execute │ dispatch task via gateway / task / ticket`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`│ │ agent investigates and acts on the target host`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`└───────┬───────┘`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` │`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` ▼`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`┌───────────────┐`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`│ Validate │ evaluate pattern_match / task_count / status rules`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`│ │ run validate.yml → check actual machine state`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`└───────┬───────┘`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` │`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` ▼`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`┌───────────────┐`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`│ Restore │ run restore.yml → reset host to clean baseline`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`└───────┬───────┘ (non-fatal if fails)`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` │`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` ▼`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`┌───────────────┐`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`│ Report │ print summary, persist ScenarioReport to DB`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`└───────────────┘`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{})})]})})}),`\n`,_jsx(_components.hr,{}),`\n`,_jsx(Heading,{level:`2`,id:`prepare-yml`,children:`prepare.yml`}),`\n`,_jsxs(_components.p,{children:[`Runs `,_jsx(_components.strong,{children:`before`}),` the agent executes. Use it to introduce the failure condition the scenario is benchmarking.`]}),`\n`,_jsxs(_components.p,{children:[_jsxs(_components.strong,{children:[`Before `,_jsx(_components.code,{children:`prepare.yml`}),` runs`]}),`, the runner silently executes `,_jsx(_components.code,{children:`restore.yml`}),` with errors suppressed. This clears leftover state from any previous failed run so each execution starts from a known baseline: even when the prior run was interrupted mid-way.`]}),`\n`,_jsxs(_components.p,{children:[`If `,_jsx(_components.code,{children:`prepare.yml`}),` itself fails, execution is aborted and the scenario is marked as failed.`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`26`,language:`yaml`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`yaml`,children:_jsxs(_components.code,{language:`yaml`,numberOfLines:`26`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:`---`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`- `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`name`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`Deploy broken nginx configuration`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` hosts`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`all`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` become`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:`true`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` tasks`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`name`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`Ensure nginx is installed`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` apt`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` name`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`nginx`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` state`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`present`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` update_cache`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:`true`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`name`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`Write a config with a syntax error (missing semicolon after listen 80)`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` copy`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` dest`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`/etc/nginx/sites-available/default`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` content`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`|`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` server {`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` listen 80`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` root /var/www/html;`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` index index.html;`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` }`})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`name`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`Attempt reload`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`this will fail, which is intentional`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` systemd`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` name`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`nginx`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` state`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`restarted`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` ignore_errors`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:`true`})]}),`\n`]})})}),`\n`,_jsx(_components.hr,{}),`\n`,_jsx(Heading,{level:`2`,id:`restore-yml`,children:`restore.yml`}),`\n`,_jsxs(_components.p,{children:[`Runs `,_jsx(_components.strong,{children:`after`}),` validation, during cleanup. Use it to reset the host to a clean baseline.`]}),`\n`,_jsxs(_components.p,{children:[`Restore failures are `,_jsx(_components.strong,{children:`non-fatal`}),`: the runner logs a warning and continues. Write your restore playbooks defensively with `,_jsx(_components.code,{children:`ignore_errors: true`}),` on steps that may fail on an already-clean host.`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`17`,language:`yaml`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`yaml`,children:_jsxs(_components.code,{language:`yaml`,numberOfLines:`17`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:`---`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`- `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`name`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`Reset nginx to clean state`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` hosts`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`all`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` become`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:`true`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` tasks`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`name`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`Stop nginx`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` systemd`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` name`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`nginx`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` state`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`stopped`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` enabled`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:`false`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` ignore_errors`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:`true`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`name`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`Remove injected config`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` file`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` path`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`/etc/nginx/sites-available/default`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` state`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`absent`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` ignore_errors`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:`true`})]}),`\n`]})})}),`\n`,_jsx(_components.hr,{}),`\n`,_jsx(Heading,{level:`2`,id:`validate-yml`,children:`validate.yml`}),`\n`,_jsxs(_components.p,{children:[`Runs `,_jsx(_components.strong,{children:`after`}),` execution as part of the validation phase. Use it to verify that the agent’s actions actually worked: service status, file contents, port availability, process list.`]}),`\n`,_jsxs(_components.p,{children:[`Declared in `,_jsx(_components.code,{children:`scenario.json`}),` as an `,_jsx(_components.code,{children:`ansible`}),` validator:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`5`,language:`json`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`json`,children:_jsxs(_components.code,{language:`json`,numberOfLines:`5`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`{`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"label\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"Nginx is healthy\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"validator\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"ansible\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"ansiblePath\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"validate.yml\"`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`}`})}),`\n`]})})}),`\n`,_jsx(_components.p,{children:`A non-zero exit code fails the resolution gate and marks the scenario as failed.`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`15`,language:`yaml`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`yaml`,children:_jsxs(_components.code,{language:`yaml`,numberOfLines:`15`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:`---`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`- `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`name`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`Verify nginx is healthy`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` hosts`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`all`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` become`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:`true`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` tasks`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`name`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`Config syntax is valid`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` command`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`nginx -t`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`name`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`Service is active`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` command`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`systemctl is-active nginx`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`name`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`Port 80 is responding`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` uri`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` url`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`http://localhost:80`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` status_code`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: [`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`200`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`301`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`302`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`]`})]}),`\n`]})})}),`\n`,_jsx(_components.hr,{}),`\n`,_jsx(Heading,{level:`2`,id:`using-environment-variables`,children:`Using Environment Variables`}),`\n`,_jsxs(_components.p,{children:[`Variables from `,_jsx(_components.code,{children:`/etc/2501/env.runner`}),` are available in all playbooks via `,_jsx(_components.code,{children:`lookup('env', ...)`}),`:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`4`,language:`yaml`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`yaml`,children:_jsxs(_components.code,{language:`yaml`,numberOfLines:`4`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`- `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`name`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`Clone a private repository`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` git`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` repo`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"https://{{ lookup('env', 'GH_TOKEN') }}@github.com/your-org/fixtures.git\"`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` dest`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`/opt/fixtures`})]}),`\n`]})})}),`\n`,_jsx(_components.hr,{}),`\n`,_jsx(Heading,{level:`2`,id:`inventory-ini`,children:`inventory.ini`}),`\n`,_jsxs(_components.p,{children:[`The runner needs an Ansible inventory to know which hosts to target and how to reach them. Place an `,_jsx(_components.code,{children:`inventory.ini`}),` file in the scenario directory: the runner detects it automatically and passes it to every `,_jsx(_components.code,{children:`ansible-playbook`}),` call for that scenario.`]}),`\n`,_jsx(_components.p,{children:`Standard Ansible INI format:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`8`,language:`ini`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`ini`,children:_jsxs(_components.code,{language:`ini`,numberOfLines:`8`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#D4D4D4`},children:`[web]`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`sandbox-web-01 `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`ansible_host`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`=10.0.1.10 `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`ansible_user`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`=ubuntu `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`ansible_port`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`=22`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#D4D4D4`},children:`[db]`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`sandbox-db-01 `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`ansible_host`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`=10.0.1.20 `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`ansible_user`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`=ubuntu `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`ansible_port`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`=22`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#D4D4D4`},children:`[all:vars]`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`ansible_ssh_private_key_file`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`=/etc/2501/keys/sandbox.pem`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`The hostnames must match the logical names used in `,_jsx(_components.code,{children:`scenario.json`}),` so the runner can correlate them correctly.`]}),`\n`,_jsx(Warning,{children:_jsxs(_components.p,{children:[`If no `,_jsx(_components.code,{children:`inventory.ini`}),` is present, `,_jsx(_components.code,{children:`ansible-playbook`}),` runs without an explicit inventory. Your playbooks won’t be able to reach any hosts. Always include `,_jsx(_components.code,{children:`inventory.ini`}),` when your scenario has playbooks.`]})})]})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent};function _missingMdxReference(id,component){throw new Error(`Expected `+(component?`component`:`object`)+\" `\"+id+\"` to be defined: you likely forgot to import, pass, or provide it.\")}","frontmatter":{},"scope":{"config":{},"pageMetadata":{"title":"Playbooks","description":"prepare.yml, restore.yml, validate.yml, and Ansible inventory","href":"/0.3.0/scenario-runner/playbooks"}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[{"title":"Execution Flow","slug":"execution-flow","depth":2,"children":[]},{"title":"prepare.yml","slug":"prepare-yml","depth":2,"children":[]},{"title":"restore.yml","slug":"restore-yml","depth":2,"children":[]},{"title":"validate.yml","slug":"validate-yml","depth":2,"children":[]},{"title":"Using Environment Variables","slug":"using-environment-variables","depth":2,"children":[]},{"title":"inventory.ini","slug":"inventory-ini","depth":2,"children":[]}],"codeExamples":{}},"jsLinks":[],"dynamicCss":".\\[all\\:vars\\] {\n all: vars\n}","subdomain":"2501","siteName":"2501.ai","title":"Playbooks - 2501.ai","navMaps":{"firstHrefInVersion":{"0.19":{"href":"/0.19/getting-started/welcome","matchLevel":4},"0.18":{"href":"/0.18/getting-started/welcome","matchLevel":4},"0.17":{"href":"/0.17/getting-started/welcome","matchLevel":4},"0.16":{"href":"/0.16/getting-started/welcome","matchLevel":4},"0.15":{"href":"/0.15/getting-started/welcome","matchLevel":4},"0.14":{"href":"/0.14/getting-started/welcome","matchLevel":4},"0.13":{"href":"/0.13/getting-started/welcome","matchLevel":4},"0.12":{"href":"/0.12/getting-started/welcome","matchLevel":4},"0.11":{"href":"/0.11/getting-started/welcome","matchLevel":4},"0.10":{"href":"/0.10/getting-started/welcome","matchLevel":4},"0.9":{"href":"/0.9/getting-started/welcome","matchLevel":4},"0.8":{"href":"/0.8/getting-started/welcome","matchLevel":4},"0.7":{"href":"/0.7/getting-started/welcome","matchLevel":4},"0.4":{"href":"/0.4/scenario-runner/playbooks","matchLevel":1},"0.3.0":{"href":"/0.3.0/scenario-runner/playbooks","matchLevel":0},"0.2.6":{"href":"/0.2.6/command-center","matchLevel":4}},"firstHrefInLanguage":{}},"lastModified":"2026-03-25T01:56:15.987Z","originalFileLocation":"0.3.0/scenario-runner/playbooks.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"light\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"prepare.yml, restore.yml, validate.yml, and Ansible inventory\">\u003cmeta data-mint-head name=\"application-name\" content=\"2501.ai\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/2501/ur2ley-wQyHAsGwc/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/mintlify-assets/_mintlify/favicons/2501/ur2ley-wQyHAsGwc/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/2501/ur2ley-wQyHAsGwc/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/2501/ur2ley-wQyHAsGwc/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/2501/ur2ley-wQyHAsGwc/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/2501/ur2ley-wQyHAsGwc/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/2501/ur2ley-wQyHAsGwc/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/2501/ur2ley-wQyHAsGwc/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/2501/ur2ley-wQyHAsGwc/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"Playbooks - 2501.ai\">\u003cmeta data-mint-head property=\"og:description\" content=\"prepare.yml, restore.yml, validate.yml, and Ansible inventory\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"2501.ai\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://docs.2501.ai/0.3.0/scenario-runner/playbooks\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://2501.mintlify.app/_mintlify/api/og/v2?division=Scenario+Runner\u0026amp;title=Playbooks\u0026amp;description=prepare.yml%2C+restore.yml%2C+validate.yml%2C+and+Ansible+inventory\u0026amp;theme=f33d4ade6ddd98c4a45fdcd4\u0026amp;signature=73fb0a5d3ccda4cac23a92860db48de216e7842ed877b5c6ae3f1019d6a4bcde\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"Playbooks - 2501.ai\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"prepare.yml, restore.yml, validate.yml, and Ansible inventory\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://2501.mintlify.app/_mintlify/api/og/v2?division=Scenario+Runner\u0026amp;title=Playbooks\u0026amp;description=prepare.yml%2C+restore.yml%2C+validate.yml%2C+and+Ansible+inventory\u0026amp;theme=f33d4ade6ddd98c4a45fdcd4\u0026amp;signature=73fb0a5d3ccda4cac23a92860db48de216e7842ed877b5c6ae3f1019d6a4bcde\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/mintlify-assets/_mintlify/favicons/2501/ur2ley-wQyHAsGwc/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"2501.ai\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#121212\">\u003clink data-mint-head rel=\"canonical\" href=\"https://docs.2501.ai/0.3.0/scenario-runner/playbooks\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/0.3.0/scenario-runner/playbooks.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://docs.2501.ai/#organization\",\"name\":\"2501.ai\",\"url\":\"https://docs.2501.ai\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/2501/gMl_w8qww9Zl47hO/logo/light.png?fit=max\u0026auto=format\u0026n=gMl_w8qww9Zl47hO\u0026q=85\u0026s=eeeb37b3ca386a00dde53b3e6235adce\"}},{\"@type\":\"WebSite\",\"@id\":\"https://docs.2501.ai#website\",\"name\":\"2501.ai\",\"url\":\"https://docs.2501.ai\",\"publisher\":{\"@id\":\"https://docs.2501.ai/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://docs.2501.ai/0.3.0/scenario-runner/playbooks#webpage\",\"url\":\"https://docs.2501.ai/0.3.0/scenario-runner/playbooks\",\"name\":\"Playbooks\",\"description\":\"prepare.yml, restore.yml, validate.yml, and Ansible inventory\",\"dateModified\":\"2026-03-25T01:56:15.987Z\",\"isPartOf\":{\"@id\":\"https://docs.2501.ai#website\"},\"breadcrumb\":{\"@id\":\"https://docs.2501.ai/0.3.0/scenario-runner/playbooks#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://docs.2501.ai/0.3.0/scenario-runner/playbooks#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Scenario Runner\",\"item\":\"https://docs.2501.ai/0.3.0/scenario-runner/overview\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Playbooks\",\"item\":\"https://docs.2501.ai/0.3.0/scenario-runner/playbooks\"}]},{\"@type\":[\"Article\",\"TechArticle\"],\"@id\":\"https://docs.2501.ai/0.3.0/scenario-runner/playbooks#article\",\"headline\":\"Playbooks\",\"name\":\"Playbooks\",\"description\":\"prepare.yml, restore.yml, validate.yml, and Ansible inventory\",\"url\":\"https://docs.2501.ai/0.3.0/scenario-runner/playbooks\",\"mainEntityOfPage\":{\"@id\":\"https://docs.2501.ai/0.3.0/scenario-runner/playbooks#webpage\"},\"dateModified\":\"2026-03-25T01:56:15.987Z\",\"publisher\":{\"@id\":\"https://docs.2501.ai/#organization\"},\"isPartOf\":{\"@id\":\"https://docs.2501.ai#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"2501.ai\",\"creator\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","siteName":"2501.ai","nav":{"global":null,"versions":[{"version":"0.19","pages":[{"title":"0.19","href":"/0.19/getting-started/welcome"}]},{"version":"0.18","pages":[{"title":"0.18","href":"/0.18/getting-started/welcome"}]},{"version":"0.17","pages":[{"title":"0.17","href":"/0.17/getting-started/welcome"}]},{"version":"0.16","pages":[{"title":"0.16","href":"/0.16/getting-started/welcome"}]},{"version":"0.15","pages":[{"title":"0.15","href":"/0.15/getting-started/welcome"}]},{"version":"0.14","pages":[{"title":"0.14","href":"/0.14/getting-started/welcome"}]},{"version":"0.13","pages":[{"title":"0.13","href":"/0.13/getting-started/welcome"}]},{"version":"0.12","pages":[{"title":"0.12","href":"/0.12/getting-started/welcome"}]},{"version":"0.11","pages":[{"title":"0.11","href":"/0.11/getting-started/welcome"}]},{"version":"0.10","pages":[{"title":"0.10","href":"/0.10/getting-started/welcome"}]},{"version":"0.9","pages":[{"title":"0.9","href":"/0.9/getting-started/welcome"}]},{"version":"0.8","pages":[{"title":"0.8","href":"/0.8/getting-started/welcome"}]},{"version":"0.7","pages":[{"title":"0.7","href":"/0.7/getting-started/welcome"}]},{"version":"0.4","pages":[{"title":"0.4","href":"/0.4/scenario-runner/playbooks"}]},{"version":"0.3.0","tabs":[{"tab":"Documentation","groups":[{"group":"Getting Started","pages":[{"title":"Command Center","href":"/0.3.0/command-center"}]},{"group":"Deployment","pages":[{"title":"Overview","href":"/0.3.0/deployment/overview"},{"title":"Init Command","href":"/0.3.0/deployment/init-command"},{"title":"Configuration","href":"/0.3.0/deployment/configuration"},{"title":"Docker Swarm","href":"/0.3.0/deployment/docker-swarm"},{"title":"LLM Providers","href":"/0.3.0/deployment/llm-providers"},{"title":"Users \u0026 Organizations","href":"/0.3.0/deployment/users-organizations"},{"title":"Troubleshooting","href":"/0.3.0/deployment/troubleshooting"}]},{"group":"Core Concepts","pages":[{"title":"Agents","href":"/0.3.0/core-concepts/agents"},{"title":"Hosts","href":"/0.3.0/core-concepts/hosts"},{"title":"Organizations","href":"/0.3.0/core-concepts/organizations"},{"title":"Tasks","href":"/0.3.0/core-concepts/tasks"},{"title":"Jobs","href":"/0.3.0/core-concepts/jobs"},{"title":"Gateways","href":"/0.3.0/core-concepts/gateways"}]},{"group":"Configure","pages":[{"title":"Specialties","href":"/0.3.0/configure/specialties"},{"title":"Engines","href":"/0.3.0/configure/engines"},{"title":"Operational Rules","href":"/0.3.0/configure/operational-rules"},{"title":"Blacklist","href":"/0.3.0/configure/blacklist"},{"title":"Credentials","href":"/0.3.0/configure/credentials"},{"title":"Plugins","href":"/0.3.0/configure/plugins"},{"title":"Users","href":"/0.3.0/configure/users"},{"title":"Prompting","href":"/0.3.0/configure/prompting"},{"title":"Import Hosts via CSV","href":"/0.3.0/configure/import-hosts-csv"}]},{"group":"Scenario Runner","pages":[{"title":"Overview","href":"/0.3.0/scenario-runner/overview"},{"title":"Scenario Structure","href":"/0.3.0/scenario-runner/scenario-structure"},{"title":"Hosts \u0026 Agents","href":"/0.3.0/scenario-runner/hosts-and-agents"},{"title":"Validation","description":"Validation rules, validators, scoring model, and fail-fast guards","href":"/0.3.0/scenario-runner/validation"},{"title":"Playbooks","href":"/0.3.0/scenario-runner/playbooks"},{"title":"Examples","description":"Complete scenario examples: disk full, nginx broken config, Kubernetes crashloop","href":"/0.3.0/scenario-runner/examples"},{"title":"Run Scenarios","href":"/0.3.0/scenario-runner/run-command"}]},{"group":"CLI","pages":[{"title":"Installation","href":"/0.3.0/cli/installation"},{"title":"Authentication","href":"/0.3.0/cli/authentication"},{"title":"Commands","href":"/0.3.0/cli/commands"}]}]}]},{"version":"0.2.6","pages":[{"title":"0.2.6","href":"/0.2.6/command-center"}]}]},"basePath":"","title":"Playbooks - 2501.ai","buildId":"dpl_9VVk5y1P8k1ATeJguVngy9Q3cmbD","deploymentId":"dpl_9VVk5y1P8k1ATeJguVngy9Q3cmbD","dynamics":[],"chunks":[]}