> ## Documentation Index
> Fetch the complete documentation index at: https://docs.phoneuse.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Org isolation

> Where the boundary between orgs runs, and what enforces it.

The **org** is the unit of isolation. An org owns its devices, its
credentials, its leases, its receipts and its usage. Nothing crosses between
orgs, and this page describes what makes that true rather than merely
intended.

An operator is a person who belongs to one or more orgs. An agent acts on
behalf of an org with a credential issued for it. Neither one owns anything:
the org does.

## Org context comes from the request

Every request resolves to exactly one org, at the entry point, once.

There is no process wide notion of a current org. There never has been, and
the service is built so that there cannot be: an org identifier is a checked
value rather than a bare string, so an unvalidated value cannot reach a query
or a storage key by accident. From the entry point onward the org travels as an
explicit parameter into every call.

Where it comes from depends on the credential:

* **An OAuth token** carries the org in a claim, using the same claim name the
  database's own policies read.
* **An API key** is issued for exactly one org and resolves to it.

There is no authenticated state without an org. It is not a case the code has
to handle, because the shape of the authorization context does not permit it.

## Two independent guards on the data

Isolation does not rest on one mechanism, because one mechanism has one bug.

**A forced org scope in the application.** Every read and write is scoped to the
resolved org before it reaches the database. A query carrying no org condition
is refused outright rather than left for a reviewer to catch.

**Row level security in the database.** Every table that holds more than one
org's data has policies enabled. Inside the transaction the resolved org is set as a session variable,
and the policies read it.

The control plane connects with a dedicated database role that **cannot**
bypass row level security. This is the detail that makes the two guards
genuinely independent rather than nominally so: if the application layer ever
failed to scope a query, the database would still refuse the rows. Each is the
other's backstop.

The same policy set serves the other application that reads this database,
which reaches it with a different identity and reads the org from its own
token. One set of policies, two callers, no second definition to drift.

## Narrower than an org

An API key can be restricted to a subset of its org's devices. That subset is
applied by filtering the device rows at the entry point, before any surface
sees them, so it narrows **visibility and addressing together**.

The consequence is worth stating plainly: a device outside your key's subset
is not refused, it is not found. There is no oracle telling you that a device
exists but is out of reach. `get_device` reports it as not found, receipts for
it report as not found, and it does not appear in `list_devices`.

The same rule applies across the whole surface. The MCP tools, the REST run
routes and the device channel all resolve devices through one directory built
from the same visibility rules, so they cannot disagree about what a
credential can see.

## Leases are org scoped

A lease binds an org to a device. Acquiring a device that another org holds is
refused, and so is acquiring one that belongs to another org at all, since a
device's ownership is a property of the device's own record.

Leases carry a fencing token, which is what makes a resumed or duplicated
caller lose to the current holder rather than acting on stale authority. You
never handle it: it is issued and checked inside the control plane, and it is
deliberately withheld from anything running outside it.

## Stored objects are prefixed by org

Any object the control plane stores for you is written under a prefix derived
from your org id. Cross org read paths are not merely unauthorized, they are
not expressible as a key.

That is also why an org id is validated rather than trusted. Control
characters, path separators and dot segments are rejected when the id is
parsed, so a value that could escape a prefix cannot be constructed in the
first place.

## The device boundary

The control plane never speaks to hardware directly. It does not open a debug
bridge, a serial port or a camera. Everything goes through a device gateway
protocol.

That boundary exists for isolation, and it is also the seam along which a
private deployment becomes possible: the gateway is the part that could one
day run in your environment while the control plane stays where it is. That
deployment shape is not built. What is guaranteed today is that the boundary
is clean enough to keep it possible.

## Local mode

Local mode is a single org on a single machine, on loopback, with no shared
database. It resolves to a constant local org rather than to a mutable global,
so the request pipeline has the same shape it has in a hosted deployment.

Do not read local mode's convenience as a permission model. It grants every
scope to whoever can reach the port, which is exactly why it refuses to bind
anywhere but loopback.

## Related

<Columns cols={2}>
  <Card title="Authentication" href="/mcp/auth">
    How a credential resolves to an org and a set of scopes.
  </Card>

  <Card title="Frame retention" href="/security/frame-retention">
    What happens to captured screens.
  </Card>
</Columns>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.