Projects
A Project is the isolation scope for sessions and pools — and the durable, developer-declared home for their configuration. It is what keeps one deployment's rooms from colliding with another's: all session and pool names resolve within a Project, never globally. Two clients in Project studio-42 and Project gallery-north that both join a session named "lobby" land in different rooms.
A Project is structural (an isolation scope) and, when provisioned through the control plane, configured — it owns matchmaking policies, credential bindings, and a lockdown flag. Isolation itself needs no credentials; enforcing who may enter a Project is the separate concern of authentication.
Connection-scoped
A connection is bound to exactly one Project, established once during the handshake. The client declares it up front and never repeats it — the Project is not a per-frame field, so a client cannot reach another Project by altering a message after connecting.
import { StarfishClient } from "@starfish/client";
// Declare the Project at construction…
const client = new StarfishClient({
server: "ws://localhost:4000",
project: "studio-42",
});
await client.connect();
// …or when you connect.
await client.connect("studio-42");
// The effective Project the server bound you to:
console.log(client.project); // "studio-42"from starfish import StarfishClient, StarfishClientOptions
# Declare the Project at construction…
client = StarfishClient(StarfishClientOptions(
server="ws://localhost:4000",
project="studio-42",
))
await client.connect()
# The effective Project the server bound you to:
print(client.project) # "studio-42"Omitting project (or passing an empty string) binds the connection to the reserved Project "default". The server resolves the effective Project — the value you declared, or one assigned by the authenticator — and echoes it back in the welcome as client.project.
Implicit vs. declared
A referenced Project resolves into one of two modes. The server decides by looking up the Project id in its store: found → declared, not found → implicit.
| Implicit (undeclared) | Declared (provisioned) | |
|---|---|---|
| How it exists | Simply referenced by a client — never provisioned | Created through the control plane |
| Session / pool creation | Ad-hoc create: true with client-chosen names and config | Ad-hoc still allowed by default; denied under lockdown |
| Matchmaking | Client supplies pool config on entry | Clients join declared policies by name |
| Configuration | None | Matchmaking policies, credential keys, lockdown |
| Use for | Local development, trusted single-tenant | Production, multi-tenant, server-owned matchmaking |
Implicit is the zero-config path. A Project id that was never provisioned behaves permissively — clients create sessions and pools with their own names and config, exactly as they always have. The reserved "default" Project is always implicit and can never be provisioned. A deployment that provisions nothing runs entirely in implicit mode, behaving as a single global keyspace.
Declared is the opt-in production layer. A Project created via the control plane carries durable configuration: matchmaking policies that clients join by name, credential keys that bind a credential to the Project, and a lockdown flag. By default a declared Project still permits ad-hoc create: true (the addition is non-breaking). When lockdown: true, only declared policies may be used, and ad-hoc creation is rejected with project.lockdown.
Zero-config still works
Adding the Project model changed nothing for local development. Point a client at a server without declaring a Project — or provisioning one — and you get the same single-keyspace behavior as before. Provisioning is a progressive, opt-in step you take when you need server-owned matchmaking or tenant isolation.
Relationship to sessions, pools, and auth
- Sessions and pools resolve inside the Project. Matchmaking pairs members only within the same Project, and every session it mints belongs to that Project. See Core Concepts.
- Matchmaking policies move the pool config a client used to supply on entry server-side, so clients join by policy name instead. See the Control Plane reference.
- Authentication is a separate concern that composes with Projects. A credential can be bound to a Project through its
keys; that binding is authoritative and overrides the client's declaredproject. A client whose credential maps to one Project but declares a different one is rejected withproject.forbidden. This is how a deployment mints one Project per API key. See Projects and authentication.
Next steps
- Matchmaking as a Policy — provision a Project and join a session by policy.
- Project Provisioning API — the control-plane reference:
/admin/projectsCRUD, config and policy schemas. - Authentication — bind credentials to Projects.