@cratis/pi 7.126.0 → 7.128.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/package/corpus/harnesses/copilot/instructions/profiles.instructions.md +3 -2
  2. package/package/corpus/harnesses/copilot/instructions/secrets.instructions.md +1 -1
  3. package/package/corpus/hooks/README.md +1 -1
  4. package/package/corpus/hooks/scripts/cratis-guard-secrets.sh +13 -2
  5. package/package/corpus/rules/profiles.md +3 -2
  6. package/package/corpus/rules/secrets.md +1 -1
  7. package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/SKILL.md +1 -1
  8. package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/references/authproxy.md +26 -0
  9. package/package/corpus/skills/cratis-environments-and-secrets/LICENSE +9 -0
  10. package/package/corpus/skills/cratis-environments-and-secrets/SKILL.md +112 -0
  11. package/package/corpus/skills/cratis-environments-and-secrets/references/environment-file.md +48 -0
  12. package/package/corpus/skills/cratis-onboarding-runtime/LICENSE +9 -0
  13. package/package/corpus/skills/cratis-onboarding-runtime/SKILL.md +102 -0
  14. package/package/corpus/skills/cratis-onboarding-runtime/references/ante-onboarding-keys.md +31 -0
  15. package/package/corpus/skills/cratis-onboarding-runtime/references/default-offering.md +61 -0
  16. package/package/corpus/skills/cratis-onboarding-runtime/references/performance.md +86 -0
  17. package/package/corpus/skills/cratis-onboarding-runtime/references/sign-up-review.md +52 -0
  18. package/package/corpus/skills/cratis-screenplay-authentication-and-onboarding/LICENSE +9 -0
  19. package/package/corpus/skills/cratis-screenplay-authentication-and-onboarding/SKILL.md +111 -0
  20. package/package/corpus/skills/cratis-screenplay-authentication-and-onboarding/references/onboarding-directives.md +89 -0
  21. package/package/corpus/skills/cratis-screenplay-authentication-and-onboarding/verification.json +32 -0
  22. package/package/corpus/skills/cratis-screenplay-command-surface/references/policy-persona-seed.md +1 -0
  23. package/package/corpus/skills/cratis-screenplay-model-authoring/references/language-reference.md +1 -1
  24. package/package/corpus/skills/cratis-screenplay-model-review/SKILL.md +2 -0
  25. package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/references/renderability-gate.md +8 -0
  26. package/package/corpus/skills/cratis-screenplay-toolchain/references/neighbouring-skills.md +2 -0
  27. package/package/corpus/skills/cratis-screenplay-toolchain/references/screenplay-contract-exceptions.json +70 -0
  28. package/package/corpus/skills/cratis-showrunner-herald/LICENSE +9 -0
  29. package/package/corpus/skills/cratis-showrunner-herald/SKILL.md +111 -0
  30. package/package/corpus/skills/cratis-showrunner-herald/references/options.md +35 -0
  31. package/package/corpus/skills/cratis-showrunner-herald/references/templates-and-images.md +70 -0
  32. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/SKILL.md +5 -0
  33. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/rendered-application.md +48 -0
  34. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/sandbox-and-specrunner.md +7 -0
  35. package/package/profile-catalog.json +6 -2
  36. package/package.json +1 -1
@@ -215,12 +215,12 @@ language policy always follows the consuming repository's `go.mod` minimum.
215
215
  | `cratis/codescene` | Opt-in CodeScene Code Health change gates, refactoring, debt prioritization and risk-based testing; requires an account and available MCP tools; each user registers the MCP server (see below) |
216
216
  | `cratis/playwright` | Opt-in Playwright browser automation MCP server declaration for exploratory checks; carries no skills or rules and each user registers the server (see below) |
217
217
  | `cratis/studio` | Studio MCP safety guidance |
218
- | `cratis/cli` | CLI operations |
218
+ | `cratis/cli` | CLI operations, project environments and secrets |
219
219
  | `cratis/cli/terminal-workbench` | Human-operated terminal Workbench |
220
220
  | `cratis/chronicle/mcp` | Chronicle MCP inspection and exact tool-effect guidance |
221
221
  | `cratis/lens` | Lens browser extension |
222
222
  | `cratis/screenplay` | Model-first event modeling: lifecycle, phase skills, toolchain, review, render and gap-fill, plus the whole `.play` language |
223
- | `cratis/stage` | Stage rendering and sandbox |
223
+ | `cratis/stage` | Stage rendering and sandbox, onboarding runtime (Ante, Stage Manager) |
224
224
  | `cratis/modeling/screenplay-stage` | Screenplay + Stage together |
225
225
 
226
226
  ### Code Health with CodeScene
@@ -302,6 +302,7 @@ and one phase skill, then the construct skill needed for syntax.
302
302
  | `cratis-screenplay-read-surface` | `readmodel`, `query`, `screen`, name resolution |
303
303
  | `cratis-screenplay-ui-composition` | `layout`, templates, `form`, `contribute`, `ui profile`, `theme`, `$strings`, `file` |
304
304
  | `cratis-screenplay-captures-and-reactions` | The Change Data Capture Language, `reaction`, `trigger` |
305
+ | `cratis-screenplay-authentication-and-onboarding` | `authentication`, `onboarding`, and the environment keys derived from them |
305
306
  | `cratis-screenplay-specifications` | Given/when/then and the reference execution |
306
307
  | `cratis-screenplay-model-authoring` | Typed MCP authoring, model navigation/refactoring, compiler diagnostics, and source-versus-executable readiness |
307
308
 
@@ -17,7 +17,7 @@ Every line is tagged **[contract]** (binding) per the Three Levels of Authority
17
17
  secrets; `kubectl get secret`; `kubectl config view --raw`; `env`, `printenv`, `export -p`
18
18
  (including `env | …`); `docker inspect`; `gh secret`, `gh api …/secrets`, `gh auth token`;
19
19
  `vault read`, `vault kv get`; cloud secret-manager reads; `pulumi … --show-secrets`;
20
- reading kubeconfigs, `.env*` files, private keys or token files.
20
+ `cratis config get … --show-secret`; reading kubeconfigs, `.env*` files, private keys or token files.
21
21
  - **[contract] Project the field you need and say which one:** `-o jsonpath='{.spec.containers[*].image}'`,
22
22
  `-o custom-columns=…`, `kubectl get … -o name`, status fields, `kubectl logs`, `docker inspect --format`.
