# dhairyabhanderi/saviynt-scenario-runner architecture

> Architecture diagram of the GitHub repository dhairyabhanderi/saviynt-scenario-runner, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-08-14). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/dhairyabhanderi/saviynt-scenario-runner
- Repository: https://github.com/dhairyabhanderi/saviynt-scenario-runner

## Overview

#### Purpose and entry points
Saviynt Scenario Runner is a Python automation system for declarative Saviynt Enterprise Identity Cloud (EIC) scenarios. It compiles intent-oriented YAML or explicit step YAML, executes EIC REST calls safely, waits for asynchronous provisioning, validates outcomes, and persists reports/audit data.

CLI entry points are `saviynt_scenario_runner/__main__.py` and `saviynt_scenario_runner/cli.py`. The optional localhost-only FastAPI interface starts from `saviynt_scenario_runner/web/app.py`.

#### Scenario authoring and compilation
Two input boundaries converge on an executable scenario IR: Flow YAML is parsed, expanded through lifecycle presets, and compiled into classic steps; classic YAML is loaded directly. The operation registry is the authoritative mapping between authoring operations, required fields, entity bindings, defaults, and inserted verification/wait behavior.

Core paths: `saviynt_scenario_runner/planning/flow_spec.py`, `saviynt_scenario_runner/planning/compiler.py`, `saviynt_scenario_runner/planning/field_spec.py`, `saviynt_scenario_runner/template/loader.py`, `saviynt_scenario_runner/models/scenario.py`.

#### Execution engine and state
The runner executes compiled steps in order, resolves runtime context/interpolation and dates, evaluates conditions, captures outputs, and runs cleanup even after failure. It supports dry runs and live execution, stop-on-failure, expected-error semantics, polling, retry controls, and reconciliation for ambiguous non-idempotent submits.

Core paths: `saviynt_scenario_runner/execution/runner.py`, `saviynt_scenario_runner/execution/context.py`, `saviynt_scenario_runner/execution/retry.py`, `saviynt_scenario_runner/execution/poller.py`, `saviynt_scenario_runner/execution/reconcile.py`.

#### Actions and Saviynt API boundary
Actions isolate scenario semantics from HTTP details. The action registry dispatches operations such as user lifecycle changes, access changes, requests/approvals, task checks, jobs, bulk uploads, assertions, and raw/generic API calls. The API client owns authentication, token refresh, endpoint construction, request building, response normalization, and error classification; this is the external-service boundary to Saviynt EIC REST APIs.

Core paths: `saviynt_scenario_runner/actions/registry.py`, `saviynt_scenario_runner/actions/base.py`, `saviynt_scenario_runner/actions/account_lifecycle.py`, `saviynt_scenario_runner/api/client.py`, `saviynt_scenario_runner/api/endpoints.py`.

#### Validation, outcomes, and durable observability
Validation actions apply assertion operators to API results and captured context. Execution produces step-level results and an outcome summary for console and JSON reporting. Audit, report, run-history, and saved-scenario persistence are local filesystem artifacts under the user home directory; secrets are sourced from environment/.env or optional OS keychain, while named connection metadata is stored separately from passwords.

Core paths: `saviynt_scenario_runner/validation/assertions.py`, `saviynt_scenario_runner/reporting/outcome.py`, `saviynt_scenario_runner/reporting/json_report.py`, `saviynt_scenario_runner/observability.py`, `saviynt_scenario_runner/secrets.py`.

#### Local web control plane and assistant
The FastAPI UI is a local control plane for YAML editing, scenario/run persistence, dry/live execution, live step streaming, and tenant connection management. Its security boundary is loopback binding plus Host allow-list and Origin checks; it has no standalone authentication. The assistant subsystem is a substantial adjacent orchestration layer: it ingests/searches knowledge, compiles context, manages scoped memory, plans tool use, and exposes assistant routes. Its memory adapter can use Everos Cloud, making that an optional external service.

Core paths: `saviynt_scenario_runner/web/app.py`, `saviynt_scenario_runner/web/run_manager.py`, `saviynt_scenario_runner/web/connections.py`, `saviynt_scenario_runner/web/assistant/orchestrator.py`, `saviynt_scenario_runner/web/assistant/context_compiler.py`, `saviynt_scenario_runner/web/assistant/memory/everos_cloud.py`.

