diff --git a/README.md b/README.md
index 5ce8353..6b5afbb 100644
--- a/README.md
+++ b/README.md
@@ -1,121 +1,131 @@
-# SimRun
+
+
+
-SimRun is an **Attack Simulation Platform (ASP)** for detection testing. It **detonates**
-attack simulations and verifies that the security alerts you expect fire in your SIEM
-(currently only Elastic Security is supported).
+SimRun
-It ships as a single Go binary serving a REST API + WebSocket interface backed by
-PostgreSQL, with an embedded SvelteKit frontend.
+
+ An Attack Simulation Platform for detection engineering.
+ Detonate attacks, verify the alerts fire, and measure exactly which detections you're testing โ across multiple clouds.
+
-## Getting Started
+
+
+
+
+
+
-### Prerequisites
+---
-- [mise](https://mise.jdx.dev/) โ manages the Go 1.25 and Node 22 toolchains (or install them yourself)
-- PostgreSQL
+## Why SimRun
-### Build
+Detection rules rot silently. A field gets renamed, a log source drifts, an index mapping changes โ and the alert you were counting on simply stops firing. You don't find out until the breach.
-```bash
-mise build # builds the SvelteKit frontend and the simrun binary into dist/simrun
-```
+SimRun closes that gap. It runs real attack techniques against your environment, confirms the detections you expect actually fire in your SIEM, and tracks **which of your rules are tested and which are blind spots**.
-### Run
+It's not a script you wire into CI and forget. It's a platform:
-simrun requires a PostgreSQL database; schema migrations run automatically on startup.
+- **๐ฏ Coverage you can see.** SimRun joins your live Elastic detection rules against your scenarios and their latest pass/fail result, then reports a coverage percentage. You learn what you *aren't* testing โ not just whether one test passed. โ [Rule Coverage](#rule-coverage)
+- **โ๏ธ Multiple clouds, multiple accounts.** First-class connectors for AWS, GCP, Azure, and Kubernetes, each backed by managed, encrypted secret groups and selectable per scenario.
+- **๐งช Three ways to exercise a detection.** **Detonate** a real attack, **inject** a crafted log to confirm a rule is wired up without touching infrastructure, or **collect** the raw logs an attack produced to build the next rule.
+- **๐ฆ A pack ecosystem.** Simulations ship as versioned, shareable bundles with a clean Go SDK. Use the first-party packs, wrap [Stratus Red Team](https://github.com/DataDog/stratus-red-team), or author your own. โ [Ecosystem](docs/ecosystem.md)
+- **๐ฅ๏ธ Built to operate.** Web UI, REST API, and WebSocket interface; PostgreSQL persistence; scheduled runs; optional multi-user OAuth. It all ships as a single Go binary with the SvelteKit UI embedded.
-```bash
-export SR_DATABASE_URL="postgres://user:pass@localhost:5432/simrun?sslmode=disable"
-./dist/simrun
-```
+> SimRun is **primarily focused on Elastic Security** โ that's where coverage analysis, injection, and log collection are richest. Datadog security signals are supported as a matching backend.
-The UI and API are then served on http://localhost:8080.
+## How it works
-> Authentication is optional. Without `SR_GOOGLE_CLIENT_ID`/`SR_GOOGLE_CLIENT_SECRET`,
-> login is disabled and the app runs unauthenticated
+An **Assessment** is a saved set of **scenarios**. Running it creates a **Run**, which executes every scenario in parallel. Each scenario triggers some activity and then asserts that an expected alert appears in your SIEM before a timeout.
-## Configuration
+```mermaid
+flowchart LR
+ A[Assessment
scenarios] -->|run| B(Run)
+ B --> S1[Scenario 1]
+ B --> S2[Scenario 2]
+ B --> S3[Scenario N]
+ S1 --> D{Trigger}
+ D -->|detonate| E[Real attack
from SimRun pack]
+ D -->|inject| F[Crafted log
into Elasticsearch]
+ E --> M[Matcher polls SIEM
until alert fires or timeout]
+ F --> M
+ M --> R[(Results + Coverage
Postgres)]
+ E -.optional.-> C[Collector
gathers related logs]
+ C --> R
+```
-Deploy-time configuration is read from environment variables โ the only `SR_*` env
-surface. Everything else (connectors, secrets, packs, schedules, scenarios, app
-defaults) lives in the database and is managed through the web UI.
+Every detonation gets a UUID that SimRun reflects into the generated activity wherever possible (user-agent strings), so an alert maps unambiguously back to the exact attack that caused it.
-| Variable | Required | Default | Description |
-|---|---|---|---|
-| `SR_DATABASE_URL` | yes | โ | PostgreSQL connection string |
-| `SR_WEB_PORT` | no | `8080` | HTTP listen port |
-| `SR_DATA_DIR` | no | `~/.simrun` | Local data dir (encryption key, SSH logs) |
-| `SR_ENCRYPTION_KEY_FILE` | no | `$SR_DATA_DIR/encryption.key` | Key file for encrypting stored secrets |
-| `SR_DEBUG` | no | off | Verbose logging when set to a non-zero value |
-| `SR_WEB_URL` | no | โ | External base URL (used for OAuth redirects) |
-| `SR_GOOGLE_CLIENT_ID` / `SR_GOOGLE_CLIENT_SECRET` | no | โ | Google OAuth credentials (enables login) |
-| `SR_GOOGLE_ALLOWED_DOMAIN` | no | โ | Restrict OAuth login to a Google Workspace domain |
-| `SR_AUTH_SESSION_TTL_HOURS` | no | `168` | Session lifetime in hours |
+โ Full vocabulary in [Concepts](docs/concepts.md).
-### Run with Docker
+## A scenario, end to end
-```bash
-docker build -t simrun .
-docker run -p 8080:8080 \
- -e SR_DATABASE_URL="postgres://..." \
- -v simrun-data:/home/nonroot/.simrun \
- simrun
+Build scenarios visually in the assessment editor, or write the YAML directly โ the editor toggles between a forms-based **Builder** and raw **YAML**. This scenario detonates a pack simulation in AWS and asserts the matching Elastic Security rule fires:
+
+```yaml
+targets:
+ aws: prod-aws # an AWS connector you configured in the UI
+
+scenarios:
+ - name: S3 public access block disabled
+ detonate:
+ simrunDetonator:
+ pack: simrun-base-pack
+ simulation: aws.s3-disable-public-access-block
+ expectations:
+ - timeout: 5m
+ elasticSecurityAlert:
+ name: "S3 Public Access Block Disabled"
```
-The image bundles the `aws`, `gcloud`, and `az` CLIs used by detonators. Persist
-`SR_DATA_DIR` (the volume above) so the secret-encryption key survives restarts.
+Swap `detonate` for `inject` to test a rule without running an attack, or add a `collect` block to capture the raw logs the attack produced.
-## Architecture
+โ [Scenarios reference](docs/scenarios.md).
-A single Go binary handles:
-- Simulation detonation and orchestration
-- Alert matching and verification
-- Log collection from security platforms
-- Scenario parsing and execution
+## Quickstart (60 seconds)
-### Simulation Packs
+**Prerequisites:** [mise](https://mise.jdx.dev/) (manages Go 1.25 and Node 22), PostgreSQL.
-Simulations are distributed as external packs, installed and managed via the web UI:
+```bash
+# Build the frontend + binary โ dist/simrun
+mise run build
-- simrun-base-pack โ custom simulations (AWS, Azure, GCP)
-- simrun-stratus-pack โ [Stratus Red Team](https://github.com/DataDog/stratus-red-team) simulations
+# Point it at Postgres and run
+export SR_DATABASE_URL="postgres://user:pass@localhost:5432/simrun?sslmode=disable"
+./dist/simrun # serves UI + API on http://localhost:8080
+```
+
+Schema migrations run automatically on startup. Authentication is optional โ without Google OAuth credentials, SimRun runs unauthenticated.
+
+โ Then follow the [Walkthrough](docs/walkthrough.md) to run your first detection test.
+
+## Rule Coverage
-## Concepts
+The Coverage view (`/rules/coverage`) pulls every detection rule from your Elastic deployment and answers the question CI never could: **which of these rules does a SimRun scenario actually exercise, and did it pass last time?** Rules with no scenario are flagged as blind spots; the summary reports an overall covered-rules percentage.
-### Detonators
-A **detonator** describes how and where an attack technique is executed.
-* Simrun detonator โ runs a simulation pack (Terraform-based; packs can themselves
- execute locally or over SSH)
-* AWS CLI detonator โ runs AWS CLI commands
+## The pack ecosystem
-### Injectors
-An **injector** is an alternative to detonators: instead of executing the end-to-end
-attack it takes a generated log message and injects it directly into the SIEM. This
-covers cases where end-to-end simulation isn't feasible but you still want to confirm
-the detection is operational.
-* Elastic Injector
+Simulations are distributed as **packs** โ versioned bundles of Terraform modules, scenario definitions, and a manifest. Two first-party packs are maintained alongside SimRun:
-### Alert Matchers
-An **alert matcher** is a platform-specific integration that checks whether an expected
-alert was triggered.
-* Elastic Security alerts
-* Datadog security signals
+| Pack | What it is |
+|---|---|
+| [**simrun-pack**](https://github.com/confluentinc/simrun-pack) | The reference pack and a worked example of authoring simulations in Go (AWS, Kubernetes, Okta injections). |
+| [**simrun-stratus-adapter**](https://github.com/confluentinc/simrun-stratus-adapter) | Plug-and-play wrapper that exposes the entire [Stratus Red Team](https://github.com/DataDog/stratus-red-team) technique registry as a SimRun pack. |
-### Collectors
-A **collector** retrieves logs from security platforms after detonation for analysis and
-rule generation.
-* Elastic Collector โ collects related logs from Elasticsearch by execution ID or
- user-agent correlation
-### Detonation and Alert Correlation
-Each detonation is assigned a UUID, reflected in the detonation where possible and used
-to ensure the matched alert corresponds exactly to that detonation. If the detonator
-cannot reflect the UUID, the matcher can correlate using indicators the user provides
-(static indicators) or terraform output (dynamic indicators).
+โ [Ecosystem & authoring guide](docs/ecosystem.md).
-### Simulations
-A **simulation** is a reusable module describing how to perform a specific attack.
-Simulations are distributed as [packs](#simulation-packs) and installed via the web UI.
+## Documentation
+
+- [Getting Started](docs/getting-started.md) โ prerequisites, build, first run
+- [Concepts](docs/concepts.md) โ assessments, runs, detonators, matchers, collectors
+- [Walkthrough](docs/walkthrough.md) โ end-to-end tutorial
+- [Scenarios](docs/scenarios.md) โ YAML schema reference
+- [Connectors & Secrets](docs/connectors-and-secrets.md) โ SIEM and cloud integrations
+- [Packs](docs/packs.md) โ install and configure simulation packs
+- [Ecosystem](docs/ecosystem.md) โ the pack ecosystem and writing your own
+- [Configuration](docs/configuration.md) โ environment variables reference
+- [Deployment](docs/deployment.md) โ Docker, production notes, OAuth setup
## Development
@@ -127,6 +137,13 @@ go generate ./... # regenerate mocks (mockery)
mise run parser # regenerate parser from JSON schemas
```
+## Acknowledgments
+
+SimRun stands on excellent prior work in the detection-engineering community:
+
+- [**Threatest**](https://github.com/DataDog/threatest) by Datadog pioneered the detonate-and-verify model for detection testing and shaped how we think about correlating attacks to alerts.
+- [**Stratus Red Team**](https://github.com/DataDog/stratus-red-team), also by Datadog, provides the MITRE ATT&CKโmapped cloud attack techniques that SimRun exposes through [simrun-stratus-adapter](https://github.com/confluentinc/simrun-stratus-adapter).
+
## Contributing
Issues and pull requests are welcome.
diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 0000000..4629a29
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,29 @@
+# SimRun Documentation
+
+Learn how to set up, configure, and run detection tests against your SIEM.
+
+## Suggested Reading Order
+
+Start with **Getting Started** to install SimRun, then read **Concepts** to understand the vocabulary. Follow with the **Walkthrough** to execute your first test, then dive into the reference docs as needed.
+
+---
+
+## Documentation Index
+
+- **[Getting Started](getting-started.md)** โ Install SimRun and reach the dashboard.
+
+- **[Concepts](concepts.md)** โ Vocabulary and core components: assessments, runs, scenarios, detonators, matchers, and injectors.
+
+- **[Walkthrough](walkthrough.md)** โ Step-by-step guide to your first detection test with AWS and Elastic Security.
+
+- **[Scenarios YAML Reference](scenarios.md)** โ Complete reference for the YAML format that defines assessments and scenarios.
+
+- **[Connectors and Secrets](connectors-and-secrets.md)** โ Configure endpoints and store credentials for your SIEM and cloud platforms.
+
+- **[Packs](packs.md)** โ Install and manage external attack simulation bundles and tune their parameters.
+
+- **[Ecosystem](ecosystem.md)** โ The pack ecosystem, the maintained satellite packs, and how to write your own.
+
+- **[Configuration](configuration.md)** โ All deploy-time environment variables and operational defaults.
+
+- **[Deployment](deployment.md)** โ Run SimRun in production with Docker and optional Google OAuth.
diff --git a/docs/assets/simrun-icon-rounded.png b/docs/assets/simrun-icon-rounded.png
new file mode 100644
index 0000000..f8eddf6
Binary files /dev/null and b/docs/assets/simrun-icon-rounded.png differ
diff --git a/docs/assets/simrun-icon.png b/docs/assets/simrun-icon.png
new file mode 100644
index 0000000..e0a3472
Binary files /dev/null and b/docs/assets/simrun-icon.png differ
diff --git a/docs/concepts.md b/docs/concepts.md
new file mode 100644
index 0000000..b27767c
--- /dev/null
+++ b/docs/concepts.md
@@ -0,0 +1,66 @@
+# Concepts
+
+An **Assessment** defines scenarios. Running it creates a **Run**. The run **executes each scenario** (in parallel, like jobs), and each scenario checks its **expectations** via **matchers**.
+
+## Vocabulary
+
+**Assessment**
+: A saved collection of scenarios that describes what to detonate and what alerts to expect. Managed on the Assessments page (`/assessments`).
+
+**Run**
+: A single execution of an Assessment. Persists results to the database and is viewable on the Runs page (`/runs`).
+
+**Scenario**
+: One unit of work inside an Assessment: a detonation or injection step, plus one or more expectations. Scenarios in a run execute in parallel.
+
+**Expectation**
+: A declared assertion that a specific alert or signal must appear in the target platform after detonation. Expectations are defined per-scenario in the YAML file.
+
+**Matcher**
+: The component that checks whether an expectation was satisfied by polling the target platform until the alert appears or the timeout expires.
+
+## Detonators
+
+Detonators execute the attack simulation.
+
+**SimRun detonator** โ runs a pack simulation using Terraform. The pack can execute locally (on the SimRun host) or over SSH on a remote target. This is the primary detonation method and requires a pack to be installed.
+
+## Injectors
+
+Injectors skip the attack execution and push a document directly into the SIEM.
+
+**Elastic Injector** โ writes a log document into Elasticsearch. Use this to confirm that a detection rule is operational without actually running an attack: if the matcher finds the expected alert after injection, the rule is wired up correctly.
+
+## Matchers
+
+Matchers verify that an expectation fired after detonation or injection.
+
+**Elastic Security alert matcher** โ polls Kibana for a Detection Engine alert whose `kibana.alert.rule.name` matches the expected rule name.
+
+## Collectors
+
+Collectors retrieve related logs after detonation for post-hoc analysis and rule development.
+
+**Elastic Collector** โ queries Elasticsearch for log events correlated to the detonation, either by the execution UUID (when it was reflected into the activity) or by a user-agent string. The collected logs are stored with the run result and can be used to understand what raw data a detection rule would have to match.
+
+## Correlation
+
+Every detonation is assigned a UUID (nanoid) at execution time. Where possible, SimRun reflects that UUID into the generated activity by injecting it into the user-agent string โ so that the resulting alert maps unambiguously to exactly one detonation event.
+
+When the UUID cannot be reflected into the activity (for example, in a managed AWS API call), SimRun uses **indicators** for correlation:
+
+- `static` โ a fixed string you provide (e.g. a known username or resource name) that will appear in the alert or log.
+- `terraformOutput` โ a value extracted dynamically from a Terraform output after the simulation completes (e.g. a generated resource ARN).
+
+## Packs, Connectors, Secrets
+
+**Packs** distribute simulations as versioned bundles. A pack contains Terraform modules, scenario definitions, and a manifest. Install packs from the UI and reference them by name in your scenario YAML. See [packs.md](packs.md) for installation and configuration.
+
+**Connectors** point SimRun at an external platform โ Elastic, AWS, GCP, Azure, Kubernetes, or SSH. Each connector stores the endpoint and non-secret configuration needed to reach that platform. Connectors are managed on the Connectors page (`/connectors`). See [connectors-and-secrets.md](connectors-and-secrets.md) for setup.
+
+**Secret groups** hold the credentials (API keys, passwords, certificates) that a connector uses. A connector links to at most one secret group. Secrets are managed on the Secrets page (`/secrets`) and are never returned in plaintext after saving.
+
+## See also
+
+- [walkthrough.md](walkthrough.md) โ run your first detection test end to end
+- [scenarios.md](scenarios.md) โ full YAML reference for scenario files
diff --git a/docs/configuration.md b/docs/configuration.md
new file mode 100644
index 0000000..7490850
--- /dev/null
+++ b/docs/configuration.md
@@ -0,0 +1,40 @@
+# Configuration
+
+Every deploy-time setting SimRun reads.
+
+## Overview
+
+Deploy-time configuration is environment-only. The `SR_*` environment variables below are the only settings SimRun reads at startup. Everything else โ connectors, secrets, packs, schedules, assessments, and app-level operational defaults โ lives in the database and is managed through the UI.
+
+## Environment variables
+
+| Variable | Required | Default | Description |
+|---|---|---|---|
+| `SR_DATABASE_URL` | yes | โ | PostgreSQL connection string |
+| `SR_WEB_PORT` | no | `8080` | HTTP listen port |
+| `SR_DATA_DIR` | no | `~/.simrun` | Local data dir (encryption key, SSH logs) |
+| `SR_ENCRYPTION_KEY_FILE` | no | `$SR_DATA_DIR/encryption.key` | Key file for encrypting stored secrets |
+| `SR_DEBUG` | no | off | Verbose logging when set to a non-zero/non-`false` value |
+| `SR_WEB_DEV` | no | off | Dev mode when set to `1` |
+| `SR_WEB_URL` | no | โ | External base URL (used for OAuth redirects) |
+| `SR_GOOGLE_CLIENT_ID` / `SR_GOOGLE_CLIENT_SECRET` | no | โ | Google OAuth credentials (enables login) |
+| `SR_GOOGLE_ALLOWED_DOMAIN` | no | โ | Restrict OAuth login to a Google Workspace domain |
+| `SR_AUTH_SESSION_TTL_HOURS` | no | `168` | Session lifetime in hours |
+
+## App config defaults
+
+Operational defaults that admins tune through the UI at `/config`. These are stored in the database (the `app_config` table) and take effect without a restart.
+
+Confirmed fields include:
+
+- **Parallelism** (default `5`) โ number of scenarios that run concurrently within a single run.
+- **Terraform version** โ pin the Terraform binary version used by pack detonations.
+- **Pack logs** โ toggle capture of Terraform output in run logs (enabled by default).
+- **SSH logging** โ toggle SSH session logging (disabled by default).
+- **Run log retention** โ automatically purge run logs after a configurable number of days (default 7 days, enabled by default).
+- **Run retention** โ automatically purge run records after a configurable number of days (default 30 days, disabled by default).
+
+## See also
+
+- [deployment.md](deployment.md) โ production deploy checklist, OAuth setup, Docker
+- [getting-started.md](getting-started.md) โ build SimRun and reach the dashboard for the first time
diff --git a/docs/connectors-and-secrets.md b/docs/connectors-and-secrets.md
new file mode 100644
index 0000000..c1cb656
--- /dev/null
+++ b/docs/connectors-and-secrets.md
@@ -0,0 +1,122 @@
+# Connectors and Secrets
+
+Point SimRun at your platforms and store the credentials securely.
+
+## Connectors vs secret groups
+
+A **connector** (`/connectors`) stores the endpoint and non-secret configuration needed to reach a target platform โ for example, a Kibana URL or an AWS role ARN. Connector records are stored in the database and are referenced by name in scenario targets and run defaults.
+
+A **secret group** (`/secrets`) holds the credentials (API keys, passwords, private keys) that a connector uses. A connector links to at most one secret group. Secrets are encrypted at rest using the key in `SR_DATA_DIR` (default `~/.simrun`). See [configuration.md](configuration.md) for how `SR_DATA_DIR` is set.
+
+The split keeps non-sensitive config โ URLs, region names, cluster identifiers โ visible in the UI while keeping credentials out of plain sight. Secret values are never returned in plaintext after saving.
+
+## SIEM connectors
+
+### Elastic
+
+The `elastic` connector type points SimRun at an Elastic Security deployment. It is the primary SIEM: the Elastic Security alert matcher polls Kibana for detection alerts, and the Elastic Injector writes documents into Elasticsearch.
+
+**Config fields (confirmed in `connector_handlers.go`):**
+
+| Field | Required | Description |
+|---|---|---|
+| `kibana_url` | Yes | Base URL of your Kibana instance (e.g. `https://kibana.example.com`). |
+| `cloud_id` | No | Elastic Cloud ID. Alternative to explicit URLs for Elastic Cloud deployments. |
+| `elasticsearch_url` | No | Explicit Elasticsearch URL when not derived from `cloud_id`. |
+| `export_enabled` | No | When `true`, run results are exported to Elasticsearch after completion. |
+| `export_datastream` | No | Data stream name for result export. |
+
+**Secret group:** Link a secret group that contains `SR_ELASTIC_API_KEY` (the Elasticsearch API key used for all Kibana and Elasticsearch calls).
+
+When no target overrides are specified, SimRun uses the first enabled Elastic connector as the active SIEM connection.
+
+
+## Cloud connectors
+
+Cloud connectors supply credentials to detonators that execute attack simulations in cloud environments. They are referenced from a scenario's `targets` block by connector name.
+
+### AWS
+
+The `aws` connector resolves credentials for the AWS CLI detonator and Terraform-based simulations that target AWS.
+
+**Config fields:**
+
+| Field | Description |
+|---|---|
+| `role_arn` | IAM role ARN to assume before running the simulation. When set, SimRun calls `sts:AssumeRole` and passes the resulting temporary credentials to the subprocess. |
+
+**Secret group:** Optionally store `SR_AWS_EXTERNAL_ID` (the external ID required when assuming the role) and any additional AWS credential env vars (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, etc.) for static-key auth.
+
+### GCP
+
+The `gcp` connector resolves credentials for Terraform simulations that target GCP.
+
+**Config fields:**
+
+| Field | Description |
+|---|---|
+| `auth_type` | Set to `workload_identity_federation` for WIF auth, or leave empty for legacy service account auth. |
+| `project_id` | GCP project ID, injected as `GOOGLE_CLOUD_PROJECT`. |
+| `project_number` | GCP project number (WIF only). |
+| `pool_id` | Workload Identity Pool ID (WIF only). |
+| `provider_id` | Workload Identity Provider ID (WIF only). |
+| `service_account_email` | Target service account to impersonate (WIF only). |
+| `credentials_file` | Path to a service account JSON file (legacy auth only). |
+
+**Secret group:** For legacy auth, store `SR_GCP_CREDENTIALS` (inline service account JSON).
+
+### Azure
+
+The `azure` connector resolves credentials for Terraform simulations that target Azure.
+
+**Config fields:**
+
+| Field | Description |
+|---|---|
+| `auth_type` | Set to `workload_identity_federation` for WIF auth, or leave empty for legacy service principal auth. |
+| `tenant_id` | Azure AD tenant ID. |
+| `subscription_id` | Azure subscription ID. |
+| `client_id` | Azure AD application (client) ID. |
+| `token_file` | OIDC token file path (WIF only; defaults to the EKS IRSA path). |
+
+**Secret group:** For legacy auth, store `ARM_CLIENT_SECRET` (the service principal client secret).
+
+## Other connectors
+
+### Kubernetes
+
+The `kubernetes` connector resolves a kubeconfig for simulations that run Kubernetes-native attack steps. The cloud provider (EKS, GKE, AKS) is auto-detected from the referenced cloud connector type.
+
+**Config fields (all required):**
+
+| Field | Description |
+|---|---|
+| `cluster_name` | Name of the target cluster. |
+| `region` | Cloud region where the cluster is deployed. |
+| `cloud_connector` | Name of the AWS, GCP, or Azure connector that provides cloud credentials for fetching the kubeconfig. |
+| `resource_group` | Azure resource group (AKS only). |
+| `project` | GCP project ID (GKE only; falls back to the linked GCP connector's `project_id`). |
+
+`cluster_name`, `region`, and `cloud_connector` are required. The Kubernetes connector does not have a dedicated secret group; it inherits credentials from the referenced cloud connector.
+
+### SSH
+
+The `ssh` connector is used by the SimRun detonator to execute Terraform simulations on a remote host over SSH.
+
+> โ ๏ธ **Not yet in the UI.** The SSH connector is hidden from the connector picker while its consumption path is finalised, so it can't be created from the Connectors page yet. SSH-based detonation isn't configurable through the UI in the meantime.
+
+**Config fields:**
+
+| Field | Required | Description |
+|---|---|---|
+| `host` | Yes | Hostname or IP address of the remote target. |
+| `username` | Yes | SSH username. |
+| `port` | No | SSH port (default: 22). |
+
+**Secret group:** Store `SR_SSH_KEY` (the PEM-encoded private key). The key is written to a temporary file and passed to the SSH client at runtime.
+
+## See also
+
+- [walkthrough.md](walkthrough.md) โ end-to-end example including connector setup
+- [packs.md](packs.md) โ install and configure simulation packs
+- [scenarios.md](scenarios.md) โ reference connector names in scenario targets
diff --git a/docs/deployment.md b/docs/deployment.md
new file mode 100644
index 0000000..bae9041
--- /dev/null
+++ b/docs/deployment.md
@@ -0,0 +1,48 @@
+# Deployment
+
+Run SimRun in production with Docker and optional auth.
+
+## Docker
+
+Pull the image or build it from the repository root:
+
+```bash
+docker pull ghcr.io/ibm/simrun:latest
+```
+
+Run the container, mounting a volume so state persists across restarts:
+
+```bash
+docker run -p 8080:8080 \
+ -e SR_DATABASE_URL="postgres://..." \
+ -v simrun-data:/home/nonroot/.simrun \
+ ghcr.io/ibm/simrun
+```
+
+The image bundles `aws`, `gcloud`, and `az` CLIs โ the tools used by detonators when executing cloud attack simulations.
+
+The volume mounted at `/home/nonroot/.simrun` is the default `SR_DATA_DIR`. It stores the secret-encryption key. If the key is lost, stored connector credentials become unreadable.
+
+## Authentication (Google OAuth)
+
+By default, SimRun runs without authentication. To enable login:
+
+| Variable | Description |
+|---|---|
+| `SR_GOOGLE_CLIENT_ID` / `SR_GOOGLE_CLIENT_SECRET` | Google OAuth credentials โ setting both enables login |
+| `SR_WEB_URL` | External base URL used to construct the OAuth redirect URI (e.g. `https://simrun.example.com`) |
+| `SR_GOOGLE_ALLOWED_DOMAIN` | Restrict login to a single Google Workspace domain (e.g. `example.com`) |
+| `SR_AUTH_SESSION_TTL_HOURS` | Session lifetime in hours (default `168`, i.e. 7 days) |
+
+See [configuration.md](configuration.md) for the full list of environment variables.
+
+## Data persistence
+
+The encryption key written to `SR_DATA_DIR` protects all secrets stored in the database (connector credentials, secret group values). If the data directory is not persisted โ for example, because a container restarts without a volume โ the key is regenerated and previously stored secrets become unreadable.
+
+Always mount `SR_DATA_DIR` to durable storage in production.
+
+## See also
+
+- [configuration.md](configuration.md) โ all environment variables and app config defaults
+- [getting-started.md](getting-started.md) โ build SimRun and reach the dashboard for the first time
diff --git a/docs/ecosystem.md b/docs/ecosystem.md
new file mode 100644
index 0000000..53fe22d
--- /dev/null
+++ b/docs/ecosystem.md
@@ -0,0 +1,175 @@
+# Ecosystem & Writing Packs
+
+SimRun's simulations live outside the core binary, in **packs**. This keeps the platform stable while the catalogue of attack techniques grows independently โ maintained by us, by the community, or by you for your own environment.
+
+This page covers the maintained satellite projects and how to author a pack of your own. For installing and configuring packs from the UI, see [packs.md](packs.md).
+
+## The satellite projects
+
+### simrun-pack โ the reference pack
+
+[**confluentinc/simrun-pack**](https://github.com/confluentinc/simrun-pack) is the first-party `simrun-base-pack` and doubles as the canonical example of how a pack is written. It ships real simulations across AWS and Kubernetes, plus an Okta log injection, organised by MITRE tactic:
+
+```
+simulations/
+ aws/
+ credential-access/credential-scanner-tools/ main.tf + simulation.go
+ discovery/s3-list-objects/ main.tf + simulation.go
+ k8s/
+ credential-access/eks-web-identity-token-theft/
+ privilege-escalation/create-clusterrolebinding/
+ shared/ reusable Go helpers
+injections/
+ okta/api-token-create/ injection.go + injection.tpl
+main.go registers everything
+```
+
+Each simulation is a directory with a Terraform module (`main.tf`) that stands up the infrastructure and a Go file (`simulation.go`) that registers the simulation and runs the detonation. Read it as a template for the patterns below.
+
+### simrun-stratus-adapter โ plug-and-play Stratus Red Team
+
+[**confluentinc/simrun-stratus-adapter**](https://github.com/confluentinc/simrun-stratus-adapter) exposes the entire [Stratus Red Team](https://github.com/DataDog/stratus-red-team) attack-technique registry as a single SimRun pack. Rather than re-implementing techniques, it adapts each one โ preserving its MITRE ATT&CK mapping โ into the SimRun pack format. Its `main()` is essentially:
+
+```go
+func main() {
+ pack.SetPackInfo("stratus", Version, "3.0.0")
+
+ for _, technique := range stratus.GetRegistry().ListAttackTechniques() {
+ pack.Register(adapter.AdaptTechnique(technique))
+ }
+
+ pack.Run()
+}
+```
+
+Install it like any other pack to get Stratus's cloud attack coverage in SimRun with no per-technique work.
+
+## Writing your own pack
+
+A pack is a small Go program built against the [`github.com/IBM/simrun/pack`](https://github.com/IBM/simrun/tree/main/pack) SDK. At a high level you:
+
+1. Register one or more simulations (and any log-injection templates).
+2. Declare the pack's name, version, and the minimum SimRun version it needs.
+3. Declare any pack-level parameters.
+4. Call `pack.Run()`.
+
+### The entrypoint
+
+`main.go` wires the pack together. Importing each simulation package for its side effect (`_ "..."`) triggers the `init()` that registers it:
+
+```go
+package main
+
+import (
+ "github.com/IBM/simrun/pack"
+
+ _ "github.com/your-org/your-pack/simulations/aws/discovery/s3-list-objects"
+ // ...more simulations
+)
+
+// Version is set via ldflags at build time.
+var Version = "dev"
+
+func main() {
+ pack.SetPackInfo("your-pack", Version, "0.4.0") // name, version, min SimRun version
+
+ pack.RegisterPackParams(
+ pack.PackParam{
+ Name: "resource_prefix",
+ Type: pack.PackParamTypeString,
+ Description: "Prefix applied to every resource the pack creates.",
+ Default: "simrun",
+ },
+ )
+
+ pack.Run()
+}
+```
+
+Pack-level parameters appear on the Packs page once installed and are passed to every simulation's Terraform. The SDK always provides the built-in parameters (`default_tags`, `aws_region`, `gcp_region`, `azure_location`) โ declare only the extras you need. See [packs.md](packs.md#pack-parameters) for precedence rules.
+
+### A simulation
+
+Each simulation embeds its Terraform module and registers itself in `init()`:
+
+```go
+package simulations
+
+import (
+ "context"
+ _ "embed"
+
+ "github.com/IBM/simrun/pack"
+ packaws "github.com/IBM/simrun/pack/aws"
+ "github.com/aws/aws-sdk-go-v2/aws"
+ "github.com/aws/aws-sdk-go-v2/service/s3"
+)
+
+//go:embed main.tf
+var terraform string
+
+func init() {
+ pack.Register(pack.Simulation{
+ ID: "s3-list-objects",
+ Name: "S3 Bucket Object Listing",
+ Description: "Lists objects in an S3 bucket to simulate cloud storage discovery.",
+ MITRE: pack.MITREMapping{Tactics: []string{"TA0007"}, Techniques: []string{"T1619"}},
+ Scope: "aws",
+ Terraform: terraform,
+ Detonate: Detonate,
+ })
+}
+
+// Detonate runs the attack after Terraform has applied the warm-up infrastructure.
+func Detonate(ctx context.Context, input pack.DetonateInput) (*pack.Result, error) {
+ log := pack.Logger(input)
+
+ cfg, err := packaws.AWSConfig(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ bucketName := input.TerraformOutputs["bucket_name"]
+
+ s3Client := s3.NewFromConfig(cfg)
+ if _, err := s3Client.ListObjectsV2(ctx, &s3.ListObjectsV2Input{
+ Bucket: aws.String(bucketName),
+ }); err != nil {
+ return pack.ErrorResult(pack.ErrCodeInternalError, "failed to list objects: "+err.Error()), nil
+ }
+
+ return pack.SuccessResult(map[string]any{"bucket_name": bucketName}), nil
+}
+```
+
+The flow at run time:
+
+1. SimRun applies the simulation's `main.tf` โ the **warm-up** that creates the infrastructure the attack needs.
+2. Terraform outputs are handed to `Detonate` via `input.TerraformOutputs`.
+3. `Detonate` performs the attack and returns a `Result`. Indicators returned in a `SuccessResult` are surfaced for log correlation; SimRun then tears the infrastructure back down.
+
+### The SDK surface
+
+| Function | Purpose |
+|---|---|
+| `pack.SetPackInfo(name, version, minSimrun)` | Identify the pack and the minimum SimRun version it requires. |
+| `pack.RegisterPackParams(...PackParam)` | Declare pack-level parameters beyond the built-ins. |
+| `pack.Register(Simulation)` | Register a simulation (call from the package's `init()`). |
+| `pack.RegisterTemplate(Template)` | Register a log-injection template (for `inject` scenarios). |
+| `pack.Run()` | Hand control to the SDK โ must be the last call in `main()`. |
+| `pack.SuccessResult(indicators)` / `pack.ErrorResult(code, msg)` | Build the `Result` a `Detonate` returns. |
+| `pack.Logger(input)` | Structured logger whose output is captured in the run logs. |
+
+Cloud credential helpers live in `pack/aws`, `pack/gcp`, and `pack/azure`; SSH execution helpers in `pack/ssh`. The credentials come from the connector named in the scenario's `targets` block.
+
+### Building and distributing
+
+Packs are compiled binaries. Both reference repos use [GoReleaser](https://goreleaser.com/) driven from CI to cut versioned releases, injecting `Version` via `ldflags`. To install a published pack, point the Packs page at its source.
+
+While developing, you don't need to publish at all: `go build` your pack and install the binary directly through the Packs page's **Upload** tab. That tightens the author โ install โ test loop to seconds and lets you run packs that never leave your environment. See [packs.md](packs.md#installing-a-pack) for both methods.
+
+## See also
+
+- [packs.md](packs.md) โ installing and configuring packs from the UI
+- [scenarios.md](scenarios.md) โ referencing pack simulations and templates in scenario YAML
+- [concepts.md](concepts.md) โ where packs sit in the overall model
diff --git a/docs/getting-started.md b/docs/getting-started.md
new file mode 100644
index 0000000..be995cb
--- /dev/null
+++ b/docs/getting-started.md
@@ -0,0 +1,39 @@
+# Getting Started
+
+Install SimRun and reach the dashboard.
+
+## Prerequisites
+
+- **[mise](https://mise.jdx.dev/)** โ manages Go 1.25 and Node 22 automatically. Alternatively, install Go 1.25 and Node 22 yourself.
+- **PostgreSQL** โ a running instance accessible from the host where SimRun will run.
+
+## Build
+
+Clone the repository, then run:
+
+```bash
+mise run build
+```
+
+This builds the SvelteKit frontend and compiles the `simrun` binary, placing it at `dist/simrun`.
+
+## Run
+
+Database migrations run automatically on startup. Set the database URL and start the server:
+
+```bash
+export SR_DATABASE_URL="postgres://user:pass@localhost:5432/simrun?sslmode=disable"
+./dist/simrun
+```
+
+The UI and API are served on http://localhost:8080.
+
+## Authentication is optional
+
+Without `SR_GOOGLE_CLIENT_ID` and `SR_GOOGLE_CLIENT_SECRET` set, login is disabled and the app runs unauthenticated. See [deployment.md](deployment.md) for OAuth setup.
+
+## Next steps
+
+- [concepts.md](concepts.md) โ understand scenarios, detonators, matchers, and collectors
+- [walkthrough.md](walkthrough.md) โ run your first detection test end to end
+- [configuration.md](configuration.md) โ configure connectors, app defaults, and environment variables
diff --git a/docs/packs.md b/docs/packs.md
new file mode 100644
index 0000000..a064826
--- /dev/null
+++ b/docs/packs.md
@@ -0,0 +1,76 @@
+# Packs
+
+Install simulations and tune their parameters.
+
+## What a pack is
+
+A **pack** is an external, versioned bundle of attack simulations. Each pack ships Terraform modules, scenario definitions, and a manifest that describes the simulations it contains and the parameters it accepts.
+
+Packs are installed and managed from the **Packs page** (`/packs`). Once a pack is installed, its simulations are available for use in scenario YAML files via the `simrunDetonator.pack` and `simrunDetonator.simulation` fields.
+
+## Shipped packs
+
+Two first-party packs are available:
+
+| Pack | Contents |
+|---|---|
+| `simrun-base-pack` | Custom simulations targeting AWS, Azure, and GCP. |
+| `simrun-stratus-pack` | Wraps [Stratus Red Team](https://github.com/DataDog/stratus-red-team) attack techniques. |
+
+## Installing a pack
+
+A pack is a compiled binary. There are two ways to install one from the **Packs** page (`/packs`), shown as **Remote** and **Upload** tabs in the install dialog.
+
+### Remote โ pull a published pack
+
+Use this for shipped or published packs.
+
+1. Open the **Packs** page (`/packs`) and start a new install.
+2. Choose **Remote**, then enter the pack name, its source (the release location), and optionally a version.
+3. Click **Install**. SimRun fetches the pack, validates its manifest, and stores it in the database.
+
+To move a remote pack to a newer version later, use the **Update** action on the same page.
+
+### Upload โ install a local build
+
+Use this to install a pack binary you built yourself โ ideal for **rapid development and testing of simulations**, or when publishing a pack isn't appropriate for your environment.
+
+1. Build the pack binary locally (e.g. `go build`, or `mise run build` in the pack repo).
+2. On the **Packs** page, start a new install and choose **Upload**.
+3. Enter the pack name and select the compiled binary, then install. SimRun stores the binary, runs it to read its manifest, and lists its simulations โ exactly as for a remote pack.
+
+After installation โ by either method โ the pack appears in the list with its available simulations and declared parameters.
+
+## Pack parameters
+
+Parameters let you tune pack-wide settings โ cloud regions, tag values, project identifiers โ without editing individual scenario files.
+
+### Built-in parameters
+
+Every pack automatically includes these built-in parameters (defined in the SimRun SDK):
+
+| Parameter | Description |
+|---|---|
+| `default_tags` | Map of tags applied to every resource created by the pack (e.g. `{"env": "security-test"}`). |
+| `aws_region` | AWS region used as the default for all simulations in the pack. |
+| `gcp_region` | GCP region used as the default for all simulations in the pack. |
+| `azure_location` | Azure location used as the default for all simulations in the pack. |
+
+### Custom parameters
+
+Pack authors declare additional parameters in the pack's `main()` function using `pack.RegisterPackParams(...pack.PackParam)`. These appear alongside the built-ins in the pack's manifest `params_schema` and are available for configuration on the Packs page once the pack is installed.
+
+## Parameter precedence
+
+When a simulation runs, Terraform variable values are resolved in this order (last write wins):
+
+1. **Terraform variable default** โ the `default` value declared inside the module's `variable` block.
+2. **Pack-level value** โ set via the Packs page; applies to every simulation in the pack.
+3. **Per-simulation scenario value** โ the `params` map in the scenario YAML for a specific simulation; overrides the pack-level value for that run only.
+
+Map and array parameter values are JSON-encoded before being passed to Terraform as `TF_VAR_`.
+
+## See also
+
+- [walkthrough.md](walkthrough.md) โ run your first detection test end to end
+- [scenarios.md](scenarios.md) โ reference pack simulations in scenario YAML
diff --git a/docs/scenarios.md b/docs/scenarios.md
new file mode 100644
index 0000000..e8f50ee
--- /dev/null
+++ b/docs/scenarios.md
@@ -0,0 +1,208 @@
+# Scenarios YAML reference
+
+The YAML shape behind every assessment.
+
+> You don't have to write this by hand. The assessment editor has a visual **Builder** mode โ add scenarios, detonators, and expectations with forms โ and a **YAML** mode you can toggle to at any time.
+
+---
+
+## Top-level structure
+
+A scenario file has three top-level keys. Only `scenarios` is required.
+
+| Field | Type | Required | Description |
+|---|---|---|---|
+| `targets` | object | Yes | Connector names for each cloud/infrastructure target used by all scenarios in this file. |
+| `targets.aws` | string | No | Name of the AWS connector to use for cloud credentials. |
+| `targets.gcp` | string | No | Name of the GCP connector to use for cloud credentials. |
+| `targets.azure` | string | No | Name of the Azure connector to use for cloud credentials. |
+| `targets.kubernetes` | string | No | Name of the Kubernetes connector to use for cluster access. |
+| `targets.ssh` | string | No | Name of the SSH connector to use for remote command detonation. _(The SSH connector is not yet configurable in the UI โ see [connectors-and-secrets.md](connectors-and-secrets.md#ssh).)_ |
+| `scenarios` | array | **Yes** | List of scenario objects (see below). |
+
+---
+
+## A scenario
+
+Each item in `scenarios` describes one unit of work: how to trigger activity and what alerts to expect.
+
+| Field | Type | Required | Description |
+|---|---|---|---|
+| `name` | string | **Yes** | Display name for this scenario. |
+| `expectations` | array | **Yes** | One or more alert expectations (see [Expectations](#expectations)). |
+| `enabled` | boolean | No | Whether to run this scenario. Defaults to `true`. Set to `false` to skip without deleting. |
+| `indicators` | object | No | Values extracted after detonation and used for log correlation. |
+| `indicators.terraformOutput` | string[] | No | Terraform output keys to extract (e.g. `attacker_vm_public_ip`). |
+| `indicators.static` | string[] | No | Fixed strings that will appear in generated activity (e.g. a known username). |
+| `detonate` | object | No | How to execute the attack. Mutually exclusive with `inject`. |
+| `inject` | object | No | How to push a document directly into the SIEM instead of running an attack. Mutually exclusive with `detonate`. |
+| `collect` | object | No | How to retrieve related logs after detonation for post-hoc analysis. |
+
+---
+
+## Detonators
+
+A `detonate` block must contain exactly one detonator.
+
+
+### simrunDetonator
+
+Runs a pack simulation using Terraform. The pack must be installed before the run.
+
+| Field | Type | Required | Description |
+|---|---|---|---|
+| `pack` | string | **Yes** | Name of the installed pack containing the simulation. |
+| `simulation` | string | **Yes** | Simulation ID within the pack (e.g. `aws.exfil.s3`). |
+| `params` | object | No | Key-value parameters passed to the simulation. Merged with pack-level defaults; per-scenario values take precedence. Map and array values are JSON-encoded. |
+
+```yaml
+scenarios:
+ - name: s3 exfiltration
+ detonate:
+ simrunDetonator:
+ pack: attack-pack
+ simulation: aws.s3-disable-public-access-block
+ params:
+ aws_region: us-east-1
+ bucket_name: my-test-bucket
+ expectations:
+ - timeout: 5m
+ elasticSecurityAlert:
+ name: "S3 Public Access Block Disabled"
+ severity: high
+```
+
+---
+
+## Injector
+
+An `inject` block must contain `elasticInjector`. Use injection to verify a detection rule is wired up without running a real attack: SimRun writes the document and then polls for the expected alert.
+
+### elasticInjector
+
+| Field | Type | Required | Description |
+|---|---|---|---|
+| `documents` | array | **Yes** | One or more documents to inject into Elasticsearch. |
+| `documents[].index` | string | **Yes** | Elasticsearch index to write into. |
+| `documents[].file` | string | See note | Path to a JSON document file. Supports `{{variable_name}}` placeholder substitution. Required unless `template` is used. |
+| `documents[].template` | string | See note | Pack template ID (e.g. `okta.add-group-member`). Required unless `file` is used. |
+| `documents[].pack` | string | See note | Pack providing the template. Required when `template` is set. |
+| `documents[].vars` | object | No | String-to-string map of variables to substitute in the document using `{{variable_name}}` syntax. |
+
+Each document must supply both `template` + `pack`.
+
+```yaml
+scenarios:
+ - name: Okta API key created without network zone restriction
+ inject:
+ elasticInjector:
+ documents:
+ - index: "logs-okta.system-default"
+ template: okta.api-token-create
+ pack: base-dev
+ expectations:
+ - elasticSecurityAlert:
+ name: "Okta API key created/updated without network zone restriction"
+ timeout: 10m
+```
+
+---
+
+## Collector
+
+A `collect` block must contain `elasticCollector`. Collectors run after detonation and store related logs with the run result.
+
+### elasticCollector
+
+| Field | Type | Required | Description |
+|---|---|---|---|
+| `index` | string | **Yes** | Elasticsearch index to search for logs. |
+| `additionalFields` | object | No | Extra fields to filter by. Values can be static strings or template expressions referencing Terraform outputs, e.g. `{{ indicators.terraformOutput.attacker_vm_public_ip }}`. |
+
+```yaml
+scenarios:
+ - name: with collector
+ detonate:
+ simrunDetonator:
+ pack: attack-pack
+ simulation: aws.s3-disable-public-access-block
+ collect:
+ elasticCollector:
+ index: "logs-test"
+ additionalFields:
+ source.ip: "{{ indicators.terraformOutput.attacker_vm_public_ip }}"
+ expectations:
+ - timeout: 1m
+ elasticSecurityAlert:
+ name: "Test signal"
+```
+
+---
+
+## Expectations
+
+Every scenario must declare at least one expectation. Each expectation specifies a `timeout` and exactly one matcher.
+
+| Field | Type | Required | Description |
+|---|---|---|---|
+| `timeout` | string | No | Maximum time to wait for the alert. Written as a Go duration (e.g. `5m`, `30s`, `2m30s`). Defaults to `5m`. |
+| `elasticSecurityAlert` | object | See note | Match an Elastic Security Detection alert. |
+| `datadogSecuritySignal` | object | See note | Match a Datadog security signal. |
+
+### elasticSecurityAlert
+
+Polls Kibana until a Detection Engine alert appears whose `kibana.alert.rule.name.keyword` matches `name`.
+
+| Field | Type | Required | Description |
+|---|---|---|---|
+| `name` | string | **Yes** | Exact rule name to match (matched against `kibana.alert.rule.name.keyword`). |
+| `severity` | string | No | Alert severity to match. One of: `low`, `medium`, `high`, `critical`. |
+
+### datadogSecuritySignal
+
+Polls Datadog Security Signals until a signal with a matching name appears.
+
+| Field | Type | Required | Description |
+|---|---|---|---|
+| `name` | string | **Yes** | Exact signal name to match. |
+| `severity` | string | No | Signal severity to match. |
+
+---
+
+## Full example
+
+```yaml
+targets:
+ aws: "aws-prod"
+ azure: "azure-prod"
+
+scenarios:
+ - name: Exfiltrate an AMI by Sharing It
+ detonate:
+ simrunDetonator:
+ pack: stratus-dev
+ simulation: aws.ec2-share-ami
+ expectations:
+ - elasticSecurityAlert:
+ name: AWS EC2 AMI Shared with Another Account
+ timeout: 20m
+ - name: Delete CloudTrail Trail
+ detonate:
+ simrunDetonator:
+ pack: stratus-dev
+ simulation: aws.cloudtrail-delete
+ indicators:
+ terraformOutput:
+ - cloudtrail_trail_name
+ expectations:
+ - elasticSecurityAlert:
+ name: "AWS CloudTrail Log Deleted"
+ timeout: 15m
+```
+
+---
+
+## See also
+
+- [concepts.md](concepts.md) โ vocabulary, detonators, matchers, and collectors explained
+- [connectors-and-secrets.md](connectors-and-secrets.md) โ set up the connectors referenced in `targets`
diff --git a/docs/walkthrough.md b/docs/walkthrough.md
new file mode 100644
index 0000000..d7cafa8
--- /dev/null
+++ b/docs/walkthrough.md
@@ -0,0 +1,113 @@
+# Walkthrough: Your First Detection Test
+
+From a fresh SimRun to your first matched detection.
+
+## Before you start
+
+- SimRun is running and reachable. See [getting-started.md](getting-started.md) if you haven't set it up yet.
+- You're familiar with the vocabulary โ assessments, runs, scenarios, expectations, matchers. See [concepts.md](concepts.md) for a quick overview.
+
+**Goal:** detonate a real pack simulation in AWS and confirm that the expected Elastic Security alert fires.
+
+You'll need:
+- A running Elastic Security deployment with Kibana access and an API key.
+- An AWS account and credentials (access key or role ARN) that SimRun can use to run the simulation.
+
+---
+
+## Step 1 โ Open the dashboard
+
+Navigate to http://localhost:8080. The Dashboard gives an at-a-glance view of recent runs and scenario pass/fail rates.
+
+---
+
+## Step 2 โ Add connectors and secrets
+
+SimRun needs to know where your SIEM is and how to reach AWS. Both are configured as connectors backed by secret groups.
+
+### Add the Elastic connector
+
+1. Go to **Connectors** (`/connectors`).
+2. Click **Add connector**, choose type `elastic`.
+3. Enter your `kibana_url` (e.g. `https://kibana.example.com`).
+4. Under **Secret group**, create a new group and add `SR_ELASTIC_API_KEY` with your Elasticsearch API key.
+5. Save. SimRun will use this connector as the default SIEM for all runs.
+
+### Add the AWS connector
+
+1. Still on **Connectors**, click **Add connector**, choose type `aws`.
+2. If you're using role assumption, enter the `role_arn`.
+3. (if not using a role) Under **Secret group**, create a group and add `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`.
+
+See [connectors-and-secrets.md](connectors-and-secrets.md) for the full field reference.
+
+---
+
+## Step 3 โ Install a pack
+
+A pack bundles the Terraform modules and scenario definitions for a set of simulations.
+
+1. Go to **Packs** (`/packs`) and start a new install.
+2. Choose **Remote** and enter the pack name (e.g. `simrun-base-pack`) and its source. (The **Upload** tab installs a pack binary you built locally โ handy when developing your own simulations.)
+3. Click **Install**. SimRun fetches the pack, validates its manifest, and lists the available simulations.
+4. Optionally set pack-level parameters โ for example, set `aws_region` to `us-east-2` so every simulation in the pack targets that region by default.
+
+See [packs.md](packs.md) for both install methods and parameter details.
+
+---
+
+## Step 4 โ Create an assessment
+
+An assessment is a saved definition of scenarios. You'll create one with a single scenario that detonates a pack simulation and expects an Elastic Security alert.
+
+1. Go to **Assessments** (`/assessments`) and click **New assessment**.
+2. Give it a name, then define the scenario. The editor opens in **Builder** mode, where you add detonators and expectations with forms โ or switch to **YAML** mode to write or paste it directly. Either way, here's the YAML this scenario produces:
+
+```yaml
+targets:
+ aws: my-aws-connector # the connector name from Step 2
+
+scenarios:
+ - name: S3 public access block disabled
+ detonate:
+ simrunDetonator:
+ pack: simrun-base-pack
+ simulation: aws.s3-disable-public-access-block
+ expectations:
+ - elasticSecurityAlert:
+ name: "S3 Public Access Block Disabled"
+```
+
+Key points:
+- `targets.aws` must match the connector name you created in Step 2.
+- `simrunDetonator.pack` and `simrunDetonator.simulation` reference the pack you installed in Step 3.
+- `elasticSecurityAlert.name` is the exact Detection Engine rule name in Kibana that you expect to fire.
+
+See [scenarios.md](scenarios.md) for the full YAML reference.
+
+---
+
+## Step 5 โ Run it
+
+Click **Run** on the assessment. SimRun creates a new Run and begins executing scenarios in parallel.
+
+- Each scenario detonates the simulation, then polls Kibana for the expected alert.
+- The run page updates in real time as scenarios complete.
+
+---
+
+## Step 6 โ Wait for the results
+
+Each scenario shows one of:
+- **Matched** โ the expectation fired; the expected alert was found in Kibana within the timeout.
+- **Unmatched** โ the alert was not found before the timeout expired. Check whether the rule is enabled in Kibana and that the simulation actually ran.
+
+If you added a `collect` block to your scenario, the related Elasticsearch logs are shown alongside the results for post-hoc analysis.
+
+---
+
+## Next steps
+
+- **Rule Coverage** (`/rules/coverage`) โ view your Elastic detection rules mapped to MITRE ATT&CK techniques. Identify which techniques have coverage and which are gaps.
+- **Scheduling** โ run assessments on a recurring schedule directly from the Assessments page.
+- **Write your own scenarios** โ see [scenarios.md](scenarios.md) for the full YAML reference: multiple expectations, AWS CLI detonation, log injection, indicators, and collectors.
diff --git a/web/frontend/src/lib/assets/simrun-icon.png b/web/frontend/src/lib/assets/simrun-icon.png
new file mode 100644
index 0000000..e0a3472
Binary files /dev/null and b/web/frontend/src/lib/assets/simrun-icon.png differ
diff --git a/web/frontend/src/lib/components/Sidebar.svelte b/web/frontend/src/lib/components/Sidebar.svelte
index 76f250e..4490f2e 100644
--- a/web/frontend/src/lib/components/Sidebar.svelte
+++ b/web/frontend/src/lib/components/Sidebar.svelte
@@ -8,6 +8,7 @@
import { activeRuns } from '$lib/stores/runs';
import { getVersion } from '$lib/api/client';
import { health } from '$lib/stores/health';
+ import simrunIcon from '$lib/assets/simrun-icon.png';
import LayoutDashboardIcon from '@lucide/svelte/icons/layout-dashboard';
import PlayIcon from '@lucide/svelte/icons/play';
import FileTextIcon from '@lucide/svelte/icons/file-text';
@@ -54,23 +55,23 @@
{#if sidebar.state === 'collapsed'}
{:else}
-
- SR
-
+ />
SimRun
Attack Simulation
diff --git a/web/frontend/src/routes/login/+page.svelte b/web/frontend/src/routes/login/+page.svelte
index 720b39b..154ff4c 100644
--- a/web/frontend/src/routes/login/+page.svelte
+++ b/web/frontend/src/routes/login/+page.svelte
@@ -1,16 +1,13 @@
-
- SR
-
+
Welcome to SimRun
Sign in with your Google account to continue