23
23
  Read a `.env.example`, never the `.env`.
@@ -11,7 +11,7 @@ Three layers:
11
11
  | Pattern pass | `PostToolUse` on a write | `scripts/cratis-pattern-scan.sh` | zero tokens until a match | appends a one-line reminder to context, never blocks |
12
12
  | Hard block | `PreToolUse` on a write | `scripts/cratis-guard-writes.sh` | zero | exits **2** — the write does not happen |
13
13
  | Hard block | `PreToolUse` on `Bash` | `scripts/cratis-guard-store-mutations.sh` | zero; parses only commands that mention `cratis` | exits **2** — the store-changing `cratis chronicle` command does not run |
14
- | Hard block | `PreToolUse` on `Bash` | `scripts/cratis-guard-secrets.sh` | zero; parses only commands that mention a credential-bearing tool or file | exits **2** — a command that prints credentials (full `kubectl` specs and secrets, `env`/`printenv`, `docker inspect`, secret-manager reads, `.env`/kubeconfig/key files; also behind `/usr/bin/env`, `command`, attached options such as `-ePATTERN`, a bare `{.}` projection) does not run unless it projects a field; piped shells and recursive searches with no named file stay uncovered; see [`secrets.md`](../rules/secrets.md) |
14
+ | Hard block | `PreToolUse` on `Bash` | `scripts/cratis-guard-secrets.sh` | zero; parses only commands that mention a credential-bearing tool or file | exits **2** — a command that prints credentials (full `kubectl` specs and secrets, `env`/`printenv`, `docker inspect`, secret-manager reads, `cratis config get --show-secret`, `.env`/kubeconfig/key files; also behind `/usr/bin/env`, `command`, attached options such as `-ePATTERN`, a bare `{.}` projection) does not run unless it projects a field; piped shells and recursive searches with no named file stay uncovered; see [`secrets.md`](../rules/secrets.md) |
15
15
  | Hard block | `PreToolUse` on `Bash` | `scripts/cratis-guard-pr-body.sh` | fetches shared rules only for `gh pr create/edit` | exits **2** for inline bodies, invalid notes or conflicting release labels; warns and allows when offline with no cache |
16
16
  | Cleanup of delivered work | `PostToolUse` on `Bash` (`gh pr merge`, `git pull/merge/worktree`) and `SessionStart` (Pi: `tool_result` and `session_start`) | `scripts/cratis-cleanup-worktrees.sh --hook` | zero when the command is unrelated | never blocks; removes delivered worktrees and branches, reports what it kept |
17
17
  | Quality gate (Claude) | `Stop` | `scripts/cratis-quality-gate.sh` | one build/test run, only when relevant files changed | exits **2** — the turn does not end |
@@ -35,7 +35,7 @@ command_text="$(hook_json "$input" '.tool_input.command')"
35
35
 
36
36
  # Cheap exit for the overwhelming majority of shell commands, which mention none of these words.
37
37
  case "$(printf '%s' "$command_text" | tr '[:upper:]' '[:lower:]')" in
38
- *kubectl*|*printenv*|*env*|*docker*|*podman*|*"gh "*|*vault*|*pulumi*|*aws*|*"az "*|*gcloud*|*kubeconfig*|*.kube*|\
38
+ *kubectl*|*printenv*|*env*|*docker*|*podman*|*"gh "*|*vault*|*pulumi*|*show-secret*|*aws*|*"az "*|*gcloud*|*kubeconfig*|*.kube*|\
39
39
  *export*|*declare*|*typeset*|*id_rsa*|*id_ed25519*|*id_ecdsa*|*id_dsa*|*.pem*|*.p12*|*.pfx*|*token*|*.netrc*|*.npmrc*|\
40
40
  *credentials*|*.pgpass*|*secrets*) ;;
41
41
  *) exit 0 ;;
@@ -397,7 +397,7 @@ function drop_redirects(A, s, n, k, m, w) {
397
397
  }
398
398
  return m
399
399
  }
