Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@
"browsers/live-view",
"browsers/termination",
"browsers/standby",
"browsers/headless"
"browsers/headless",
"info/projects"
Comment thread
hiroTamada marked this conversation as resolved.
]
},
{
Expand Down Expand Up @@ -232,6 +233,7 @@
"reference/cli/auth",
"reference/cli/browsers",
"reference/cli/apps",
"reference/cli/projects",
"reference/cli/mcp",
"reference/cli/extensions"
]
Expand Down
191 changes: 191 additions & 0 deletions info/projects.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
---
title: "Projects"
description: "Organize resources and isolate access within your Kernel organization"
---

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.
- **Per-project limits** — cap concurrency on a per-project basis 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:

```json
{ "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 on any API request to scope it to a specific project. Without the header (and without a project-scoped API key), requests operate org-wide.

```bash
curl https://api.onkernel.com/browsers \
-H "Authorization: Bearer $KERNEL_API_KEY" \
-H "X-Kernel-Project-Id: proj_abc123"
```

### SDK usage

Set the header on the client so every request is scoped to the project. You can also override it per-request.

<CodeGroup>
```typescript TypeScript
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' } },
);
```

```python Python
from kernel import Kernel

# Scope the whole client to a project
kernel = Kernel(
default_headers={"X-Kernel-Project-Id": "proj_abc123"},
)

browser = kernel.browsers.create()

# Or override per-request
other = kernel.browsers.create(
extra_headers={"X-Kernel-Project-Id": "proj_def456"},
)
```
</CodeGroup>

## 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 and pick the target project 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](/reference/cli/projects) 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.

```bash
# 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 `/projects` REST endpoints (or the SDKs' `projects` resource) to manage projects.

| Method | Path | Description |
| --- | --- | --- |
| `GET` | `/projects` | List projects in the organization |
| `POST` | `/projects` | Create a project |
| `GET` | `/projects/{id}` | Get a project by ID |
| `PATCH` | `/projects/{id}` | Update a project's name or status (`active` / `archived`) |
| `DELETE` | `/projects/{id}` | Delete a project (must be empty and not the last active project) |
| `GET` | `/projects/{id}/limits` | Get per-project concurrency limit overrides |
| `PATCH` | `/projects/{id}/limits` | Update per-project concurrency limit overrides |

### Create a project

<CodeGroup>
```typescript TypeScript
import Kernel from '@onkernel/sdk';

const kernel = new Kernel();

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

```python Python
from kernel import Kernel

kernel = Kernel()

project = kernel.projects.create(name="staging")
print(project.id) # proj_abc123
```
</CodeGroup>

### List projects

<CodeGroup>
```typescript TypeScript
for await (const project of kernel.projects.list()) {
console.log(project.id, project.name, project.status);
}
```

```python Python
for project in kernel.projects.list():
print(project.id, project.name, project.status)
```
</CodeGroup>

### Update a project

<CodeGroup>
```typescript TypeScript
await kernel.projects.update('proj_abc123', { name: 'production' });
```

```python Python
kernel.projects.update("proj_abc123", name="production")
```
</CodeGroup>

### Delete a project

<CodeGroup>
```typescript TypeScript
await kernel.projects.delete('proj_abc123');
```

```python Python
kernel.projects.delete("proj_abc123")
```
</CodeGroup>

<Info>
You can't delete a project that still owns active resources, and you can't delete the last remaining active project in your org.
</Info>

See the [API reference](https://kernel.sh/docs/api-reference/projects/list-projects) for full request and response schemas, including `ProjectLimits` for per-project concurrency caps.
4 changes: 4 additions & 0 deletions reference/cli.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ kernel --version
<Card icon="code-fork" title="MCP" href="/reference/cli/mcp">
Install Kernel MCP server configuration for AI tools.
</Card>
<Card icon="folder-tree" title="Projects" href="/reference/cli/projects">
Manage projects and scope commands with `--project`.
</Card>
</Columns>

## Quick Start
Expand All @@ -66,6 +69,7 @@ kernel invoke my-app action-name --payload '{"key":"value"}'
- `--version`, `-v` - Print the CLI version
- `--no-color` - Disable color output
- `--log-level <level>` - Set the log level (trace, debug, info, warn, error, fatal, print)
- `--project <id-or-name>` - Scope the request to a specific [project](/reference/cli/projects) (also reads the `KERNEL_PROJECT` env var)

## JSON Output

Expand Down
83 changes: 83 additions & 0 deletions reference/cli/projects.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
---
title: "Projects"
---

Manage [Projects](/info/projects) from the CLI and scope other commands to a specific project.

## Scoping commands to a project

Use the global `--project` flag (or the `KERNEL_PROJECT` environment variable) to scope any `kernel` command to a project. The flag accepts either a **project ID** or a **project name** — names are resolved case-insensitively by listing your projects.

```bash
# Scope a single command by name
kernel browsers list --project staging

# Scope by ID
kernel browsers list --project proj_abc123

# Scope via environment variable
export KERNEL_PROJECT=staging
kernel apps list
```

Under the hood, the flag adds the `X-Kernel-Project-Id` header to every authenticated API request. OAuth-based logins (`kernel login`) remain org-wide by default, so this is the recommended way to target a single project when logged in with OAuth.

<Info>
Project-scoped API keys are already bound to a project server-side, so you don't need `--project` when using them — but if you do pass it, it must match the key's project or the request is rejected.
</Info>

If the name is ambiguous (multiple projects share it) or no match is found, the CLI returns a clear error; pass the project ID instead.

## Commands

### `kernel projects list`

List all projects in the authenticated organization.

### `kernel projects create <name>`

Create a new project with the given name.

```bash
kernel projects create staging
```

### `kernel projects get <id-or-name>`

Show details for a project by ID or name.

### `kernel projects delete <id-or-name>`

Delete a project. The project must be empty, and it can't be the last active project in the org.

## Project limits

Each project can have its own concurrency limit overrides that cap resource use below the org-wide limits.

### `kernel projects limits get <id-or-name>`

Show the per-project limit overrides. Fields show `unlimited` when no project-level cap is set (the org limit applies).

| Flag | Description |
|------|-------------|
| `--output json`, `-o json` | Output raw JSON object. |

### `kernel projects limits set <id-or-name>`

Update per-project limit overrides. Pass `0` to a limit to remove the cap for that field.

| Flag | Description |
|------|-------------|
| `--max-concurrent-sessions <n>` | Maximum concurrent browser sessions (0 to remove cap). |
| `--max-persistent-sessions <n>` | Maximum persistent browser sessions (0 to remove cap). |
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we are offering persistent sessions any longer and so shouldn't show this?

| `--max-concurrent-invocations <n>` | Maximum concurrent app invocations (0 to remove cap). |
| `--max-pooled-sessions <n>` | Maximum pooled sessions capacity (0 to remove cap). |
| `--output json`, `-o json` | Output raw JSON object. |

```bash
# Cap staging to 5 concurrent browser sessions
kernel projects limits set staging --max-concurrent-sessions 5

# Remove the cap
kernel projects limits set staging --max-concurrent-sessions 0
```
Loading