Skip to main content
A Project is a named container for Kernel resources inside an organization. Use projects to separate environments (like production and staging), split resources between teams, or isolate customer workloads — each project has its own browsers, profiles, credentials, proxies, extensions, deployments, and pools.

Why Projects?

  • Isolate environments — keep production resources apart from staging or experiments.
  • Scope access — issue API keys that can only see resources in one project.
  • Concurrency limits — set an org-wide default cap for every project, or override it per project, so one team or environment can’t exhaust your org quota.

The Default Project

Every organization has at least one project. Resources that existed before projects were introduced have been moved into a project named Default, so your existing browsers, apps, profiles, and other resources continue to work without any changes on your end. Your organization must always have at least one active project. The API returns 409 Conflict if you try to delete the last remaining project:
{ "code": "conflict", "message": "organization must have at least one project" }
A project must also be empty before it can be deleted — archive or remove its active resources first.

Scoping Requests to a Project

Pass the X-Kernel-Project-Id header — a project ID or name — on any API request to scope it to a specific project. Without the header (and without a project-scoped API key), requests act on your organization’s default project: reads return the default project’s resources, and writes create resources in it.
curl https://api.onkernel.com/browsers \
  -H "Authorization: Bearer $KERNEL_API_KEY" \
  -H "X-Kernel-Project-Id: proj_abc123"

Resolution rules

  • Unknown or archived project — a header naming a project that doesn’t exist or isn’t active fails with 404 Not Found:
    { "code": "project_not_found", "message": "Project not found or inactive" }
    
  • The default project is the baseline — naming your organization’s default project is exactly equivalent to omitting the header, for both reads and writes.
  • Scoped keys reject mismatches — with a project-scoped API key, a header naming any other project fails with 403 Forbidden (see API keys below).

SDK usage

Set the header on the client so every request is scoped to the project. You can also override it per-request.
import Kernel from '@onkernel/sdk';

// Scope the whole client to a project
const kernel = new Kernel({
  defaultHeaders: { 'X-Kernel-Project-Id': 'proj_abc123' },
});

const browser = await kernel.browsers.create();

// Or override per-request
const other = await kernel.browsers.create(
  {},
  { headers: { 'X-Kernel-Project-Id': 'proj_def456' } },
);

Authentication and Project Scope

API keys

API keys can be org-wide or project-scoped.
  • Existing API keys are org-wide. They see every resource in your organization across all projects. Include an X-Kernel-Project-Id header to restrict a single request to one project.
  • Project-scoped API keys can only access resources inside the project they were issued for. Create one from the API Keys page in the dashboard, the CLI, an SDK, or the API keys guide, and pass the target project_id when generating the key. Requests made with a scoped key are automatically limited to that project — no header required. If you do send an X-Kernel-Project-Id header and it conflicts with the key’s project, the request is rejected with 403 Forbidden.

OAuth

OAuth tokens (used by the Kernel CLI and MCP server) are always org-wide. You cannot bind an OAuth session to a single project. To scope OAuth-authenticated requests, send the X-Kernel-Project-Id header with each request — or use the CLI’s --project flag (see below).

Using Projects from the CLI

The Kernel CLI has first-class project support:
  • A global --project <id-or-name> flag scopes any command to a single project. Names are resolved case-insensitively, so --project staging works.
  • The KERNEL_PROJECT environment variable does the same, so you can set it once in your shell or CI.
  • A kernel projects command group lets you list, create, get, and delete projects, and manage per-project limit overrides.
# Scope a single command
kernel browsers list --project staging

# Scope every command in the shell
export KERNEL_PROJECT=staging
kernel apps list

# Manage projects
kernel projects list
kernel projects create staging
kernel projects limits set staging --max-concurrent-sessions 5
Under the hood, --project (or the env var) adds the X-Kernel-Project-Id header to every authenticated request. It’s the recommended way to target a specific project when you’re logged in with OAuth (kernel login), since OAuth itself is always org-wide.

Managing Projects

Use the /org/projects REST endpoints (or the SDKs’ projects resource) to manage projects.
MethodPathDescription
GET/org/projectsList projects in the organization
POST/org/projectsCreate a project
GET/org/projects/{id}Get a project by ID
PATCH/org/projects/{id}Update a project’s name or status (active / archived)
DELETE/org/projects/{id}Delete a project (must be empty and not the last active project)

Create a project

import Kernel from '@onkernel/sdk';

const kernel = new Kernel();

const project = await kernel.projects.create({ name: 'staging' });
console.log(project.id); // proj_abc123

List projects

for await (const project of kernel.projects.list()) {
  console.log(project.id, project.name, project.status);
}

Update a project

await kernel.projects.update('proj_abc123', { name: 'production' });

Delete a project

await kernel.projects.delete('proj_abc123');
You can’t delete a project that still owns active resources, and you can’t delete the last remaining active project in your org.

Concurrency Limits

Kernel caps how many browser sessions can run at once, at two levels:
  • Organization limit — the total concurrent sessions allowed across your whole organization, determined by your plan. Every session counts against it.
  • Per-project limits — optional caps on individual projects, so one team or environment can’t consume the entire org limit.
Per-project caps come from two places:
  • An org-wide default — one value that every project inherits unless it sets its own. It applies to existing and newly created projects alike, so you don’t have to configure each project by hand.
  • A per-project override — an explicit cap on a single project that takes precedence over the default.
A project’s effective cap resolves in this order:
  1. The project’s explicit override, if set.
  2. Otherwise, the organization’s default project cap, if set.
  3. Otherwise, no per-project cap — only the organization limit applies.
A per-project cap never lets a project exceed your organization’s concurrent-session limit.
MethodPathDescription
GET/org/limitsGet the org concurrent-session limit and the default per-project cap
PATCH/org/limitsSet the default per-project cap (send 0 to clear it)
GET/org/projects/{id}/limitsGet a single project’s limit overrides
PATCH/org/projects/{id}/limitsSet a single project’s limit overrides (send 0 to clear a cap)

Set an org-wide default

Apply a default of 10 concurrent sessions to every project that doesn’t have its own override:
curl -X PATCH https://api.onkernel.com/org/limits \
  -H "Authorization: Bearer $KERNEL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "default_project_max_concurrent_sessions": 10 }'
To cap a specific project differently, set an explicit override on it with PATCH /org/projects/{id}/limits — that value takes precedence over the default. See the API reference for full request and response schemas, including ProjectLimits for per-project concurrency caps.