ScenarioForge — installation guide

Marketing / product name is ScenarioForge. The on-disk identifier (Python package, CLI, env vars, Docker image) stays scenariogen for backwards compatibility — every command below uses that name. See docs/BRAND.md for the naming rule.

This is the customer-facing install guide for a self-host evaluation or production deployment. It assumes:

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)

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:

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:

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:

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:


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.