---
title: Tenancy
description: Organization, workspace, environment — the hierarchy every other resource hangs off, and the isolation guarantee behind it.
---

Three levels, and everything else in Veefore is reachable only through them.

```text
Organization                 the tenant boundary
└── Workspace                a team or product area
    └── Environment          development / staging / production
        ├── Agents
        ├── Tools and credentials
        ├── Policies and delegations
        └── Actions and audit
```

## Organization

The tenant boundary. Created in the same transaction as its first owner, so
there is no window in which an organization exists with nobody able to
administer it.

An organization owns its members, roles, SSO and SCIM configuration, network
restrictions, billing, and every resource below it.

:::security The organization is the isolation boundary
Every query in the data layer is scoped to an organization, and the scoping is
not something an individual query opts into — the repository layer requires a
tenant scope and refuses without one.

Crossing it needs an explicit, named justification in code, which background
jobs use and request handlers do not. A request that somehow reaches a resource
in another organization is refused with `TENANT_MISMATCH` rather than returning
`404`, so the attempt is distinguishable in the audit trail from a typo.

Row-level security is available as a second, independent layer —
`DATABASE_ENABLE_RLS` — so a bug in application-level scoping does not become a
data leak. See [Tenant isolation](/secure/tenant-isolation).
:::

## Workspace

A team or a product area. Workspaces divide an organization without dividing its
identity: members, roles and SSO are organization-wide, while agents, tools and
policies belong to a workspace.

The practical reason to have more than one is scoped access. A role grant can be
limited to a workspace, so the payments team's developers operate payments
agents and cannot touch the logistics team's.

## Environment

Where the enforcement mode lives. Three types: `DEVELOPMENT`, `STAGING`,
`PRODUCTION`.

```bash
curl -X POST https://veefore.example.com/v1/environments \
  -H "Authorization: Bearer $VEEFORE_API_KEY" \
  -H 'content-type: application/json' \
  -H 'Idempotency-Key: create-payments-prod' \
  -d '{
    "workspace_id": "wsp_01JAV…",
    "name": "Payments production",
    "type": "PRODUCTION"
  }'
```

An agent belongs to exactly one environment. An identity provisioned in staging
cannot act in production — not because a policy forbids it, but because the
agent is not there. That is a stronger guarantee than a rule, because it cannot
be misconfigured away.

`environment.type` is a policy field, which is how you write rules that apply to
production specifically:

```json
{
  "kind": "condition",
  "id": "c-prod",
  "field": "environment.type",
  "operator": "eq",
  "value": "PRODUCTION"
}
```

## Scope headers

Session-authenticated requests carry the active scope in headers:

```http
GET /v1/agents
Authorization: Bearer aos_sk_…
x-veefore-workspace: wsp_01JAV7YQ4T2K9M3E8H6R5N1XZ0
x-veefore-environment: env_01JAV7YQ4T4ZC1P8W2M6B9K3QD
```

Omit them and you get the organization-wide view, subject to your permissions.
Supply a scope you have no access to and the request is refused.

The console sets these from the scope switcher. The CLI sets them from
`veefore.config.json`.

## Policy binding scope

A policy is bound at one of five levels:

| Scope | Applies to |
| --- | --- |
| `ORGANIZATION` | Everything in the tenant |
| `WORKSPACE` | Everything in one workspace |
| `ENVIRONMENT` | Everything in one environment |
| `AGENT` | One agent |
| `TOOL` | One tool |

All in-scope policies are evaluated together, and the strictest decision wins.
See [Policy](/concepts/policy#precedence-the-part-to-read-twice).

:::danger Bind deny-by-default policies narrowly
A policy with `"defaultDecision": "BLOCK"` bound to an entire environment denies
**everything** in that environment, because every other policy's `ALLOW` loses
to it. Strictest wins, regardless of priority.

This is a real and easy mistake to make — a deny-by-default database guardrail
bound to a whole production environment will make every unrelated agent in it
unreachable, and the symptom is "nothing works" with no obviously relevant rule.
Bind deny-by-default policies to the `AGENT` or `TOOL` they are meant to
constrain.
:::

## Lifecycle controls

```bash
# Stop all protected execution in an environment. Immediate.
curl -X POST https://veefore.example.com/v1/environments/env_01ABC/pause \
  -H "Authorization: Bearer $VEEFORE_API_KEY" \
  -H 'content-type: application/json' \
  -d '{ "reason": "Investigating anomalous refund volume" }'
```

`environment:pause` is high impact and step-up gated. A paused environment
refuses every protected action with `ENVIRONMENT_PAUSED`. This is the correct
emergency control — not dropping the mode to `OBSERVE`, which stops refusing
anything.

## Shape it for how you work

A common arrangement:

```text
Acme Payments (organization)
├── Payments (workspace)
│   ├── Development   SIMULATE
│   ├── Staging       ENFORCE
│   └── Production    ENFORCE
└── Logistics (workspace)
    ├── Development   SIMULATE
    └── Production    ENFORCE
```

Two rules of thumb. One organization per tenant — do not use organizations to
separate your own teams, because that fragments members, roles and audit. And
a separate environment per deployment tier, so enforcement mode and agent
identity are never shared across tiers.

## Related

:::cards

:::card Tenant isolation | /secure/tenant-isolation
The guarantee, the enforcement layers and the tests behind it.
:::

:::card RBAC | /secure/rbac
Roles, permissions and scoped grants.
:::

:::card Enforcement modes | /concepts/enforcement-modes
The setting that lives on the environment.
:::

:::card Tenancy API | /reference/api/tenancy
Organizations, workspaces, environments, mode and pause.
:::

:::
