ScenarioForge — installation guide
Marketing / product name is ScenarioForge. The on-disk identifier (Python package, CLI, env vars, Docker image) stays
scenariogenfor backwards compatibility — every command below uses that name. Seedocs/BRAND.mdfor the naming rule.
This is the customer-facing install guide for a self-host evaluation or production deployment. It assumes:
- You have a host (laptop, VM, or Kubernetes cluster) that can run Docker.
- You have credentials for one LLM provider (BYOK — bring your own key).
- You have read-write API credentials for one or more issue trackers you want to integrate with.
scenariogen never proxies LLM traffic, never holds your tracker tokens,
and never phones home. See docs/LICENSING.md for the BYOK
guarantees.
1. Quick start — local evaluation
60-second demo (no credentials needed)
If you just want to see the review console working with realistic seeded data, before signing up for any LLM or tracker:
git clone https://github.com/luigipascal/Scenarios.git scenariogen
cd scenariogen
docker compose --profile demo up --build
# wait ~30s for the seed step, then:
open http://localhost:8000
This spins up a one-shot init container that seeds ./runs/ with a
complete demo (5 Kondor-treasury tickets, full RTM, BDD .feature
files, markdown reports) using the bundled stub LLM, then starts the
dashboard. No LLM key, no Jira credential, no .env file required.
When you're ready to use it against your own backlog, set credentials
in .env and use the "real" flow below.
Prerequisites (real use)
- Docker Desktop (Windows / macOS) or Docker Engine 24+ (Linux).
- Git to clone the repository.
- One LLM API key (OpenAI / Azure OpenAI / Anthropic / Gemini / Bedrock / on-prem OpenAI-compatible).
- One tracker credential (any of Jira / Linear / Azure DevOps / GitHub / GitLab).
Steps
# 1. Clone the repo into a dedicated folder.
git clone https://github.com/luigipascal/Scenarios.git scenariogen
cd scenariogen
git checkout claude/tracker-adapters-dev # enterprise branch
# 2. Configure BYOK + tracker credentials.
cp .env.example .env
# Edit .env:
# * One LLM provider, e.g. OPENAI_API_KEY=sk-...
# * One tracker, e.g. JIRA_URL + JIRA_USER + JIRA_TOKEN
# (or LINEAR_API_KEY / ADO_* / GITHUB_TOKEN / GITLAB_TOKEN)
# * Optional: SCENARIOGEN_LICENSE_KEY (otherwise community mode)
# 3a. Either build the image locally:
docker compose build --no-cache scenariogen
# 3b. ... or pull a pre-built image from GHCR (CI publishes on every push):
docker pull ghcr.io/luigipascal/scenariogen:enterprise-edge
docker tag ghcr.io/luigipascal/scenariogen:enterprise-edge scenariogen:latest
# 4. Start the dashboard.
docker compose up -d
# 5. Smoke-test from another terminal.
curl http://localhost:8000/api/health
# Or open the URL in a browser.
Windows / PowerShell users: the same flow is wrapped by a helper script:
.\scripts\scenariogen.ps1 pull-image enterprise-edge
.\scripts\scenariogen.ps1 up
.\scripts\scenariogen.ps1 admin alice # create an admin
.\scripts\scenariogen.ps1 logs # tail logs
.\scripts\scenariogen.ps1 license # confirm community / licensed
If port 8000 is taken, edit docker-compose.yml and change the host side
of the port mapping (e.g. "8123:8000" → open http://localhost:8123).
2. Enable authentication
By default — with no users defined and no shared-secret token — the
dashboard runs in open mode (single-user evaluation). The moment you
either set SCENARIOGEN_LICENSE_KEY or add a user, the auth layer
activates.
Create the first admin
docker compose run --rm scenariogen user add admin --role admin --display-name "Admin"
# Prompts for password twice. Minimum 8 characters.
Now http://localhost:8000 redirects you to /login. Sign in with the
admin you just created; the dashboard reappears with a "signed in as"
pill in the top-right and a logout link.
Roles available:
viewer— read runs, scenarios, RTM.reviewer— edit / approve / reject scenarios.author— trigger new runs, push approved scenarios to your tracker.admin— manage users + runtime configuration.
Add more users:
docker compose run --rm scenariogen user add alice --role reviewer
docker compose run --rm scenariogen user add bob --role author
docker compose run --rm scenariogen user list
docker compose run --rm scenariogen user set-role alice author
docker compose run --rm scenariogen user disable bob
Optional: shared-secret token (for CI / automation)
If you have a CI pipeline that needs to call the API non-interactively,
set SCENARIOGEN_TOKEN and pass it as X-Scenariogen-Token: … on every
request. The token acts as an author-role service principal.
3. Licensing
Without a licence, ScenarioForge runs in community mode:
- Single project, single tracker (Jira only).
- No SSO, no audit export, no enterprise add-ons.
With a vendor-signed licence token (Ed25519, stateless, offline-verifiable), you unlock the trackers and features listed inside the token. To inspect the active licence:
docker compose run --rm scenariogen license show
Apply a licence by putting it in .env:
SCENARIOGEN_LICENSE_KEY=eyJhbGciOi…
Or mount it from a Kubernetes / Docker secret:
SCENARIOGEN_LICENSE_FILE=/run/secrets/scenariogen-license
The licence file is verified on every container start against the vendor
public key bundled in the image. Air-gapped deployments can override
that with SCENARIOGEN_LICENSE_PUBLIC_KEY_FILE=….
See docs/LICENSING.md for the full token format,
rotation policy, and entitlement model.
4. Connect a tracker
scenariogen supports five trackers out of the box. Set the corresponding
env vars in .env, then either ingest from the CLI or use the dashboard.
| Tracker | Env vars | Example query |
|---|---|---|
| Jira | JIRA_URL, JIRA_USER, JIRA_TOKEN |
JQL: project = WALLET AND status != Done |
| Linear | LINEAR_API_KEY, LINEAR_API_URL |
identifiers: ENG-12,ENG-13 |
| Azure DevOps | ADO_ORGANIZATION, ADO_PROJECT, ADO_PAT |
id list: 101,102 or WIQL |
| GitHub | GITHUB_TOKEN, GITHUB_OWNER, GITHUB_REPO |
refs: acme/wallet#42 |
| GitLab | GITLAB_TOKEN, GITLAB_PROJECT, GITLAB_URL |
refs: acme/wallet#42 |
| YouTrack | YOUTRACK_URL, YOUTRACK_TOKEN |
id list: RON-1,RON-2 |
CLI examples:
docker compose run --rm scenariogen ingest --source jira --input "project = WALLET"
docker compose run --rm scenariogen ingest --source linear --input "ENG-12,ENG-13"
docker compose run --rm scenariogen ingest --source ado --input "101,102"
docker compose run --rm scenariogen ingest --source github --input "acme/wallet#42"
docker compose run --rm scenariogen ingest --source gitlab --input "acme/wallet#42"
End-to-end pipeline (generates scenarios + RTM + Gherkin + Markdown):
docker compose run --rm scenariogen run \
--source jira --input "project = WALLET" \
--system "Wallet App" --sector "fintech" \
--output-dir /app/runs
Outputs land in ./runs/<timestamp>/ on the host.
5. Production deployment
For anything beyond a single-host evaluation:
- TLS — put nginx / Caddy / Traefik / a cloud load balancer in front of port 8000. The container does not terminate TLS itself.
- Secrets — load
.envfrom a real secret store (Docker secrets, KubernetesSecret, AWS / GCP secret manager). Never bake API keys into the image. - Persistence — mount a persistent volume at
/app/runsand/app/.scenariogen/cacheso runs, audit logs, the user store, the licence run counter, and the session secret survive restarts. - Outbound network policy — restrict the container's egress to your LLM endpoint(s) + tracker URL(s) + (optionally) Tavily search.
- Observability — the container emits structured JSON logs on stdout
with
X-Request-IDcorrelation. Ship them to your existing log aggregator (Loki, Splunk, CloudWatch, etc.). Seedocs/DEPLOY.mdfor details.
Kubernetes (Helm)
For Studio / Agency / Enterprise tiers we ship a Helm chart at
helm/scenariogen/. Two install paths:
# A. From the repo (current).
helm install scenarioforge ./helm/scenariogen \
--namespace scenarioforge --create-namespace \
--set image.tag=enterprise-edge \
--set secrets.llmApiKey=$OPENAI_API_KEY \
--set secrets.licenseKey="$(cat scenarioforge.lic)" \
-f my-values.yaml
# B. From OCI (recommended for production — pinned + signed).
helm install scenarioforge \
oci://ghcr.io/luigipascal/charts/scenariogen \
--version 0.1.0 \
--namespace scenarioforge --create-namespace \
-f my-values.yaml
my-values.yaml example:
image:
repository: ghcr.io/luigipascal/scenariogen
tag: enterprise-edge # or pin to :v0.3.0 in production
ingress:
enabled: true
host: scenarioforge.acme-bank.internal
tls:
secretName: scenarioforge-tls
persistence:
runs:
size: 50Gi
storageClass: fast-ssd
resources:
requests: { cpu: 500m, memory: 1Gi }
limits: { cpu: 2, memory: 4Gi }
Secrets (LLM key, tracker creds, licence) come from a Kubernetes
Secret you create out-of-band — never set them in the values file
that lands in git.
6. Upgrading
cd <your-clone>
git pull
docker compose pull # if you're using the pre-built image
docker compose build --no-cache scenariogen # if you build locally
docker compose down
docker compose up -d
Backwards compatibility:
- The licence token format is versioned in its header (
SCEN-LIC); old tokens continue to verify against subsequent releases until we publish a breaking-change major version. - User-store files are pydantic-validated; unknown fields are dropped silently when a new release adds them.
7. Common problems
| Symptom | Fix |
|---|---|
docker compose up → "port already allocated" |
Edit docker-compose.yml: change "8000:8000" to e.g. "8123:8000". |
exec /usr/local/bin/scenariogen-entrypoint: no such file or directory |
CRLF line endings from a Windows checkout. Pull latest and rebuild — the Dockerfile strips \r automatically since commit 3870bc0. |
Bind for 0.0.0.0:8000 failed: port is already allocated after stopping a container |
docker compose down to release the port mapping reservation. |
Dashboard keeps redirecting to /login then back |
The session cookie is being lost. Likely a reverse-proxy issue rewriting cookies; check SameSite and that the proxy forwards Set-Cookie. |
scenariogen license show says "No licence configured" |
Expected for community mode. Set SCENARIOGEN_LICENSE_KEY to enable enterprise tiers. |
| HTTP 401 on every API call after enabling auth | Sign in at /login. CI clients should use X-Scenariogen-Token. |
| HTTP 403 "role does not cover" | Your role isn't high enough for that endpoint. See the role table above. |
For anything else, file an issue with the request-id from the
X-Request-ID response header — every log line carries it.
8. Air-gapped install (Enterprise tier)
For customers running in a disconnected environment (no outbound internet from the cluster), we deliver a single tarball that bundles the image, the Helm chart, the vendor public key, and an SBOM.
What we ship
scenarioforge-airgap-<version>.tar.gz
├── images/
│ └── scenariogen-<version>.tar # docker save output
├── helm/
│ └── scenariogen-<version>.tgz # helm package output
├── vendor-public-key.pem # Ed25519 licence verify key
├── sbom.spdx.json # SBOM (syft)
├── cosign.pub # cosign public key for image
├── INSTALL.txt # this file (offline copy)
└── checksums.sha256
Customer steps
# 1. Transfer the tarball into the air-gapped network and extract.
tar -xzf scenarioforge-airgap-v0.3.0.tar.gz
cd scenarioforge-airgap-v0.3.0
# 2. Verify checksums.
sha256sum -c checksums.sha256
# 3. Load the image into the cluster's internal registry.
docker load -i images/scenariogen-v0.3.0.tar
docker tag ghcr.io/luigipascal/scenariogen:v0.3.0 \
registry.internal.acme/scenariogen:v0.3.0
docker push registry.internal.acme/scenariogen:v0.3.0
# 4. Install via Helm, pointing at the internal registry.
helm install scenarioforge ./helm/scenariogen-v0.3.0.tgz \
--namespace scenarioforge --create-namespace \
--set image.repository=registry.internal.acme/scenariogen \
--set image.tag=v0.3.0 \
--set licensing.publicKeyFile=/etc/scenarioforge/vendor-public-key.pem \
-f my-values.yaml
# 5. Mount the licence + public key into the pod (Kubernetes Secret).
kubectl create secret generic scenarioforge-licence \
--from-file=licence=./scenarioforge.lic \
--from-file=vendor-public-key.pem=./vendor-public-key.pem \
-n scenarioforge
The licence verifies against vendor-public-key.pem with no outbound
network call. Zero phone-home.
To build the tarball yourself (vendor side, before shipping to the customer):
./scripts/build-airgap-bundle.sh \
--image-tag v0.3.0 \
--output-dir ./dist
9. Verifying the image (supply-chain)
Every image we publish to GHCR is signed with cosign (keyless OIDC via GitHub Actions) and ships with a syft-generated SBOM as a cosign attestation. Customers should verify both before deploying.
# 1. Verify the image signature.
cosign verify ghcr.io/luigipascal/scenariogen:enterprise-edge \
--certificate-identity-regexp 'https://github.com/luigipascal/Scenarios/.+' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com'
# 2. Verify and download the SBOM attestation.
cosign verify-attestation ghcr.io/luigipascal/scenariogen:enterprise-edge \
--type spdxjson \
--certificate-identity-regexp 'https://github.com/luigipascal/Scenarios/.+' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
| jq -r '.payload | @base64d | fromjson | .predicate' > sbom.spdx.json
Anna's procurement team will ask for both. Hand them the cosign verify command + the resulting SBOM JSON. SOC 2 Type II audit is in progress; until the report is final we share the evidence we have today (Ed25519 licence verification, structured per-tenant audit log, signed SBOM, DPA template) under NDA.