Tenant
Every runtime is scoped to exactly one tenant. define_tenant(...) creates the identity serialized into RuntimeSpec; the Rust runtime (flowai-runtime) uses it as the isolation key...
Every runtime is scoped to exactly one tenant. define_tenant(...) creates the identity
serialized into RuntimeSpec; the Rust runtime (flowai-runtime) uses it as the isolation
key for everything it stores and serves.
from flowai_harness import define_tenant
tenant = define_tenant("acme", "v1")
tenant.model_dump(by_alias=True, mode="json")
# {"resourceId": "acme", "version": "v1"}Pick a stable resource_id from trusted auth or deployment configuration; do not derive it
from a user prompt.
What tenancy isolates
resource_id namespaces everything the runtime persists or guards:
- Runtime storage — the runtime's KV state (references, plans, pending-approval audit records, caches) is keyed by tenant, so two tenants sharing one store never read each other's entries.
- References — reference ids are content hashes salted with the tenant, and every resolve checks the stored owner. A handle leaked across tenants resolves to "not found" rather than to another tenant's payload.
- Plans — plans are stored and loaded per
(tenant, plan_id). Cross-tenant loads also return "not found", so the existence of another tenant's plan is never disclosed. - Requests — every query is checked against the handle's tenant. There is no per-call tenant override; a mismatched request is rejected.
- Data-environment scope — if
data_environmentdeclares atenant_id, runtime construction rejects it unless it matches the runtime tenant.
Telemetry and trace events are recorded per runtime handle, and each handle is bound to a single tenant.
What tenancy does not isolate: the topology itself. Agents, prompts, tools, and provider
configuration are properties of the RuntimeSpec you build — runtimes created from the same
spec for different tenants run the same agents. Per-tenant behavior belongs in the spec you
construct for that tenant, not in the identity.
version semantics
The second field, version, labels the revision of the tenant identity. It must be a
non-empty string and is serialized with the spec, so it shows up wherever the runtime spec is
dumped or inspected. It does not participate in storage keying: changing "v1" to "v2" does
not repartition or invalidate stored references, plans, or approval records — the tenant still
sees all state keyed by its resource_id. Use it to record which revision of your tenant
configuration built a given runtime.
Tenant is not prompt content
Tenant identity is runtime routing metadata. It is not automatically rendered into system
prompts. Put business vocabulary, domain facts, or operating assumptions in
layered_prompt(domain_knowledge=...) instead:
domain_knowledge = {
"entities": ["product", "segment", "channel"],
"metrics": ["revenue", "margin"],
}This separation keeps tenancy inspectable and security-relevant while keeping prompt content customer-defined and domain-specific.
See also
- Runtime —
define_runtime(tenant=...)and the single-tenant handle. define_tenantreference
Concepts
The harness is a spec-and-callback boundary. Python describes the agent topology with validated Pydantic models and provides callback handlers for tools and approvals; the Rust...
Agents
The harness exposes four agent roles, each constructed with a dedicated define_* helper that returns a frozen AgentSpec.
