Skip to main content
Two things explain most of Noorle’s shape: requests are dispatched by hostname, and the agent loop runs in the control plane, outside every sandbox.

Host-based routing

One server accepts every request and inspects the Host header to decide which service handles it. The two gateway hosts are the only wildcard matches. The match requires a dot before the base domain, so a lookalike apex cannot slip into gateway dispatch.
The Portal is the web UI — the SPA and the JSON backend that serves it are the same host.

Where the agent loop runs

This is the load-bearing architectural fact, and the one most often misread. The control plane is the agent loop. Model routing, memory, tool dispatch, the journal, autonomy decisions, scheduling, multi-agent coordination — all of it runs in the host process, outside every execution sandbox. An agent has no path back into the control plane. It cannot reconfigure itself, escalate its own permissions, or reach another tenant’s resources, because it is not running anywhere that could. It requests capabilities through the loop, and the loop decides. Execution happens in tiers the loop calls into. None of them is “the runtime”; the loop picks per workload. A broker daemon runs on a Computer, but it is only a broker: it executes what the control plane sends it. It is not the agent loop.

Request path for a tool call

Every capability call, from every surface, converges on the same path. Two properties worth stating plainly: Executing a capability requires a witness the admission door is the only thing that can produce. A dispatch path that skipped the door would not compile. This is enforced by the type system, not by discipline. A policy read failure denies. There is no last-known-good fallback for invocation policy, deliberately — a fallback would be a back door to failing open.

Data

The journal split matters. SlateDB is authoritative; ClickHouse is derived. A ClickHouse outage degrades query surfaces and returns a typed error — it does not stop the agent loop, because strict context reads never touch it. ClickHouse can be truncated and re-derived from the journal. Likewise Qdrant is a projection: Postgres holds curated memory authoritatively, and recall falls back to a keyword search when the vector index is unavailable.

Multi-tenancy

Every resource carries an account id, and every repository query is floored on it. Authority is evaluated above that floor by a dedicated layer that sits between the domain and the runtime — handlers do not decide authorization themselves; they build an identity context and call a management service that re-reads role and grants per operation. An authority denial is a 403. A row that does not exist under the tenancy floor is a 404 — validation runs only after authority, so a denied caller cannot probe for what exists.

Identity

Identity is issued by a separate auth server at auth.noorle.com, with its own database that no product code reads. It is the sole issuer for every principal type: humans at first login, and service and agent principals on request. Both databases use the same UUID for the same identity — there is no mapping table. API keys are not boundary-issued; they are platform-local. If the identity boundary is unavailable, sign-in fails, but API-key verification is unaffected. See Authentication.

What this design buys you

Capability escape does not become platform escape. The most dangerous code — your plugin, an agent’s shell command — runs furthest from the decision-making. Autonomy policy cannot be prompted away. The gate is not an instruction to the model; it is a code path the call has to survive. History survives infrastructure loss. The conversation rebuilds from an object-store-backed journal, not from a cache and not from the analytics store.
Next: Use cases for shapes that compose well out of this.