License configuration
StoatFlow validates a license at startup (and re-checks it on a periodic heartbeat). You give it two things: your license key and — for production — an environment label. This page covers every way to provide them, for local development and CI/CD.
The license key
Your key is the signed string from your onboarding email — it starts with key/. The runtime resolves it by looking for an explicit key first, then a key file — and within each, an environment variable beats a system property (which is what an application.yaml value becomes):
- An explicit key —
STOATFLOW_LICENSE_KEY(environment variable), else thestoatflow.license.keysystem property (whichapplication.yaml'sstoatflow.license.keyfeeds). - A key file —
STOATFLOW_LICENSE_FILE(environment variable), else thestoatflow.license.filesystem property (fed byapplication.yaml'sstoatflow.license.file), else the default~/.stoatflow/license.key.
So an explicit key always wins over a key file, regardless of where each came from.
application.yaml values are applied below environment variables and -D system properties — so an env var always wins over YAML. This lets you commit a YAML default and override it per environment without touching the file.Pick whichever fits — by source:
# Highest precedence. Good for containers, CI, and one-off local runs.
export STOATFLOW_LICENSE_KEY="key/...your key from the onboarding email..."
# Set once, every local app picks it up — no env var needed.
# Must be chmod 600 (owner-only) on Linux/macOS, or startup is refused.
mkdir -p ~/.stoatflow
printf '%s' 'key/...your key...' > ~/.stoatflow/license.key
chmod 600 ~/.stoatflow/license.key
# Runtime module only. Interpolate from an env var so the literal key
# never lands in source control.
stoatflow:
license:
key: ${STOATFLOW_LICENSE_KEY}
The environment label
The environment is a label for the deployment a license seat is bound to — e.g. prod, prod-eu-west, staging, dev. StoatFlow derives a machine fingerprint from it:
fingerprint = SHA-256(application-id || environment)
So the same application-id + the same environment is one seat; distinct environments are distinct seats. Set it with STOATFLOW_LICENSE_ENVIRONMENT, the stoatflow.license.environment system property, or stoatflow.license.environment in application.yaml.
- Local development (Trial / Developer tiers): if you don't set it, the environment defaults to
<your-username>-<hostname>— one seat per developer machine, no configuration needed. - Production: the Production tier requires an explicit environment — startup fails if it has to auto-generate one. Set it per deployment (
prod,prod-eu-west, …) so each gets its own node-locked seat.
Local development
The simplest local setup is the key file — write it once and every StoatFlow app you run locally is licensed, with no env vars and an auto-derived per-machine environment:
mkdir -p ~/.stoatflow
printf '%s' 'key/...your developer key...' > ~/.stoatflow/license.key
chmod 600 ~/.stoatflow/license.key
Prefer per-run configuration? Export the key (and optionally the environment) in your shell:
export STOATFLOW_LICENSE_KEY="key/...your developer key..."
# Optional — defaults to <username>-<hostname> if unset:
export STOATFLOW_LICENSE_ENVIRONMENT="dev-$(whoami)"
CI/CD
Use your CI/CD-tier key (it carries a higher machine cap suited to short-lived build agents). Store it as an encrypted secret — never in the repo.
On GitHub Actions, StoatFlow auto-detects the run and sets the environment to cicd-<run id> for you, so each run gets a fresh, ephemeral seat — you only need to provide the key:
# .github/workflows/your-workflow.yml
jobs:
integration-test:
runs-on: ubuntu-latest
env:
STOATFLOW_LICENSE_KEY: ${{ secrets.STOATFLOW_CI_LICENSE }}
# Optional — auto-derived as cicd-${GITHUB_RUN_ID} on GitHub Actions:
# STOATFLOW_LICENSE_ENVIRONMENT: cicd-${{ github.run_id }}
steps:
- uses: actions/checkout@v4
# ... build + run StoatFlow tests ...
On other CI systems (GitLab CI, Jenkins, …) there's no auto-detection — set the environment explicitly to something unique-per-run so concurrent builds don't contend for one seat:
export STOATFLOW_LICENSE_KEY="$STOATFLOW_CI_LICENSE"
export STOATFLOW_LICENSE_ENVIRONMENT="cicd-${CI_PIPELINE_ID:-$(date +%s)}"
All license settings
Every setting, with its environment variable, system property, and application.yaml key (under stoatflow.license). Environment variable wins over system property wins over YAML.
application.yaml (stoatflow.license.*) | Environment variable | System property | Default | Purpose |
|---|---|---|---|---|
key | STOATFLOW_LICENSE_KEY | stoatflow.license.key | — | The signed license key (key/…). |
file | STOATFLOW_LICENSE_FILE | stoatflow.license.file | ~/.stoatflow/license.key | Path to a file containing the key. |
environment | STOATFLOW_LICENSE_ENVIRONMENT | stoatflow.license.environment | <username>-<hostname> (auto) | Seat label; required for Production. |
cache-dir | STOATFLOW_LICENSE_CACHE_DIR | stoatflow.license.cache-dir | ~/.stoatflow/license-cache/ | Where the offline-grace cache is stored. |
verbose-banner | STOATFLOW_LICENSE_VERBOSE_BANNER | stoatflow.license.verbose-banner | false | Log a detailed license banner at startup. |
Troubleshooting
- Startup fails: license missing / invalid / expired / revoked. StoatFlow hard-fails fast rather than running unlicensed. Check the key is set (precedence above) and current.
license key file has insecure permissions. The key file must be owner-only —chmod 600 ~/.stoatflow/license.key.- Production refuses to start without an environment. Set
STOATFLOW_LICENSE_ENVIRONMENT(orstoatflow.license.environment) explicitly — Production won't auto-generate one. - Brief Keygen outage. The runtime keeps serving from its offline cache for the grace window, then fails on the next check. Normal restarts within the window are fine.
- Lost your key or token? We re-issue rather than retrieve — reply to your onboarding email and we'll rotate it.
Next steps
- Architecture — how the engine runs your topology.
- Questions about your license tier or seats? Get in touch.