Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
82 changes: 82 additions & 0 deletions reference/cli/projects.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
---
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-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