Appearance
The demo tenant
The demo seeder builds a complete, governed demo in the Anchor Demo tenant (workspace Sales Analytics) on the local stack, using only Keel's public HTTP API — the same path a person takes, so jobs, workers, checks and the audit log all run for real. It is idempotent: every step reads the current state first and only acts when something is missing, so you can run it again at any time.
Run it
Start the stack first (Run Keel locally). It seeds the tenant, the dev users and the two Chinook sources on start. Then:
bash
scripts/seed-demo.sh # Git Bash / macOS / Linux
pwsh scripts/seed-demo.ps1 # PowerShell
scripts/seed-demo.sh --dry-run # read-only: print what it would doBoth wrappers run dotnet run --project src/Keel.DemoSeeder -- … and pass every argument through. By default the seeder signs in as owner@keel.local / keel through the dev realm's keel-seed client (password grant, dev only — if Keycloak was started before that client existed, restart the AppHost so the realm is re-imported).
At the end it prints one line per step — Created, Updated, Unchanged, Planned (dry run), Skipped or Warning — and, the first time only, the demo API key. Exit code 0 = done, 1 = stopped (with the reason), 2 = bad arguments.
What it creates
| Step | Result |
|---|---|
| Workspace | Finds tenant anchor-demo and workspace "Sales Analytics" through /me. |
| Source | Uses chinook-postgres (or registers one from --register-* options). |
| Scan | Scans the source if it has no successful run and waits for the run and the model generation. |
| Proposals | Accepts undecided proposals with confidence ≥ 0.85. |
| Model | Takes the generated model's change request through checks, acknowledgement of breaking changes, approval and merge. |
| Metric descriptions | Picks the demo metrics (--metrics, or the first two simple metrics that don't end in _count) and, where a description of 20+ characters is missing, adds one on a demo/metric-descriptions-… branch through a change request. |
| Release | Publishes a release unless the latest one is already main's head. |
| Glossary | One approved term per demo metric plus Customer, Invoice and Track, linked to their entities. |
| Ownership | The demo metrics are owned and stewarded by steward@keel.local (Priya Steward). |
| Data quality | Accepts suggested rules (Freshness and VolumeAnomaly stay proposed: the sample data is historical) and runs every rule that never ran. |
| Demo incident | A Critical custom-SQL rule, Demo: no track longer than 10 minutes, whose failing rows open an incident. It is placed on a table that feeds no demo metric, so it never caps their trust. |
| Policy | Applies the default mask_restricted_for_analysts policy (Restricted columns masked for Analysts and Viewers). |
| Lineage | Rebuilds lineage for the model if it has none. |
| Certification | Requests and certifies each demo metric. If a criterion is unmet it reports a Warning naming it — the seeder never fakes certification or relaxes the tenant's criteria. |
| Serving endpoint | chinook-sales on the latest release (SQL shown, 300 s cache, 120 requests/min): /api/v1/serving/chinook-sales and MCP at /mcp/chinook-sales. |
| API key | demo-serving with scopes serving:query and mcp:use. The key is printed once; a rerun says it exists — --rotate-key revokes it and prints a new one. |
| Assistant | Checks the tenant's AI settings and tells you what is missing (the assistant also needs Keel:Llm:ApiKey on the API and worker — see AI features). |
Try the result
bash
export KEEL_API_KEY=keel_live_… # printed by the seeder
curl http://localhost:5080/api/v1/serving/chinook-sales/catalog -H "X-Api-Key: $KEEL_API_KEY"
claude mcp add --transport http keel-demo http://localhost:5090/mcp/chinook-sales --header "X-Api-Key: $KEEL_API_KEY"Then sign in as analyst@keel.local and open the Playground or the Metrics catalog: Restricted columns are masked; sign in as steward@keel.local to see the certified metrics, the incident on Data quality, and the audit trail.
Options
| Option | Default | |
|---|---|---|
--api | http://localhost:5080 | API base URL |
--tenant / --workspace / --workspace-id | anchor-demo / Sales Analytics | Where to seed |
--source | chinook-postgres | Source name |
--model | first model including the source | Model name |
--metrics a,b | two simple metrics | Metrics to describe, own and certify |
--owner-email | steward@keel.local | Owner and steward of the demo metrics |
--no-incident | — | Skip the failing demo rule |
--dry-run | — | Read only; the HTTP client refuses any non-GET request |
--rotate-key | — | Replace the demo API key |
--register-host/-port/-database/-user/-include | — | Register the source if it doesn't exist (password in KEEL_DEMO_SOURCE_PASSWORD) |
| Auth | Keycloak password grant (--authority, --client-id keel-seed, --user owner@keel.local, --password or KEEL_DEMO_PASSWORD) | Or --token / KEEL_DEMO_TOKEN, or --api-key / KEEL_DEMO_API_KEY with --workspace-id |
Tested
Unit tests prove the idempotency rules against a fake API (a second run and a dry run send no mutating request; unmet certification becomes a warning; the key is never re-shown). An integration test runs the seeder end to end against the real API, worker and PostgreSQL, then runs it again and checks that every step is Unchanged.