Main entry points: [`saviynt_scenario_runner/execution/runner.py`](https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/execution/runner.py) (Scenario runner), [`saviynt_scenario_runner/web/app.py`](https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/web/app.py) (Local FastAPI control plane), [`saviynt_scenario_runner/planning/compiler.py`](https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/planning/compiler.py) (Scenario compiler), [`saviynt_scenario_runner/models/scenario.py`](https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/models/scenario.py) (Executable scenario IR)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_authoring["Scenario Authoring"]
  node_flow_spec["Flow YAML parser<br/>planner<br/>[flow_spec.py]"]
  node_compiler["Scenario compiler<br/>planner<br/>[compiler.py]"]
  node_field_spec["Operation registry<br/>operation schema<br/>[field_spec.py]"]
  node_classic_loader["Classic YAML loader<br/>template loader<br/>[loader.py]"]
  node_scenario_ir["Executable scenario IR<br/>scenario model<br/>[scenario.py]"]
end

subgraph group_execution["Execution"]
  node_runner["Scenario runner<br/>execution engine<br/>[runner.py]"]
  node_runtime_context["Runtime context<br/>execution state<br/>[context.py]"]
  node_resilience["Polling &amp; reconciliation<br/>reliability controls<br/>[reconcile.py]"]
  node_action_registry["Action registry<br/>action dispatch<br/>[registry.py]"]
  node_api_client{{"Saviynt API client<br/>HTTP boundary<br/>[client.py]"}}
  node_validation["Assertions<br/>validation engine<br/>[assertions.py]"]
  node_outcomes["Outcomes &amp; JSON reports<br/>reporting<br/>[outcome.py]"]
end

subgraph group_web["Local Web &amp; Assistant"]
  node_web_app["Local FastAPI control plane<br/>FastAPI app<br/>[app.py]"]
  node_run_manager["Web run manager<br/>web orchestration<br/>[run_manager.py]"]
  node_assistant["Assistant orchestrator<br/>assistant subsystem<br/>[orchestrator.py]"]
end

subgraph group_external["External Services"]
  node_saviynt_eic{{"Saviynt EIC REST APIs<br/>external service"}}
  node_everos{{"Everos Cloud<br/>optional memory service"}}
end

node_cli["CLI entry points<br/>Python CLI<br/>[cli.py]"]
node_local_storage[("Local audit &amp; run storage<br/>filesystem persistence<br/>[observability.py]")]
node_secrets["Secrets &amp; connections<br/>credential management<br/>[secrets.py]"]

node_cli -->|"loads flow YAML"| node_flow_spec
node_cli -->|"loads classic YAML"| node_classic_loader
node_flow_spec -->|"expanded flow"| node_compiler
node_field_spec -->|"operation definitions"| node_compiler
node_compiler -->|"compiled steps"| node_scenario_ir
node_classic_loader -->|"explicit steps"| node_scenario_ir
node_scenario_ir -->|"execution plan"| node_runner
node_runner -->|"resolves and captures state"| node_runtime_context
node_runner -->|"waits, retries, reconciles"| node_resilience
node_runner -->|"dispatches steps"| node_action_registry
node_action_registry -->|"performs API actions"| node_api_client
node_api_client -->|"REST calls"| node_saviynt_eic
node_runner -->|"runs assertions"| node_validation
node_runtime_context -->|"captured values"| node_validation
node_runner -->|"step results"| node_outcomes
node_outcomes -->|"reports and audit"| node_local_storage
node_secrets -.->|"credentials"| node_api_client
node_web_app -->|"run requests and streaming"| node_run_manager
node_run_manager -->|"dry/live execution"| node_runner
node_web_app -->|"assistant routes"| node_assistant
node_assistant -.->|"optional memory adapter"| node_everos
node_web_app -->|"scenarios, runs, connections"| node_local_storage

