Run two tenants on one daemon
Multi-tenancy is a first-class primitive. One declaragent daemon process can host N tenants with isolated:
- Session state (
(tenantId, sessionId)is the composite key after slice 0). - Message bus (per-tenant bus strategy — no cross-tenant leaks).
- Extensions (
extensions.allow/extensions.denyper tenant). - Quotas (cost + rate limits per tenant).
- Audit log (separate Merkle chains per tenant).
- Metrics (every Prometheus series gets a
tenant=label).
Minimal setup
Scaffold from the template:
declaragent init --template multi-tenant-starter --multi-tenant --tenant-id acme-prod
Then edit tenants.yaml to add a second tenant:
tenants:
- id: acme-prod
residency: us
extensions:
allow: [slack, kafka]
quotas:
dailyTokenUSD: 100
requestsPerMinute: 1000
- id: beta-tenant
residency: eu
extensions:
deny: [whatsapp]
quotas:
dailyTokenUSD: 5
requestsPerMinute: 60
Verify
declaragent daemon &
declaragent tenants list
declaragent tenants show acme-prod
declaragent tenants show beta-tenant
declaragent tenants diff # shows pending config vs. loaded config
Audit
declaragent audit query --tenant acme-prod --since $(($(date +%s%3N) - 3600000))
declaragent audit verify --tenant acme-prod
declaragent audit verify --tenant beta-tenant
Boundary violations are visible per-tenant:
declaragent audit query --kind tenant_boundary_denied
Key points
- Boundary enforcement. Any attempt to route a message across tenants emits a
tenant_boundary_deniedaudit record + aTENANT_BOUNDARYalert. - Per-tenant metrics labels. Slice 0 auto-stamps
tenant=on every series emitted by the Prometheus exporter. - Independent rotations.
declaragent secrets rotate --tenant <id>scopes the rotation. Other tenants are undisturbed.