Appearance
Plans, entitlements and module licences
Keel is one platform with licensed modules (Platform and modules). What a tenant can use comes from its entitlements: the features and limits of its plan (Team, Business or Enterprise) plus its add-ons. The shared core and Keel Semantic's modeling are always on; serving (REST endpoints, the SQL interface and MCP), governance and SSO come with Business and Enterprise; the private agent pools with Enterprise; Keel Migrate (migrate) is an add-on.
Where entitlements come from
| Source | How | Who |
|---|---|---|
| Trial | Every new tenant gets 14 days of Business | Automatic at sign-up |
| Self-serve | Team or Business bought in Settings › Billing (Stripe checkout), add-ons toggled there | Tenant Owners |
| Contract | Enterprise, or an add-on granted by contract; invoiced outside Stripe | The platform operator |
When a trial ends without a plan, or a subscription is canceled, the tenant becomes read-only: people can still sign in, read and export, but changes are refused (Billing.ReadOnly) until an Owner chooses a plan. Nothing is deleted; data is kept at least 30 days.
Grant or revoke a module by contract
Only the platform operator grants contract entitlements. There is no HTTP endpoint for it, and tenant Owners can't grant add-ons themselves (they buy them). Run the API host's licence verb with the deployment's own configuration and database access:
bash
dotnet run --project src/Keel.Api -- licence grant --tenant <slug> --module migrate
dotnet run --project src/Keel.Api -- licence revoke --tenant <slug> --module migrate
# or, from a published build:
dotnet Keel.Api.dll licence grant --tenant <slug> --module migrate--tenanttakes the tenant's slug, and--moduletakes a licensable module (today onlymigrate).- The command applies database migrations first, so it also works on a fresh database.
- It prints
migrate: licensed for <slug>.ormigrate: revoked for <slug>.. It exits with 0 on success, 1 when the change fails (for example an unknown tenant), and 2 with the usage line when the arguments are wrong. - A grant is a contract entitlement: the add-on is added to the tenant's subscription with source Contract, on top of whatever the tenant pays for, and Stripe updates never remove it. Owners see it checked and marked "by contract" on the billing page. Every change is audited in the tenant's log as
Billing.ContractEntitlementChanged.
Tenants that existed before billing was introduced were carried over as Enterprise contracts with the modules they were licensed for.
What an entitlement changes
| Entitled | Not entitled | |
|---|---|---|
| Navigation | Migrations (with a New badge), Serving | Hidden |
API routes (/api/v1/workspaces/{id}/migrations…, /api/v1/serving/…, /mcp/…, the agent's run reports) | Available, subject to permissions | 404, as if they did not exist |
| Module jobs (inference, generation, reconciliation, runs) | Run | Dead-lettered |
GET /api/v1/tenant/modules, GET /api/v1/tenant/entitlements | List it | Don't list it |
Hosts cache a tenant's entitlements for up to 30 seconds (Keel:Billing:EntitlementsCacheTtl); the host that makes a change drops its cache at once, others follow within that time.
Revoking an add-on hides the module and stops its jobs. It doesn't delete the tenant's migration projects.
Usage limits
Plans limit source connections, workspaces, members, serving queries, AI tokens and scans per month. At 80% of a monthly limit, Owners get an email and a banner. At 100%, only two things change: serving endpoints answer 429 with a link to upgrade, and AI suggestions switch to heuristics-only (scans keep running). Nothing is ever deleted because of a limit. Downgrading below current usage is refused with the list of what to remove first.
Local development
The dev demo tenant (Anchor Demo, slug anchor-demo) is seeded as an Enterprise contract with every add-on, both by the AppHost and by dotnet run --project src/Keel.Api -- seed --demo. Use the licence verb to grant another tenant you create locally. Payments are off unless Keel:Billing:Provider is stripe (see the deployment configuration).