click node_cli "https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/cli.py"
click node_flow_spec "https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/planning/flow_spec.py"
click node_compiler "https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/planning/compiler.py"
click node_field_spec "https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/planning/field_spec.py"
click node_classic_loader "https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/template/loader.py"
click node_scenario_ir "https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/models/scenario.py"
click node_runner "https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/execution/runner.py"
click node_runtime_context "https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/execution/context.py"
click node_resilience "https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/execution/reconcile.py"
click node_action_registry "https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/actions/registry.py"
click node_api_client "https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/api/client.py"
click node_validation "https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/validation/assertions.py"
click node_outcomes "https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/reporting/outcome.py"
click node_local_storage "https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/observability.py"
click node_secrets "https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/secrets.py"
click node_web_app "https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/web/app.py"
click node_run_manager "https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/web/run_manager.py"
click node_assistant "https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/web/assistant/orchestrator.py"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_flow_spec,node_compiler,node_field_spec,node_classic_loader,node_scenario_ir toneBlue
class node_runner,node_runtime_context,node_resilience,node_action_registry,node_api_client,node_validation,node_outcomes toneAmber
class node_web_app,node_run_manager,node_assistant toneMint
class node_saviynt_eic,node_everos toneRose
class node_cli,node_local_storage,node_secrets toneNeutral
```

## Components

### Scenario Authoring

- [Flow YAML parser](https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/planning/flow_spec.py): planner · Expands intent-oriented lifecycle flows. · `saviynt_scenario_runner/planning/flow_spec.py`
- [Scenario compiler](https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/planning/compiler.py): planner · Compiles flow operations into executable classic steps. · `saviynt_scenario_runner/planning/compiler.py`
- [Operation registry](https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/planning/field_spec.py): operation schema · Defines operation fields, bindings, defaults, waits, and verification. · `saviynt_scenario_runner/planning/field_spec.py`
- [Classic YAML loader](https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/template/loader.py): template loader · Loads explicit step scenarios directly. · `saviynt_scenario_runner/template/loader.py`
- [Executable scenario IR](https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/models/scenario.py): scenario model · `saviynt_scenario_runner/models/scenario.py`

### Execution

- [Scenario runner](https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/execution/runner.py): execution engine · Runs ordered steps, cleanup, dry/live modes, and failure policy. · `saviynt_scenario_runner/execution/runner.py`
- [Runtime context](https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/execution/context.py): execution state · Resolves interpolation, dates, conditions, and captured outputs. · `saviynt_scenario_runner/execution/context.py`
- [Polling & reconciliation](https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/execution/reconcile.py): reliability controls · Handles retries, asynchronous waits, and ambiguous submissions. · `saviynt_scenario_runner/execution/reconcile.py`
- [Action registry](https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/actions/registry.py): action dispatch · Maps scenario operations to lifecycle, access, request, job, assertion, and raw API actions. · `saviynt_scenario_runner/actions/registry.py`
- [Saviynt API client](https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/api/client.py): HTTP boundary · Owns authentication, token refresh, endpoints, requests, and error classification. · `saviynt_scenario_runner/api/client.py`
- [Assertions](https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/validation/assertions.py): validation engine · Evaluates assertion operators against API results and runtime context. · `saviynt_scenario_runner/validation/assertions.py`
- [Outcomes & JSON reports](https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/reporting/outcome.py): reporting · Builds step results and console/JSON summaries. · `saviynt_scenario_runner/reporting/outcome.py`

### Local Web & Assistant

- [Local FastAPI control plane](https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/web/app.py): FastAPI app · Loopback-only UI with Host and Origin checks. · `saviynt_scenario_runner/web/app.py`
- [Web run manager](https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/web/run_manager.py): web orchestration · Coordinates YAML runs and live step streaming. · `saviynt_scenario_runner/web/run_manager.py`
- [Assistant orchestrator](https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/web/assistant/orchestrator.py): assistant subsystem · Plans tool use with compiled knowledge context and scoped memory. · `saviynt_scenario_runner/web/assistant/orchestrator.py`

### External Services

- **Saviynt EIC REST APIs**: external service
- **Everos Cloud**: optional memory service

### Other components

- [CLI entry points](https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/cli.py): Python CLI · Starts scenario runs and local web mode. · `saviynt_scenario_runner/cli.py`
- [Local audit & run storage](https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/observability.py): filesystem persistence · Persists audit data, reports, run history, and saved scenarios under user home. · `saviynt_scenario_runner/observability.py`
- [Secrets & connections](https://github.com/dhairyabhanderi/saviynt-scenario-runner/blob/main/saviynt_scenario_runner/secrets.py): credential management · Reads environment, .env, or keychain secrets separately from connection metadata. · `saviynt_scenario_runner/secrets.py`

## Connections

- CLI entry points → Flow YAML parser: loads flow YAML
- CLI entry points → Classic YAML loader: loads classic YAML
- Flow YAML parser → Scenario compiler: expanded flow
- Operation registry → Scenario compiler: operation definitions
- Scenario compiler → Executable scenario IR: compiled steps
- Classic YAML loader → Executable scenario IR: explicit steps
- Executable scenario IR → Scenario runner: execution plan
- Scenario runner → Runtime context: resolves and captures state
- Scenario runner → Polling & reconciliation: waits, retries, reconciles
- Scenario runner → Action registry: dispatches steps
- Action registry → Saviynt API client: performs API actions
- Saviynt API client → Saviynt EIC REST APIs: REST calls
- Scenario runner → Assertions: runs assertions
- Runtime context → Assertions: captured values
- Scenario runner → Outcomes & JSON reports: step results
- Outcomes & JSON reports → Local audit & run storage: reports and audit
- Secrets & connections → Saviynt API client: credentials
- Local FastAPI control plane → Web run manager: run requests and streaming
- Web run manager → Scenario runner: dry/live execution
- Local FastAPI control plane → Assistant orchestrator: assistant routes
- Assistant orchestrator → Everos Cloud: optional memory adapter
- Local FastAPI control plane → Local audit & run storage: scenarios, runs, connections
