The rename is vocabulary at the product layer. The physical tables are unchanged:
an organization is a
companies row and a child project is a tenant_users row,
so company_id, tenant_user_id, /v1/company and /v1/users/:user_id/... all
keep working. Only projects is new.The default project
Created for each organization by migration059, which also backfilled every
pre-existing account kit, child project, connection, vault entry, approval,
activity event, and agent into it. An organization created before the migration
and never touched since gets its default project lazily, on first read.
The default project is not deletable and not archivable. It is where every
un-projected caller lands, so removing it would strand the organization.
A row whose project_id is NULL belongs to the default project. The column is
nullable on purpose (nothing that writes these tables is required to know about
projects yet), so a write from an un-taught path lands as NULL and is still
visible exactly where its organization can see it — never invisible, never
another project’s.
Selecting a project
Five ways, in this order:- The path —
/v1/projects/:project_id/...in front of any data-plane route./v1/projects/<id>/users/<child_id>/vaultis/v1/users/<child_id>/vaultscoped to that project. - The
X-Naive-Project-Idheader — same effect without changing the route. Treated as untrusted input and validated against the key’s organization, like any path param. - The API key’s pinned project (
active_project_id), set when the key is created. - The project of the key’s sealed child project, if it is sealed to one —
what makes a key sealed into a non-default project usable without also
pinning the project. A child project named in the path does not select
a project this way: naming a child of another project without selecting that
project is a
404, not a door into it. - The organization’s default project.
default and current mean the caller’s own project: the
key’s pinned project when it has one, otherwise the organization’s default
project. They are a way to decline to name a project, not a way to name the
default one — a pinned key writing default still acts inside its pin.
The cross-project guard
Subject resolution now asserts both axes. After resolving a candidate child project, the resolver requires:What is project-scoped, and what is organization-wide
Deployments were already namespaced by
(organization, project) before this
layer existed — the IaC project: string is the same project key, now first-class.
See Infrastructure as code.
Using it
naive.forUser(id), naive.users, naive.accountKits,
naive use <child_project_id>, /v1/users/..., /v1/company, and MCP tools
called with user_id alone.
See Projects (getting started) for the walkthrough.