400
- function analyze(A, s, n, w, b, k, names, p) {
400
+ function analyze(A, s, n, w, b, k, names, p, config, get, show) {
401
401
  while (s <= n) {
402
402
  w = A[s]; b = base(w)
403
403
  if (is_assign(w)) { s++; continue }
@@ -446,6 +446,17 @@ function analyze(A, s, n, w, b, k, names, p) {
446
446
  for (k = s + 1; k <= n; k++) if (A[k] ~ /^--show-secrets/) report("pulumi --show-secrets prints decrypted secrets", "pulumi config / pulumi stack output without --show-secrets (secrets stay masked)")
447
447
  return
448
448
  }
449
+ # `cratis config get` prints a secret as [secret]; --show-secret resolves it through the secrets provider.
450
+ if (b == "cratis") {
451
+ config = 0
452
+ for (k = s + 1; k <= n; k++) {
453
+ if (A[k] == "config") config = 1
454
+ else if (config && A[k] == "get") get = 1
455
+ if (A[k] ~ /^--show-secret/) show = 1
456
+ }
457
+ if (config && get && show) report("cratis config get --show-secret prints a decrypted secret", "cratis config get without --show-secret (a secret prints as [secret]); name the key in your report")
458
+ return
459
+ }
449
460
  # A redirect is not a variable name: `printenv > f` and `export > f` still dump the whole environment.
450
461
  if (b == "printenv" || b == "export" || b == "declare" || b == "typeset") n = drop_redirects(A, s, n)
451
462
  if (b == "printenv") {
@@ -214,12 +214,12 @@ language policy always follows the consuming repository's `go.mod` minimum.
214
214
  | `cratis/codescene` | Opt-in CodeScene Code Health change gates, refactoring, debt prioritization and risk-based testing; requires an account and available MCP tools; each user registers the MCP server (see below) |
215
215
  | `cratis/playwright` | Opt-in Playwright browser automation MCP server declaration for exploratory checks; carries no skills or rules and each user registers the server (see below) |
216
216
  | `cratis/studio` | Studio MCP safety guidance |
217
- | `cratis/cli` | CLI operations |
217
+ | `cratis/cli` | CLI operations, project environments and secrets |
218
218
  | `cratis/cli/terminal-workbench` | Human-operated terminal Workbench |
219
219
  | `cratis/chronicle/mcp` | Chronicle MCP inspection and exact tool-effect guidance |
220
220
  | `cratis/lens` | Lens browser extension |
221
221
  | `cratis/screenplay` | Model-first event modeling: lifecycle, phase skills, toolchain, review, render and gap-fill, plus the whole `.play` language |
222
- | `cratis/stage` | Stage rendering and sandbox |
222
+ | `cratis/stage` | Stage rendering and sandbox, onboarding runtime (Ante, Stage Manager) |
223
223
  | `cratis/modeling/screenplay-stage` | Screenplay + Stage together |
224
224
 
225
225
  ### Code Health with CodeScene
@@ -301,6 +301,7 @@ and one phase skill, then the construct skill needed for syntax.
301
301
  | `cratis-screenplay-read-surface` | `readmodel`, `query`, `screen`, name resolution |
302
302
  | `cratis-screenplay-ui-composition` | `layout`, templates, `form`, `contribute`, `ui profile`, `theme`, `$strings`, `file` |
303
303
  | `cratis-screenplay-captures-and-reactions` | The Change Data Capture Language, `reaction`, `trigger` |
304
+ | `cratis-screenplay-authentication-and-onboarding` | `authentication`, `onboarding`, and the environment keys derived from them |
304
305
  | `cratis-screenplay-specifications` | Given/when/then and the reference execution |
305
306
  | `cratis-screenplay-model-authoring` | Typed MCP authoring, model navigation/refactoring, compiler diagnostics, and source-versus-executable readiness |
306
307
 
@@ -16,7 +16,7 @@ Every line is tagged **[contract]** (binding) per the Three Levels of Authority
16
16
  secrets; `kubectl get secret`; `kubectl config view --raw`; `env`, `printenv`, `export -p`
17
17
  (including `env | …`); `docker inspect`; `gh secret`, `gh api …/secrets`, `gh auth token`;
18
18
  `vault read`, `vault kv get`; cloud secret-manager reads; `pulumi … --show-secrets`;
19
- reading kubeconfigs, `.env*` files, private keys or token files.
19
+ `cratis config get … --show-secret`; reading kubeconfigs, `.env*` files, private keys or token files.
20
20
  - **[contract] Project the field you need and say which one:** `-o jsonpath='{.spec.containers[*].image}'`,
21
21
  `-o custom-columns=…`, `kubectl get … -o name`, status fields, `kubectl logs`, `docker inspect --format`.
22
22
  Read a `.env.example`, never the `.env`.
@@ -48,7 +48,7 @@ ingress above, otherwise configure a credential-validating scheme. The old
48
48
  same host-wide flag. See [authentication](references/authentication.md).
49
49
  Source: [secure defaults](https://github.com/Cratis/Arc/blob/main/Documentation/upgrading/secure-defaults.mdx).
50
50
 
51
- Cratis AuthProxy is the ingress that meets these obligations for Cratis applications. Read [AuthProxy](references/authproxy.md) when the application is deployed behind it (header contract, `/.cratis/me` fail-closed verification, tenant headers).
51
+ Cratis AuthProxy is the ingress that meets these obligations for Cratis applications. Read [AuthProxy](references/authproxy.md) when the application is deployed behind it (header contract, `/.cratis/me` fail-closed verification, tenant headers, and starting it from a Screenplay model's provider list and a Cratis environment).
52
52
 
53
53
  ## Identity details — what the frontend is told
54
54
 
@@ -49,6 +49,32 @@ is a crawler policy, not authorization. Invitation error-page tokens
49
49
  letters, digits and `._+-@`; do not assume these placeholders always contain text.
50
50
  Signed-in `/register` forwarding needs no host workaround.
51
51
 
52
+ ## Starting AuthProxy from a Screenplay application's contract
53
+
54
+ Requires AuthProxy 2.40.0 or later for `Cratis:AuthProxy:Application`; an older image ignores it and starts with no providers.
55
+
56
+ AuthProxy can start from two inputs: the **provider list** of a Screenplay model (kind and identity per provider) and the **values of a Cratis environment**. It translates them onto its ordinary `Cratis:AuthProxy` options, so an application behind it trusts the proxy exactly as described above. The model never carries provider configuration; see `cratis-screenplay-authentication-and-onboarding` for the keys and `cratis-environments-and-secrets` for the values.
57
+
58
+ ```json
59
+ {
60
+ "Cratis": { "AuthProxy": { "Application": {
61
+ "EnvironmentName": "production",
62
+ "Providers": [
63
+ { "Kind": "EntraId", "Identity": "EntraId" },
64
+ { "Kind": "OpenId", "Identity": "Partner" }
65
+ ]
66
+ } } }
67
+ }
68
+ ```
69
+
70
+ - A provider's `Kind` is `EntraId`, `GitHub`, `Google`, `Apple` or `OpenId`; `Identity` is the model's alias, otherwise the provider name, unique ignoring case. The identity is also the scheme (lowercase, spaces to hyphens), so the callback is `/signin-<scheme>`.
71
+ - Required keys per kind: `clientId` and `clientSecret` for all; plus `tenantId` for `EntraId` and `authority` for `OpenId`. Each is addressed as `authentication.providers.<Identity>.<key>`.
72
+ - The contract cannot be combined with providers configured directly under `Authentication:OidcProviders` or `OAuthProviders`; AuthProxy refuses to start.
73
+ - A missing required key stops AuthProxy before it listens (exit code 78), naming the key, provider and environment, never a value.
74
+ - **Secrets are never read from arguments and never logged.** A key resolves from `Cratis:AuthProxy:Application:Environment:<key>`, then the same key with `_FILE` appended (a path to a file holding the value), then a file named exactly `<key>` in `SecretsDirectory`. Mount secrets as files and point `SecretsDirectory` at the folder; do not put a secret in an environment variable or an image.
75
+ - `Application:Development=true` allows HTTP only on loopback addresses; every other URL must be HTTPS. Never set it outside local development.
76
+ - With `Application:Onboarding=true`, supply the `onboarding.*` keys for the application's own Ante and every provider also gets invitation completion; see `cratis-onboarding-runtime`.
77
+
52
78
  ## Tenants and services
53
79
 
54
80
  AuthProxy resolves the tenant through ordered strategies under `Cratis:AuthProxy:TenantResolutions` (`Host`, `Claim`, `Route`, `Specified`, `Default`, `SubHost`, `Selection`). The result reaches the backend as `x-cratis-tenant-id`, which is Arc's default tenant header, so an Arc application behind AuthProxy needs no tenancy configuration and the `UseHeaderTenancy("Tenant-ID")` workaround seen in older applications can be removed.
@@ -0,0 +1,9 @@
1
+ Copyright (c) Cratis. All rights reserved.
2
+ Licensed under the MIT license. See LICENSE file in the canonical Cratis/AI repository for the full license text.
3
+
4
+ Third-party notices
5
+
6
+ This skill adapts material from agentic-engineer by Martin Dilger and Nebulit GmbH
7
+ (https://github.com/Nebulit-GmbH/agentic-engineer, commit 07b0f30648d663cb588d7e2c7aa031af9dfc21f2;
8
+ https://nebulit.de), used with the explicit consent of Martin Dilger and Nebulit GmbH. The adapted
9
+ material remains credited to Martin Dilger and Nebulit GmbH.
@@ -0,0 +1,112 @@
1
+ ---
2
+ name: cratis-environments-and-secrets
3
+ description: Use when a Cratis project needs named environments, per-environment configuration values or secrets with `cratis env` and `cratis config`, or when a Screenplay model's environment keys must be filled. Not for Chronicle server contexts or for authoring the model.
4
+ license: MIT
5
+ ---
6
+
7
+ # Cratis environments and secrets
8
+
9
+ A Screenplay model is the same in every environment. What it needs to run (a client id, an SMTP
10
+ host, a signing key) is not. A project keeps that in **named environments**, one committed file
11
+ per environment next to the model, in the way a Pulumi project has stacks. Which keys a model
12
+ needs is derived from its declarations: see
13
+ [cratis-screenplay-authentication-and-onboarding](../cratis-screenplay-authentication-and-onboarding/SKILL.md).
14
+
15
+ **Requires** `cratis` 3.114.0 or later for `cratis env` and `cratis config` (`cratis --version`,
16
+ and `which -a cratis` for a shadowing copy). The commands do not exist in older releases.
17
+
18
+ This is not a Chronicle server context: `cratis context` and `-e/--event-store` on `chronicle`
19
+ commands belong to `cratis-chronicle-cli-operations`.
20
+
21
+ ## The secrets contract
22
+
23
+ This skill applies the always-on [secrets rule](../../rules/secrets.md); read it first. For this
24
+ CLI it means:
25
+
26
+ - **A secret enters only through stdin or the hidden prompt.** Never as an argument (it lands in shell history and the transcript).
27
+ - **An agent never runs `cratis config get <key> --show-secret`** and never prints a secret by
28
+ any other route. Without the flag a secret prints as `[secret]`, which is the form to use.
29
+ - **An agent does not receive the value to set.** When a secret is needed and the person has not
30
+ provided it through a channel the agent cannot read, ask them to run the `--secret` command in
31
+ their own terminal. Do not ask them to paste it into the chat.
32
+ - **A passphrase is not a value to hold.** It comes from `CRATIS_PASSPHRASE`, the file named by
33
+ `CRATIS_PASSPHRASE_FILE`, or the hidden prompt. Never write one to a file in the repository,
34
+ and never export one inline in a command.
35
+
36
+ ## Files and selection
37
+
38
+ Each environment is `.cratis/environments/<name>.yaml`; a name is a safe file name such as
39
+ `development`, `staging` or `customer-x`. Entries are a plain `key: value`, a `secure: <base64>`
40
+ secret encrypted by the passphrase provider (safe to commit), or a `ref:` to a vault. The file
41
+ never holds a clear-text secret. Read [environment file](references/environment-file.md) for the
42
+ exact shape.
43
+
44
+ The environment in effect is, in order: `--environment <name>` (`-e` on `env` and `config`),
45
+ `CRATIS_ENVIRONMENT`, the user's selection in `.cratis/local/selected-environment` (not committed), then
46
+ `development`. On Chronicle commands `-e` means `--event-store`; use `--environment` there.
47
+
48
+ ## Commands
49
+
50
+ ```bash
51
+ cratis env init # creates "development"
52
+ cratis env init production --secrets-provider azurekeyvault://<vault>
53
+ cratis env select production
54
+ cratis env ls
55
+ cratis config set auth:clientId <client-id>
56
+ cratis config set smtp:password --secret # reads stdin or a hidden prompt
57
+ cratis config get smtp:password # [secret]
58
+ cratis config # list; secrets show as [secret]
59
+ cratis config --missing ./model # keys the model needs and the environment lacks
60
+ ```
61
+
62
+ | Command | Purpose |
63
+ |---|---|
64
+ | `cratis env init [name]` | Create an environment; `--secrets-provider` picks where secrets live. |
65
+ | `cratis env select <name>` / `ls` / `rm <name>` | Select for this user, list (the one in effect is marked), remove (confirms; `--yes` skips). |
66
+ | `cratis env change-secrets-provider <uri>` | Move every secret to another provider; the file never holds clear text in between. |
67
+ | `cratis env change-passphrase` | Re-encrypt every secret under a new passphrase and salt. |
68
+ | `cratis config set <key> <value>` | Set a plain value. |
69
+ | `cratis config set <key> --secret` | Set a secret. |
70
+ | `cratis config get <key>` / `rm <key>` | Read (secrets masked) / remove (also from the vault). |
71
+ | `cratis config [--missing <path>]` | List keys, or the keys a model needs that are absent. |
72
+
73
+ All accept `-o json`. Exit codes: `0` success, `1` not found, `4` authentication failed (wrong
74
+ passphrase), `5` validation, including any key missing under `--missing`.
75
+
76
+ ## Choosing a secrets provider
77
+
78
+ Default to **passphrase** for a project with one team and a committed environment file. Choose a
79
+ vault when secrets must not travel with the repository or are shared with a cluster.
80
+
81
+ | Provider | Use when | Credentials come from |
82
+ |---|---|---|
83
+ | `passphrase` (default) | Secrets are committed encrypted (AES-256-GCM, key derived per environment). | `CRATIS_PASSPHRASE`, `CRATIS_PASSPHRASE_FILE` or a prompt. |
84
+ | `azurekeyvault://<vault>` | The team already runs Azure Key Vault. | `DefaultAzureCredential` (Azure CLI login, managed or workload identity). |
85
+ | `hashivault://<address>/<mount>[/<path>]` | The team runs HashiCorp Vault KV v2. `hashivault+http://` is for a development server. | `VAULT_TOKEN`, or `VAULT_ROLE_ID` and `VAULT_SECRET_ID`, or `VAULT_K8S_ROLE`. |
86
+
87
+ `cratis run` on a model with `authentication` resolves the selected environment (or `-e <name>`)
88
+ before starting Docker, hands the provider and onboarding values to the AuthProxy and Ante
89
+ containers, and stops with exit `5` listing the missing keys, never their values. A mail
90
+ server is optional: without `onboarding.email.server.host`, emails are written as `.eml` files.
91
+ Requires cratis CLI 3.116.0 (`cratis --version`); older CLIs run the Stage alone and play a persona.
92
+
93
+ ## Pitfalls
94
+
95
+ - Setting a secret with `cratis config set smtp:password <value>` stores a plain value and leaks it. Always add `--secret` and pipe or prompt.
96
+ - Committing a `.cratis/local/` folder: it holds the personal selection and is git-ignored by `cratis init` and `cratis env select`.
97
+ - Wrong passphrase is exit `4` before anything is decrypted; do not retry it in a loop.
98
+ - `cratis config --missing` on a model that does not compile exits `5` and names the first errors; fix the model first.
99
+ - A key added to the model later is missing from existing environments; re-run `--missing` per environment.
100
+
101
+ ## Verify
102
+
103
+ 1. `cratis env ls` marks the environment you intend; `cratis config -e <name>` lists the expected keys.
104
+ 2. `cratis config --missing <model-folder> -e <name>` exits `0` (`echo $?`).
105
+ 3. `git diff` on `.cratis/environments/` shows only plain values, `secure:` or `ref:` entries, and no clear-text secret.
106
+ 4. No command in the session used `--show-secret`, and no secret appears in the transcript.
107
+
108
+ ## Route near misses
109
+
110
+ - Chronicle server contexts and operations: `cratis-chronicle-cli-operations`.
111
+ - The model's `authentication` and `onboarding` blocks and their keys: `cratis-screenplay-authentication-and-onboarding`.
112
+ - Running the application with the resolved values: `cratis-onboarding-runtime` (cluster) and `cratis-stage-rendering-and-sandbox`.
@@ -0,0 +1,48 @@
1
+ # Environment file
2
+
3
+ ```yaml
4
+ secretsProvider: passphrase
5
+ encryptionSalt: <base64>
6
+ encryption:
7
+ kdf: pbkdf2-sha256
8
+ iterations: 600000
9
+ check: <base64>
10
+ config:
11
+ auth:clientId: <client-id>
12
+ smtp:host: mail.example.com
13
+ smtp:password:
14
+ secure: <base64>
15
+ signing:key:
16
+ ref: <vault reference>
17
+ ```
18
+
19
+ | Entry | Meaning |
20
+ |---|---|
21
+ | `key: value` | A plain value. |
22
+ | `key: { secure: <base64> }` | A secret encrypted by the passphrase provider; bound to its key, so moving the ciphertext to another key fails. Safe to commit. |
23
+ | `key: { ref: <name> }` | A secret kept in Azure Key Vault or HashiCorp Vault. The file holds only the reference. |
24
+
25
+ `secretsProvider`, `encryptionSalt` and `encryption` describe where secrets live. The salt is per
26
+ environment, so two environments with one passphrase get different ciphertext. Do not edit these
27
+ fields by hand; use `cratis env change-passphrase` or `change-secrets-provider`.
28
+
29
+ ## Vault storage
30
+
31
+ - Azure Key Vault: secrets named `cratis-<environment>-<key>` with a short hash suffix; the file holds the name as `ref:`.
32
+ - HashiCorp Vault: KV v2 at `<path>/<environment>/<key>` (the path defaults to `cratis`); the file holds that path as `ref:`.
33
+ - `VAULT_AUTH_MOUNT` overrides the auth method mount and `VAULT_NAMESPACE` sets the Vault namespace.
34
+
35
+ ## Reading environments from code
36
+
37
+ The `Cratis.Environments` package reads the same files, so other tools resolve values and
38
+ secrets exactly as the CLI does.
39
+
40
+ ```csharp
41
+ var environments = ProjectEnvironments.Discover(Directory.GetCurrentDirectory());
42
+ var selected = environments.Resolve(explicitName: null);
43
+ var environment = ProjectEnvironment.Open(environments, selected.Name, PassphraseSources.FromEnvironment());
44
+
45
+ var clientId = await environment.GetValueAsync("auth:clientId");
46
+ ```
47
+
48
+ Keep a resolved secret in memory only; never log it or write it to a file the repository tracks.
@@ -0,0 +1,9 @@
1
+ Copyright (c) Cratis. All rights reserved.
2
+ Licensed under the MIT license. See LICENSE file in the canonical Cratis/AI repository for the full license text.
3
+
4
+ Third-party notices
5
+
6
+ This skill adapts material from agentic-engineer by Martin Dilger and Nebulit GmbH
7
+ (https://github.com/Nebulit-GmbH/agentic-engineer, commit 07b0f30648d663cb588d7e2c7aa031af9dfc21f2;
8
+ https://nebulit.de), used with the explicit consent of Martin Dilger and Nebulit GmbH. The adapted
9
+ material remains credited to Martin Dilger and Nebulit GmbH.
@@ -0,0 +1,102 @@
1
+ ---
2
+ name: cratis-onboarding-runtime
3
+ description: Use when running or deploying the onboarding of a Screenplay application, meaning configuring the application's Ante from the onboarding contract or declaring a Showrunner Stage Manager `Performance` that runs the application with its AuthProxy and Ante. Not for authoring the model or for Ante used by a host product.
4
+ license: MIT
5
+ ---
6
+
7
+ # Onboarding runtime: Ante and Stage Manager
8
+
9
+ A Screenplay model with `authentication` and `onboarding` is carried out by three runtime parts
10
+ that read one contract, produced from the model and a Cratis environment:
11
+
12
+ | Part | Does | Contract |
13
+ |---|---|---|
14
+ | **AuthProxy** | The only public entry point; signs people in with the model's providers. | `Cratis:AuthProxy:Application` (see the AuthProxy reference of `cratis-arc-authentication-authorization-and-identity`). |
15
+ | **Ante** | **One per application.** Signs invitation tokens, serves the lobby, records acceptance and legal terms, publishes to its outbox. | `Ante:Onboarding:*`. |
16
+ | **Herald** | Sends the invitation and welcome emails from the application (including the declined sign-up email). | `cratis-showrunner-herald`. |
17
+
18
+ Nobody writes the equivalent `Ante:*` or `Cratis:AuthProxy:*` keys by hand for a Screenplay
19
+ application. The model supplies structure (providers, personas, invitation types, legal files);
20
+ the **environment** supplies every value and secret (`cratis-environments-and-secrets`).
21
+
22
+ **Requires** Ante 1.5.0 or later for `Ante:Onboarding:*`, AuthProxy 2.40.0 or later for
23
+ `Cratis:AuthProxy:Application`, and Showrunner 1.11.0 or later for the `Performance` resource.
24
+
25
+ ## Who owns what
26
+
27
+ Ante owns token signing, the lobby, local acceptance, legal terms presented from files, and the
28
+ persona and invitation-type checks. The **application** owns the persona list (the model), who is
29
+ invited, link delivery, membership and provisioning. Ante sends no email: the application sends
30
+ the invitation link through Herald using the `InvitationTokenIssued` token. Every accepted fact
31
+ (`InvitationToJoinTenantAccepted`, `InvitationToCreateTenantAccepted`,
32
+ `OrganizationRegistrationCompleted`, `OrganizationRegistrationDeclined`, `LegalTermsAccepted`) means **published to Ante's outbox, not
33
+ provisioned**: make provisioning idempotent by event source id and event kind. Ante does not know
34
+ what a persona may do; it validates grantable personas against the configured list only.
35
+
36
+ ## Ante's onboarding contract
37
+
38
+ Set `Ante:Onboarding:Enabled=true` to apply it. While `false` or absent every `Ante:Onboarding:*`
39
+ key is ignored. When enabled, each value it carries wins over the ordinary key it maps to,
40
+ including values from `appsettings.json`. Read [Ante onboarding keys](references/ante-onboarding-keys.md)
41
+ for the table before configuring anything.
42
+
43
+ - `HostStore` is the application's own Chronicle store, the only host store Ante observes. The application appends `UserInvitedToJoinTenant` or `UserInvitedToCreateTenant` to that store's outbox.
44
+ - `SignUp` is `CreateTenant` (default; self-service registration may create a tenant) or `JoinTenant` (`/register` closed; invitation only). This is the model's `signup` line.
45
+ - `InvitationTypes` and `Personas` are runtime checks: an invitation of a disallowed type is rejected with `InvitationTypeNotAllowed`, one granting a persona outside the list with `PersonaNotGrantable`, and no token is issued either way. Validate against the model's persona list in the application first; Ante is the second line of defense. Observe generation 4 of `InvitationRejected`.
46
+ - Legal terms are files in a mounted folder (`terms.md`, `privacy.md`). The version is a content hash, so editing either file requires everyone onboarding afterwards to accept again. Archive each version for consent audit; the bodies live in your files.
47
+ - **Secrets** (the signing private key, pinned attestation public keys) arrive only as mounted files or standard configuration, never on the command line; Ante logs no value.
48
+
49
+ ## Sign-up review and the default offering
50
+
51
+ - **Sign-up review** is opt-in (`Ante:Registration:Review`, off by default): Ante holds each sign-up until the host decides. Read [sign-up review](references/sign-up-review.md) before turning it on or handling `OrganizationRegistrationAwaitingReview`.
52
+ - **The default offering** starts each new tenant on the offer the product declared, through Box Office. Read [default offering](references/default-offering.md) before wiring `IDefaultOffering` or diagnosing a tenant without seats or modules.
53
+ - `InvitationRejected` is a host configuration problem, never a message to the invitee; only `OrganizationRegistrationDeclined` says a person was turned down.
54
+
55
+ ## Development mode is for local runs only
56
+
57
+ `Ante:Onboarding:Development:Enabled=true` generates a 2048-bit RSA signing key per data volume and
58
+ needs no secret. Ante refuses to start when the environment name is production-like (`Production`,
59
+ `Prod`, `Live`, `Staging`, `Stage`, `Preprod`), in a Kubernetes pod, or when a configured URL is not
60
+ loopback. Never copy a development key to another environment, and leave `Secrets:SigningKeyFile` out of a development run.
61
+
62
+ Locally, `cratis run` on a model with `onboarding` starts Ante this way: `ASPNETCORE_ENVIRONMENT`
63
+ is `Development` and `Ante:Onboarding:Development:Enabled` is `true`, so Ante generates its signing
64
+ key into a folder that lives only for the run. It shares AuthProxy's network stack, so AuthProxy
65
+ reaches it on loopback, and the lobby is served through AuthProxy. Nothing from a local run is
66
+ trusted by another run or cluster.
67
+
68
+ ## Stage Manager `Performance`
69
+
70
+ A `Performance` (`showrunner.cratis.io/v1alpha1`) runs one application in one Cratis environment,
71
+ with its AuthProxy when the application has `authentication` and its own Ante when it has
72
+ `onboarding`. Read [Performance resource](references/performance.md) to write or review the spec.
73
+
74
+ - The environment file is supplied as a ConfigMap key (the file `cratis` keeps in `.cratis/environments/<name>.yaml`); a passphrase environment names a Secret for the passphrase. Vault access belongs to the operator's identity, set in the chart, not the Performance.
75
+ - **A resolved value reaches a container only as a file in a mounted Secret volume**: never an environment variable, a ConfigMap, the status or the operator log.
76
+ - Nothing is created until everything is in hand. A missing environment key makes the phase `Blocked` and lists the keys in `status.missingEnvironmentKeys`; running Deployments are left alone.
77
+ - AuthProxy is the only ingress target; the application and Ante are ClusterIP Services behind it.
78
+ - The operator generates and rotates the invitation and attestation signing keys (`spec.signingKeys.rotation`) and derives the issuers, audiences and URLs, so none of them is written twice.
79
+
80
+ ## Pitfalls
81
+
82
+ - Treating `Accepted` as provisioned: provisioning is the application's, and must be idempotent.
83
+ - Setting a signing key or provider secret as an environment variable in a manifest: use the mounted files.
84
+ - Two Ante instances for one application, or one Ante shared by several Performances: one Ante per Performance, with its own event store (`ante-<name>` by default).
85
+ - Answering `InvitationRejected` with a message to the invitee: fix the invitation or host configuration instead.
86
+ - Using development mode in a shared cluster: Ante refuses; do not work around the guard.
87
+
88
+ ## Verify
89
+
90
+ 1. The model compiles and `screenplay environment <folder>` lists the keys; `cratis config --missing <folder> -e <name>` exits `0`.
91
+ 2. `kubectl get performance <name> -o jsonpath='{.status.phase}'` is `Ready`; `-o jsonpath='{.status.missingEnvironmentKeys}'` is empty.
92
+ 3. An invitation for a persona outside the model is rejected with `PersonaNotGrantable` and issues no token.
93
+ 4. No secret value appears in a manifest, the status, a log or the transcript (`kubectl get -o json` on pods or secrets is forbidden by the secrets rule; project fields instead).
94
+
95
+ ## Route near misses
96
+
97
+ - The model's `onboarding` block and environment keys: `cratis-screenplay-authentication-and-onboarding`.
98
+ - Environment commands and secrets providers: `cratis-environments-and-secrets`.
99
+ - Sending the emails: `cratis-showrunner-herald`.
100
+ - Box Office offers, seats and entitlements beyond the default offering: Showrunner's Box Office documentation; this corpus covers only starting a tenant on the default offering.
101
+ - Ante used by a host product, not a Screenplay application: Ante's own documentation; this corpus does not cover it.
102
+ - Chronicle itself in a cluster: `cratis-chronicle-hosting`.
@@ -0,0 +1,31 @@
1
+ # Ante onboarding keys
2
+
3
+ Configuration keys under `Ante:Onboarding:` when `Enabled` is `true`. Each value maps onto the
4
+ ordinary key shown and wins over it. In environment-variable form use `__` for `:`.
5
+
6
+ | Key | Type | Maps to | Notes |
7
+ |---|---|---|---|
8
+ | `Enabled` | bool | none | Applies the contract. Default `false`. |
9
+ | `HostStore` | string | `Ante:HostStores` (one entry) | The application's own Chronicle store. Required unless development mode (then `Application`). |
10
+ | `EventStore`, `Namespace` | string | `Ante:EventStore`, `Ante:Namespace` | Optional. Ante's own store and fixed namespace. |
11
+ | `PublicBaseUrl` | absolute URL | `Ante:Invitations:Token:PublicBaseUrl` | Where users reach this Ante. HTTPS, or HTTP on loopback. |
12
+ | `ApplicationUrl` | URL | `Ante:HostAppUrl` | Where people go when onboarding completes. |
13
+ | `SignUp` | `CreateTenant` or `JoinTenant` | `Ante:Registration:Enabled` | `JoinTenant` closes `/register`. |
14
+ | `RegistrationEnabled` | bool, default `true` | `Ante:Registration:Enabled` | Always off when `SignUp` is `JoinTenant`. |
15
+ | `InvitationTypes` | list | none (runtime check) | `JoinTenant`, `CreateTenant`; unset allows both. |
16
+ | `Personas` | list | none (runtime check) | Grantable personas; ordinal comparison; unset or empty accepts any role. |
17
+ | `DefaultLocale`, `AllowedLocales` | string, list | `Ante:DefaultLocale`, `Ante:SupportedLocales` | |
18
+ | `Legal:Folder`, `Legal:TermsAndConditions`, `Legal:PrivacyPolicy` | paths | `Ante:Legal:Source=Files`, `Ante:Legal:Files:*` | Omit `Legal` for no legal step. |
19
+ | `Secrets:Path` | folder | any key | One file per setting, named like the key with `__` for `:`; trailing newline removed; names starting `.` skipped. |
20
+ | `Secrets:SigningKeyFile` | file path | `Ante:Invitations:Token:PrivateKeyPem` | PEM RSA private key, at least 2048 bits. |
21
+ | `Secrets:VerificationKeyFile` | file path | `Ante:Invitations:Token:PublicKeyPem` | Optional extra trusted public key. |
22
+ | `Development:Enabled`, `Development:DataPath` | bool, folder | none | Local runs only; see `SKILL.md`. |
23
+
24
+ The same instance still needs `Cratis:Chronicle:ConnectionString` and `Cratis:MongoDB`, normally
25
+ supplied by the Cratis environment. Attested-exchange settings, `Issuer`, `Audience` and `Expiry`
26
+ stay under `Ante:Invitations`.
27
+
28
+ Legal terms from files: the version is `sha256-` plus the first 16 hex characters of a SHA-256
29
+ over both bodies. The set is read on every request, so a changed mounted file applies without a
30
+ restart. Acceptance is recorded and published as `LegalTermsAccepted` carrying that version; Ante
31
+ does not publish `LegalDocumentSetActivated` for a file set.
@@ -0,0 +1,61 @@
1
+ # Default offering
2
+
3
+ Requires Showrunner 1.13.0 or later (`Cratis.Showrunner.BoxOffice`) for `DefaultOffering`,
4
+ `IDefaultOffering` and an event store taken from the host. Older releases have neither.
5
+
6
+ A product that sells itself starts a new tenant on its default offering without waiting for the
7
+ operator. The product decides, the operator is told, and a later operator decision replaces it.
8
+
9
+ ## Declare it
10
+
11
+ ```csharp
12
+ builder.Services.AddBoxOfficeOffering(offering => offering
13
+ .Product(productId)
14
+ .Seats(SeatLicensing.PerUser)
15
+ .DefaultOffering("Starter"));
16
+ ```
17
+
18
+ The name is the offer in the operator's catalog. The declaration is reported once per change as
19
+ `DefaultOfferingDeclared`, so the operator knows which offer new tenants start on. A declaration
20
+ that cannot be sold throws `InvalidOffering` at startup, one sentence per problem.
21
+
22
+ ## Start a tenant
23
+
24
+ Call `IDefaultOffering.StartTenant(tenant, organization)` when the product has created the tenant.
25
+ It finds the named offer among the offers the operator published and does two things:
26
+
27
+ - records `TenantStartedOnDefaultOffering` in the tenant's own stream, so the tenant has the offer's
28
+ included seats and modules at once, with no trial;
29
+ - publishes `TenantStartedOnOffer` to the operator, with the offer's name, included seats and
30
+ modules.
31
+
32
+ A later operator decision such as `SeatCapacitySet` or `ModuleRevoked` supersedes what the tenant
33
+ started with: the newest decision wins.
34
+
35
+ ## Failures
36
+
37
+ | Failure | Meaning | Action |
38
+ |---|---|---|
39
+ | `DefaultOfferingNotDeclared` | The product declared no default offering. | Add `DefaultOffering(...)`. |
40
+ | `DefaultOfferingNotPublished` | The operator has not published an offer with that name, or withdrew it. The name compares ignoring case. | Publish the offer; retry. |
41
+ | `TenantNotStarted` | The tenant could not be started. | Read the reason; retry. |
42
+
43
+ The catalog arrives after the product starts, so a name is checked when a tenant starts, not at
44
+ startup. Nothing is published on a failure. Starting the same tenant again, also from another
45
+ instance, returns `TenantStart.AlreadyStarted` and publishes nothing; if the product stopped
46
+ between the two facts, starting again completes what is missing. A different default later does
47
+ not restart a tenant.
48
+
49
+ ## Event store
50
+
51
+ Herald, Box Office and the offering record in the host application's own event store in a host set
52
+ up with `AddCratis` or `AddCratisChronicle`; nothing needs naming. Set `HeraldOptions.EventStore`,
53
+ `BoxOfficeOptions.EventStore` or `OfferingOptions.EventStore` only to use another store. A host that
54
+ registers only the Chronicle client uses the name in `ChronicleClientOptions.EventStore`.
55
+
56
+ ## Verify
57
+
58
+ 1. After the operator publishes the offer, `StartTenant` for a new tenant publishes
59
+ `TenantStartedOnOffer`; a second call returns `TenantStart.AlreadyStarted`.
60
+ 2. Before the offer is published, `StartTenant` throws `DefaultOfferingNotPublished` and publishes
61
+ nothing.
@@ -0,0 +1,86 @@
1
+ # Performance resource
2
+
3
+ ```yaml
4
+ apiVersion: showrunner.cratis.io/v1alpha1
5
+ kind: Performance
6
+ metadata:
7
+ name: crm
8
+ namespace: apps
9
+ spec:
10
+ productionRef:
11
+ name: ledger
12
+ chronicle:
13
+ connectionSecretRef:
14
+ name: chronicle-connection
15
+ application:
16
+ image: registry.example.com/crm:1.0.0
17
+ eventStores: [Crm]
18
+ environment:
19
+ name: production
20
+ configMapRef:
21
+ name: crm-environment
22
+ passphraseSecretRef:
23
+ name: crm-passphrase
24
+ authProxy:
25
+ enabled: true
26
+ providers:
27
+ - kind: EntraId
28
+ identity: EntraId
29
+ onboarding:
30
+ enabled: true
31
+ signUp: CreateTenant
32
+ personas: [Administrator, Member]
33
+ legal:
34
+ configMapRef:
35
+ name: crm-legal
36
+ ingress:
37
+ enabled: true
38
+ className: nginx
39
+ hosts: [crm.example.com]
40
+ tlsIssuer:
41
+ name: letsencrypt
42
+ ```
43
+
44
+ ## Fields that decide behavior
45
+
46
+ - Chronicle: `chronicle.connectionSecretRef` (an existing Secret) takes precedence over `productionRef`. The Secret is mounted as a file, never copied. `application.eventStores[0]` is the store Ante observes.
47
+ - `environment.configMapRef` holds `<name>.yaml` unless `key` says otherwise. `passphraseSecretRef` is only for a passphrase environment. Azure Key Vault uses the operator's workload identity; HashiCorp Vault uses Kubernetes auth with the operator's service account and `VAULT_K8S_ROLE`; both are chart values.
48
+ - `authProxy.providers` carry kind and identity only, matching the model. `onboarding` carries `signUp`, `personas` and legal files; every value comes from the environment.
49
+ - `onboarding.attestedProviders` set: Ante runs attested invitation exchange against AuthProxy's attestations; unset keeps the legacy exchange.
50
+
51
+ ## Created resources (for a Performance named `crm`)
52
+
53
+ | Resource | Name | Notes |
54
+ |---|---|---|
55
+ | Deployment and Service | `crm-app`, `crm-authproxy` (when enabled), `crm-ante` (when onboarding) | ClusterIP; Ante has one replica. |
56
+ | Ingress | `crm` | Every host routes to AuthProxy only; certificate from cert-manager. |
57
+ | Secrets | `crm-app-environment`, `crm-authproxy-environment`, `crm-ante-secrets`, `crm-signing-keys` | Mounted content and generated keys. |
58
+
59
+ AuthProxy gets one file per environment key it needs in `/run/secrets/cratis`; Ante gets one file
60
+ per setting (`__` for `:`) in `/run/secrets/ante`; the application gets the remaining keys in
61
+ `/run/secrets/cratis`. Pods roll when mounted content changes, via a keyed hash annotation that
62
+ reveals nothing about a value. Ante's own MongoDB server comes from the environment key `ante.mongodb.server`.
63
+
64
+ ## Status
65
+
66
+ | Field | Meaning |
67
+ |---|---|
68
+ | `phase` | `Pending`, `Blocked`, `Progressing` or `Ready`. |
69
+ | `publicUrl` | `https://` and the first ingress host. |
70
+ | `missingEnvironmentKeys` | Keys the environment lacks while `Blocked`. |
71
+ | `conditions` | `SpecValid`, `ChronicleConnection`, `EnvironmentResolved`, `EnvironmentComplete`, and per component `ApplicationReady`, `AuthProxyReady`, `AnteReady`. |
72
+ | `signingKeys` | Key ids in use, rotation counter applied, previous public keys pinned. |
73
+
74
+ Conditions and status never contain a secret value. An unresolved environment is reported in
75
+ `EnvironmentResolved` with a message naming the key and the provider.
76
+
77
+ ## Signing keys
78
+
79
+ The operator generates the key Ante signs invitations with and the key AuthProxy signs
80
+ attestations with, in `crm-signing-keys`. Raise `spec.signingKeys.rotation` to rotate both. The
81
+ public half of each replaced key stays pinned (`signingKeys.retainPrevious`, two by default), so
82
+ Ante verifies invitations signed with a previous key.
83
+
84
+ Routing `/_invite` and `/.well-known/ante` from AuthProxy to Ante is configured on AuthProxy's
85
+ side; set `onboarding.lobbyBackendBaseUrl` in the environment when needed. Other Stage Manager
86
+ resources (`Production`, `Understudy`, `Restore`, `Rehearsal`, `BackstagePass`, `ControlRoom`) are schema only; nothing acts on them.