Policy Schema Export Automation
Audience: developers and release engineers who maintain the Policy Engine run contracts and the generated JSON Schema documents under
docs/schemas/. TL;DR: runstella tools policy-schema-export(or the standalone exporter) to regenerate the schemas; there is no active CI job that does this for you today — see CI integration.
This utility generates JSON Schema documents for the Policy Engine run contracts (PolicyRunRequest, PolicyRunStatus, PolicyDiffSummary, PolicyExplainTrace).
Reconciliation note (verified against
src/on 2026-05-30): the exporter is a .NET command-line tool, not a shell script. The historicalscripts/export-policy-schemas.shreferenced by older docs does not exist in the repository, and the CI job that invoked it now lives under.gitea/workflows-archived/(i.e. it is not an active workflow). Sections below are marked where they describe archived/roadmap behavior rather than live automation.
Command
The exporter ships as the policy-schema-export subcommand of the StellaOps CLI tools group (src/Cli/StellaOps.Cli/Commands/ToolsCommandGroup.cs):
stella tools policy-schema-export [--output <dir>] [--repo-root <dir>]
Options (from src/__Libraries/StellaOps.Policy.Tools/PolicySchemaExporterCommand.cs):
--output/-o— output directory for the schema files.--repo-root/-r— repository root used to resolve the default output path.
The command logic (option parsing, the policy-schema-export verb, and the export Runner) all live in the shared StellaOps.Policy.Tools library (src/__Libraries/StellaOps.Policy.Tools/), which both the CLI subcommand and the standalone tool reference.
A standalone executable equivalent is also available at src/Tools/PolicySchemaExporter/ (entry point Program.cs calls PolicySchemaExporterApp.RunAsync):
dotnet run --project src/Tools/PolicySchemaExporter -- [--output <dir>] [--repo-root <dir>]
When no --output directory is supplied, schemas are written to the repo’s docs/schemas/ directory (see PolicySchemaExporterPaths.ResolveDefaultOutputDirectory, which resolves <repo-root>/docs/schemas). The repo root is located by walking up until src/Directory.Build.props is found; if it cannot be resolved and no --output is given, the tool exits with code 64 (EX_USAGE). If the resolved output directory cannot be created (e.g. the path is an existing file, or directory creation throws), the tool exits with code 73 (EX_CANTCREAT).
The exporter builds schemas against StellaOps.Scheduler.Models (PolicySchemaExporterSchema.BuildExports) and emits:
policy-run-request.schema.json(PolicyRunRequest)policy-run-status.schema.json(PolicyRunStatus)policy-diff-summary.schema.json(PolicyDiffSummary)policy-explain-trace.schema.json(PolicyExplainTrace)
Schemas are generated with NJsonSchema (SchemaType.JsonSchema) using camelCase property names, additionalProperties: false (AllowAdditionalProperties = false), and NullValueHandling.Ignore. Each generated schema’s title is set to the source type name, and each file is written with a single trailing \n (LF, not CRLF — asserted by PolicySchemaExporterRunnerTests.RunAsync_WritesLfLineEndingsAsync).
CI integration (ARCHIVED — not currently wired)
Status: not active. The job below was defined in
.gitea/workflows-archived/build-test-deploy.yml(job step Export policy run schemas) and is no longer part of the active.gitea/workflows/set. It also invokesscripts/export-policy-schemas.sh, which is missing from the repo, so the archived job would fail if re-enabled as-is. The description is retained for historical context and as the basis for any future re-implementation.
As archived, the job:
- Exported schemas to
artifacts/policy-schemas/<commit>/. - Diffed each generated file against the committed copy under
docs/schemas/and wrote a unified diff topolicy-schema-diff.patchwhen any file changed. - Published the
policy-schemasdirectory as thepolicy-schema-exportsartifact. - On a detected change, posted a Slack message via the
POLICY_ENGINE_SCHEMA_WEBHOOKsecret/variable (the target channel is determined by the webhook configuration and is not encoded in the workflow).
CI integration checklist
The following reflects current source reality, not the archived workflow’s checkboxes:
- [ ] Invoke the exporter in an active DevOps pipeline. (Was wired in the archived
build-test-deploy.yml; the active.gitea/workflows/set does not run it. The referencedscripts/export-policy-schemas.shdoes not exist.) - [ ] Publish the generated schemas as pipeline artifacts. (Archived only.)
- [ ] Notify downstream consumers when schemas change (Slack via
POLICY_ENGINE_SCHEMA_WEBHOOK). (Archived only.) - [ ] Gate CLI validation once schema artifacts are available. (Not implemented.)
Note: As of this reconciliation the four generated
*.schema.jsonfiles are not committed underdocs/schemas/(onlypolicy-pack-v2.schema.jsonis present there), so a fresh export will create them. Verify the intended commit location before wiring any diff-based gate.
