diff --git a/packages/projects-docs/next-env.d.ts b/packages/projects-docs/next-env.d.ts
new file mode 100644
index 00000000..4f11a03d
--- /dev/null
+++ b/packages/projects-docs/next-env.d.ts
@@ -0,0 +1,5 @@
+///
+///
+
+// NOTE: This file should not be edited
+// see https://nextjs.org/docs/basic-features/typescript for more information.
diff --git a/packages/projects-docs/package.json b/packages/projects-docs/package.json
index 2afb15d8..d965cf92 100644
--- a/packages/projects-docs/package.json
+++ b/packages/projects-docs/package.json
@@ -24,8 +24,10 @@
},
"devDependencies": {
"autoprefixer": "^10.4.16",
+ "markdown-table": "^3.0.4",
"postcss": "^8.4.31",
- "tailwindcss": "^3.3.5"
+ "tailwindcss": "^3.3.5",
+ "typescript": "5.7.2"
},
"prettier": {
"embeddedLanguageFormatting": "off",
diff --git a/packages/projects-docs/pages/_meta.json b/packages/projects-docs/pages/_meta.json
index 741b5a23..67aa6c90 100644
--- a/packages/projects-docs/pages/_meta.json
+++ b/packages/projects-docs/pages/_meta.json
@@ -1,14 +1,20 @@
{
"learn": {
- "title": "Documentation",
+ "title": "Editor",
+ "type": "page"
+ },
+ "sdk": {
+ "title": "SDK",
"type": "page"
},
"tutorial": {
"title": "Tutorial",
- "type": "page"
+ "type": "page",
+ "display": "hidden"
},
"faq": {
"title": "FAQ",
- "type": "page"
+ "type": "page",
+ "display": "hidden"
}
}
diff --git a/packages/projects-docs/pages/learn/_meta.json b/packages/projects-docs/pages/learn/_meta.json
index ee675e1f..943d9047 100644
--- a/packages/projects-docs/pages/learn/_meta.json
+++ b/packages/projects-docs/pages/learn/_meta.json
@@ -2,6 +2,10 @@
"index": "Introduction",
"guides": "Getting Started",
"editors": "Editors",
+ "sdk": {
+ "title": "SDK",
+ "href": "/sdk/"
+ },
"-- cloud-development": {
"type": "separator",
"title": "Cloud Development"
@@ -29,5 +33,13 @@
"title": "More"
},
"ci": "CodeSandbox CI",
- "explore": "Discover Page"
+ "explore": "Discover Page",
+ "tutorials": {
+ "title": "Tutorials",
+ "href": "/tutorial/getting-started-with-dev-containers"
+ },
+ "faq": {
+ "title": "FAQ",
+ "href": "/faq"
+ }
}
\ No newline at end of file
diff --git a/packages/projects-docs/pages/learn/access/organizations.mdx b/packages/projects-docs/pages/learn/access/organizations.mdx
index 99d8d7ec..03a5c629 100644
--- a/packages/projects-docs/pages/learn/access/organizations.mdx
+++ b/packages/projects-docs/pages/learn/access/organizations.mdx
@@ -17,48 +17,42 @@ Additionally, organizations make it possible to connect all the employees at a c
## Creating an organization
-You can create an organization from any active workspace that is not already part of an organzation.
-In the _Workspace settings_, open the [Organization tab](https://codesandbox.io/t/org) and enter a name for the organization.
-
+You can create an organization from any active workspace that is not already part of an organzation.
+In the _Workspace settings_, open the [Organization tab](https://codesandbox.io/t/org) and enter a name for the organization.

To prevent confusion, we recommend that you name your organization so it directly relates to your business’ name.
-
-
+
Once you have created an organization, it will automatically be linked to the workspace you created it from. However, you can choose to add additional existing workspaces to that organization.
-You can also manage the organization admins.
+You can also manage the organization admins.
-
-
+
The [Organization settings](https://codesandbox.io/t/org) will always be discoverable through the _Workspace settings_.
## Setting an email domain
-In the _Organizations settings_, open the `Domain` tab and add your email domain.
-The domain must be verified before being approved. This is an automated process that requires no action from you.
-
+In the _Organizations settings_, open the `Domain` tab and add your email domain.
+The domain must be verified before being approved. This is an automated process that requires no action from you.

Once the domain is approved, users who have CodeSandbox accounts connected to emails with a matching domain will be given the option to join the workspace.
-Users may encounter the suggestion to join an eligible workspace when they are attempting to access projects in the workspace or when they log into CodeSandbox for the first time after the email domain has been approved.
+Users may encounter the suggestion to join an eligible workspace when they are attempting to access projects in the workspace or when they log into CodeSandbox for the first time after the email domain has been approved.
Below is an example of the message a user with a matching email domain will see when opening a private Sandbox from a workspace they are not yet part of.
-

-
## Accounts and domains
+
CodeSandbox accounts are tied to individual users. They grant access to shared workspaces and organizations, enabling collaboration with other CodeSandbox users.
With a single CodeSandbox account, users can create or join multiple workspaces and organizations to collaborate with various groups of CodeSandbox users; these workspaces and organizations are separate entities, each with a unique set of members and projects.
Since each workspace and organization are their own separate entities, members cannot see the other workspaces or organizations a user belongs to.
-

diff --git a/packages/projects-docs/pages/learn/devboxes/upload.mdx b/packages/projects-docs/pages/learn/devboxes/upload.mdx
index a7e6ccd5..878420e2 100644
--- a/packages/projects-docs/pages/learn/devboxes/upload.mdx
+++ b/packages/projects-docs/pages/learn/devboxes/upload.mdx
@@ -32,8 +32,7 @@ You can check your current Sandbox storage usage from your [Dashboard](https://c
For Devboxes and repositories, the limits are:
-- 20 GB total storage per Devbox or repository branch for workspaces on a Free plan.
-- 50 GB total storage per Devbox or repository branch for workspaces on a Pro plan.
+- 20 GB total storage per Devbox or repository branch for all workspaces.
You can check your Devbox storage usage by clicking the CodeSandbox icon at the top left of the editor and then "Virtual machine". This will open a new DevTool displaying the current VM usage, including storage.
diff --git a/packages/projects-docs/pages/learn/environment/vm.mdx b/packages/projects-docs/pages/learn/environment/vm.mdx
index 706cec18..888a7400 100644
--- a/packages/projects-docs/pages/learn/environment/vm.mdx
+++ b/packages/projects-docs/pages/learn/environment/vm.mdx
@@ -22,7 +22,7 @@ VM resources consist of vCPU, RAM and storage. The vCPU and RAM specs are groupe
| Subscription | Storage |
| ------------ | ------- |
| Free | 20 GB |
-| Pro | 50 GB |
+| Pro | 20 GB |
If you require storage that goes beyond our Pro plan defaults, please select 'Pro Subscriptions' on our support form and [get in touch](https://codesandbox.io/support). Our team can adjust your limits to suit your project.
diff --git a/packages/projects-docs/pages/sdk/_meta.json b/packages/projects-docs/pages/sdk/_meta.json
new file mode 100644
index 00000000..fa45d39e
--- /dev/null
+++ b/packages/projects-docs/pages/sdk/_meta.json
@@ -0,0 +1,33 @@
+{
+ "index": "Introduction",
+ "use-cases": "Use Cases",
+ "pricing": "Pricing",
+ "contact": {
+ "title": "Contact Us",
+ "href": "https://codesandbox.io/support#form",
+ "newWindow": true
+ },
+
+ "-- api-reference": {
+ "type": "separator",
+ "title": "API Reference"
+ },
+ "sandboxes": "Sandboxes",
+ "filesystem": "File System",
+ "shells": "Shells",
+ "ports": "Ports & Previews",
+ "tasks": "Tasks & Setup",
+ "specs": "VM Specs",
+
+ "-- resources": {
+ "type": "separator",
+ "title": "Resources"
+ },
+ "snapshot-library": "Snapshot Library",
+ "snapshot-builder": "Snapshot Builder",
+ "environment": "Environment",
+ "docker": "Docker & Docker Compose",
+ "persistence": "Persistence",
+ "fork": "Fork",
+ "faq": "FAQ"
+}
diff --git a/packages/projects-docs/pages/sdk/docker.mdx b/packages/projects-docs/pages/sdk/docker.mdx
new file mode 100644
index 00000000..bcb32b5d
--- /dev/null
+++ b/packages/projects-docs/pages/sdk/docker.mdx
@@ -0,0 +1,148 @@
+---
+title: Docker & Dev Containers
+description: Learn how to configure your sandbox environment using Dev Containers.
+---
+
+import { Callout } from 'nextra-theme-docs'
+
+# Dev Containers
+
+CodeSandbox natively supports the [Dev Containers specification](https://containers.dev/), allowing you to customize your sandbox, install system-level dependencies, and run additional services.
+
+## Configuration
+
+To configure your sandbox environment, create a `.devcontainer/devcontainer.json` file inside the root of the sandbox:
+
+```json
+{
+ "name": "Node.js",
+ "image": "mcr.microsoft.com/devcontainers/javascript-node:18",
+ "features": {
+ "ghcr.io/devcontainers/features/python:1": {}
+ }
+}
+```
+
+In this example, we're installing Node v18 as base, with Python on top using Dev Container Features.
+
+Alternatively, you can use a `Dockerfile` to build the Docker image when the sandbox boots:
+
+```json
+{
+ "name": "Node.js",
+ "build": {
+ "dockerfile": "./Dockerfile"
+ }
+}
+```
+
+### Using Dev Containers in the SDK
+
+When creating a sandbox, all shells will automatically run inside the Docker container specified in the Dev Container configuration.
+
+```ts
+const sandbox = await sdk.sandbox.create({
+ template: "node" // Template with Dev Container configuration
+});
+
+await sandbox.shells.run("node --version");
+```
+
+Since we use memory snapshots, the Docker container will already be running when you run your shell.
+
+## Docker Compose
+
+You can run additional services using Docker Compose by adding a `docker-compose.yml` configuration to your Dev Container:
+
+```json
+{
+ "name": "Full Stack App",
+ "dockerComposeFile": "docker-compose.yml",
+ "service": "app",
+ "workspaceFolder": "/workspace"
+}
+```
+
+With a corresponding `docker-compose.yml`:
+
+```yaml
+services:
+ app:
+ image: mcr.microsoft.com/devcontainers/javascript-node:18
+ command: sleep infinity
+
+ db:
+ image: postgres:14
+ ports:
+ - 5432:5432
+ environment:
+ POSTGRES_PASSWORD: password
+```
+
+### Using Docker Compose in the SDK
+
+The SDK will automatically start all services defined in your Docker Compose configuration:
+
+```ts
+const sandbox = await sdk.sandbox.create({
+ template: "fullstack" // Template with Dev Container configuration
+});
+
+// Wait for all services to be ready
+await sandbox.setup.waitForFinish();
+
+// You can now connect to the services
+const portInfo = await sandbox.ports.waitForPort(5432);
+console.log(`Database available at: ${portInfo.hostname}:${portInfo.port}`);
+```
+
+## Examples
+
+### Full-Stack Development Environment
+
+Here's an example of setting up a full-stack development environment with Node.js and PostgreSQL:
+
+```ts
+const sandbox = await sdk.sandbox.create({
+ template: "fullstack"
+});
+
+// Wait for environment setup
+const progress = await sandbox.setup.waitForFinish();
+if (progress.state !== "FINISHED") {
+ throw new Error("Environment setup failed");
+}
+
+// Start the development server
+const devTask = await sandbox.tasks.runTask("dev");
+
+// Wait for both the app and database to be ready
+const [appPort, dbPort] = await Promise.all([
+ sandbox.ports.waitForPort(3000),
+ sandbox.ports.waitForPort(5432)
+]);
+
+console.log(`
+App running at: ${appPort.getPreviewUrl()}
+Database available at: ${dbPort.hostname}:${dbPort.port}
+`);
+```
+
+### Custom Environment with System Dependencies
+
+Example of a sandbox that needs specific system packages:
+
+```ts
+const sandbox = await sdk.sandbox.create({
+ template: "custom-env"
+});
+
+// The Dev Container will install required packages during setup
+await sandbox.setup.waitForFinish();
+
+// Run a command that uses the installed packages
+const result = await sandbox.shells.run("ffmpeg -version");
+console.log(result.output);
+```
+
+For more information about Dev Container configuration options and features, visit the [Dev Container specification](https://containers.dev/). Also, take a look at our [snapshot builder](/sdk/snapshot-builder.mdx) to learn how to create efficient snapshots with preloaded Docker images.
diff --git a/packages/projects-docs/pages/sdk/environment.mdx b/packages/projects-docs/pages/sdk/environment.mdx
new file mode 100644
index 00000000..55718ced
--- /dev/null
+++ b/packages/projects-docs/pages/sdk/environment.mdx
@@ -0,0 +1,22 @@
+---
+title: Environment
+description: Learn how the CodeSandbox SDK's environment works.
+---
+
+import { Callout } from 'nextra-theme-docs'
+
+# Environment
+
+Sandboxes on CodeSandbox are backed by a [Firecracker](https://firecracker-microvm.github.io/) microVM, within the VM we run a rootless Docker container based on a [Dev Container](https://containers.dev/) configuration (specified in the `.devcontainer/devcontainer.json` file).
+
+## Booting a Sandbox
+
+Whenever we boot a sandbox from scratch, we'll:
+
+1. Start the Firecracker VM
+2. Create a default user (called `pitcher-host`)
+3. (optional) Build the Docker image specified in the `.devcontainer/devcontainer.json` file
+4. Start the Docker container
+5. Mount the `/project/sandbox` directory as a volume inside the Docker container
+
+We run an agent inside the VM that the SDK connects to. Via an RPC protocol you can then interact with the sandbox.
diff --git a/packages/projects-docs/pages/sdk/faq.mdx b/packages/projects-docs/pages/sdk/faq.mdx
new file mode 100644
index 00000000..dd2b8491
--- /dev/null
+++ b/packages/projects-docs/pages/sdk/faq.mdx
@@ -0,0 +1,42 @@
+---
+title: FAQs
+description: Find answers to common questions about the CodeSandbox SDK.
+---
+
+import { Callout } from 'nextra-theme-docs'
+
+# FAQ
+
+## Do I need a CodeSandbox workspace to be able to use the SDK?
+
+Yes. You need a CodeSandbox API key to use CodeSandbox SDK, which you can get by [creating a CodeSandbox account](https://codesandbox.io/signin).
+
+## How can I revoke my API key?
+
+To revoke an API key, go to the "Permissions" tab of your [Workspace Settings](https://codesandbox.io/t/permissions) and click the respective token under "API Access". Then, click "Remove Token" from the bottom of that modal.
+
+## I have hit a rate limit - what should I do?
+
+Please subscribe to a CodeSandbox plan that includes the most suitable rate limit for you. In case you're on our Builder plan already, please [contact us](https://webforms.pipedrive.com/f/72gS7iXoP8qjL8Ku9HZQcN5UKpUpZkgKRCjhbqREjCOYyBgzrCKCr7Mys5AyczOHBN) to discuss an Enterprise plan.
+
+## Can I change the specs of the VMs?
+
+Currently, we only allow changing the default specs for all VMs created with the SDK. You can change
+
+We are also SOC 2 Type II compliant.
+
+## Is it possible to self-host CodeSandbox SDK?
+
+No, for now we don't provide a self-host option.
+
+## Are there any SDK rate limits?
+
+Yes. The SDK has rate limits on concurrent VMs, number of requests per hour, and number of sandboxes created per hour. These limits vary depending on the CodeSandbox plan, as explained on our [Pricing page](https://codesandbox.io/pricing).
+
+## Can I use the same CodeSandbox plan for SDK and non-SDK usage?
+
+Yes. Your CodeSandbox plan will allow you to use both, so you can leverage the SDK for programmatic sandbox creation, while still allowing your team to use CodeSandbox for their development.
+
+## Does the CodeSandbox SDK use CodeSandbox Sandboxes or Devboxes?
+
+While the SDK code only mentions "sandbox", the actual environments that it uses are officially called "Devboxes" (which use VMs). So, if you need more details about these VMs, please always refer to "[Devbox](/learn/devboxes/overview)" section of the CodeSandbox documentation and pricing.
diff --git a/packages/projects-docs/pages/sdk/filesystem.mdx b/packages/projects-docs/pages/sdk/filesystem.mdx
new file mode 100644
index 00000000..c33950de
--- /dev/null
+++ b/packages/projects-docs/pages/sdk/filesystem.mdx
@@ -0,0 +1,95 @@
+---
+title: File System
+description: Learn how the CodeSandbox SDK's file system works.
+---
+
+# File System
+
+Every sandbox has a persistent file system under `/project/sandbox`. By default, the working directory is `/project/sandbox`. All files saved in `/project/sandbox` have `git` source control and will be persisted between reboots. Whenever we hibernate or shutdown a sandbox, we'll create a commit to track the filesystem of the sandbox.
+
+Refer to the [Environment](/sdk/environment) section for more information about how we store files and other resources.
+
+## API
+
+The API of the filesystem is similar to the Node.js fs module. You can find the API under `sandbox.fs`. All filesystem
+operations are relative to the workspace directory of the sandbox (which is `/project/sandbox` by default).
+
+### Writing & Reading Files
+
+You can read & write files using an api that's similer to the Node.js fs module:
+
+```ts
+const sandbox = await sdk.sandbox.create();
+
+// Writing text files
+await sandbox.fs.writeTextFile("./hello.txt", "Hello, world!");
+
+// Reading text files
+const content = await sandbox.fs.readTextFile("./hello.txt");
+console.log(content);
+
+// Writing binary files
+await sandbox.fs.writeFile("./hello.bin", new Uint8Array([1, 2, 3]));
+
+// Reading binary files
+const content = await sandbox.fs.readFile("./hello.bin");
+console.log(content);
+```
+
+### Uploading & Downloading Files
+
+Uploading and downloading files can be done using the same methods as writing and reading files.
+
+```ts
+import fs from "node:fs";
+
+const sandbox = await sdk.sandbox.create();
+
+const myBinaryFile = fs.readFileSync("./my-binary-file");
+await sandbox.fs.writeFile("./my-binary-file", myBinaryFile);
+
+const content = await sandbox.fs.readFile("./my-binary-file");
+fs.writeFileSync("./my-binary-file", content);
+```
+
+You can also download a file or directory by generating a download URL to a zip file. This download URL is valid for 5 minutes:
+
+```ts
+const { downloadUrl } = await sandbox.fs.download("./");
+console.log(downloadUrl);
+```
+
+### Listing Files & Directories
+
+You can list files & directories in a directory using the `readdir` method.
+
+```ts
+const filesOrDirs = await sandbox.fs.readdir("./");
+
+console.log(filesOrDirs);
+```
+
+### Copying, Renaming & Deleting Files
+
+You can copy, rename & delete files using the `copy`, `rename` & `remove` methods.
+
+```ts
+await sandbox.fs.copy("./hello.txt", "./hello-copy.txt");
+await sandbox.fs.rename("./hello-copy.txt", "./hello-renamed.txt");
+await sandbox.fs.remove("./hello-renamed.txt");
+```
+
+### Watching Files
+
+You can watch files for file changes, additions and deletions using the `watch` method.
+
+```ts
+const watcher = await sandbox.fs.watch("./", { recursive: true, excludes: [".git"] });
+
+watcher.onEvent((event) => {
+ console.log(event);
+});
+
+// When you're done, you can stop the watcher
+watcher.dispose();
+```
diff --git a/packages/projects-docs/pages/sdk/fork.mdx b/packages/projects-docs/pages/sdk/fork.mdx
new file mode 100644
index 00000000..29aa978b
--- /dev/null
+++ b/packages/projects-docs/pages/sdk/fork.mdx
@@ -0,0 +1,54 @@
+---
+title: Fork
+description: Learn how forking snapshots work in the CodeSandbox SDK.
+---
+
+# Fork
+
+When you hibernate a sandbox, we keep a memory snapshot of the underlying Firecracker VM. When you start that sandbox, or if any network request is made to the sandbox, we'll restore the memory snapshot and continue from where you left off.
+Because we can snapshot a sandbox, we can also fork it! For example, you can fork a sandbox to create a new sandbox running the same server.
+
+```ts
+import { CodeSandbox } from '@codesandbox/sdk'
+const sdk = new CodeSandbox();
+
+const sandbox = await sdk.sandbox.create();
+
+// Run anything on the sandbox
+await sandbox.shells.run('echo test > test.txt');
+
+const sandbox2 = await sandbox.fork();
+
+// Now we have two sandboxes that have the same fs & memory state!
+```
+
+You can use this to add support for checkpoint/restore functionality, or A/B test different agent iterations. At CodeSandbox we use this to enable users to quickly fork shared Sandboxes to their own account.
+
+## Manually Creating a Memory Snapshot
+
+You can manually create a memory snapshot by calling `sandbox.hibernate()`:
+
+```ts
+import { CodeSandbox } from '@codesandbox/sdk'
+const sdk = new CodeSandbox();
+
+const sandbox = await sdk.sandbox.create();
+
+// Do work
+
+await sandbox.hibernate();
+```
+
+Creating a memory snapshot can take between 3-10 seconds. Resuming from a memory snapshot takes between 0.5-2 seconds.
+
+## Live snapshots
+
+If a Sandbox is already running we can still fork its exact current state. This has a small overhead of about 0.5 seconds.
+
+## Learn More
+
+We have written a couple blog posts about how memory snapshots work under the hood:
+
+- [How we clone a running VM in 2 seconds](https://codesandbox.io/blog/how-we-clone-a-running-vm-in-2-seconds)
+- [Cloning microVMs by sharing memory through userfaultfd](https://codesandbox.io/blog/cloning-microvms-using-userfaultfd)
+- [How we scale our microVM infrastructure using low-latency memory decompression](https://codesandbox.io/blog/how-we-scale-our-microvm-infrastructure-using-low-latency-memory-decompression)
diff --git a/packages/projects-docs/pages/sdk/index.mdx b/packages/projects-docs/pages/sdk/index.mdx
new file mode 100644
index 00000000..62975a36
--- /dev/null
+++ b/packages/projects-docs/pages/sdk/index.mdx
@@ -0,0 +1,73 @@
+---
+title: CodeSandbox SDK
+description: Learn how CodeSandbox works and the different types of projects you can create and develop.
+---
+
+import Hero from "../../../../shared-components/Hero.js";
+
+
+
+CodeSandbox SDK (beta) enables you to quickly create and run isolated sandboxes securely.
+The SDK can be used to run concurrent VMs to support multiple use cases such as AI agents, code interpretation and [more](/sdk/use-cases.mdx)
+
+## How it works
+
+The SDK can spin up a sandbox by cloning a template in under 3 seconds. Inside this VM, you can run any code, install any dependencies and even run servers.
+
+The sandboxes run on the same infrastructure as CodeSandbox, which means you can clone, snapshot and restore sandboxes at any point in time (checkpointing).
+
+Under the hood, the SDK uses the microVM infrastructure of CodeSandbox to spin up sandboxes. It supports:
+
+1. Memory snapshot/restore (checkpointing) at any point in time
+2. Resume/clone VMs from a snapshot in 3 seconds
+3. VM FS persistence (with `git` version control)
+4. Environment customization using Docker & Docker Compose (Dev Containers)
+
+## Quickstart
+
+Install the SDK:
+
+```bash
+npm install @codesandbox/sdk
+```
+
+Create an API key at [https://codesandbox.io/t/api](https://codesandbox.io/t/api), and enable all scopes.
+
+Now you can create a sandbox and run a server:
+
+```js
+import { CodeSandbox } from "@codesandbox/sdk";
+
+const sdk = new CodeSandbox(process.env.CSB_API_KEY!);
+const sandbox = await sdk.sandbox.create();
+
+await sandbox.shells.python.run("print(1+1)");
+await sandbox.shells.run('echo "Hello World"');
+
+// We can also start shells in the background by not awaiting them
+const shellInfo = sandbox.shells.run("npx -y serve .");
+
+// Wait for port to open
+const portInfo = await sandbox.ports.waitForPort(3000);
+console.log(portInfo.getPreviewUrl());
+
+// And, we can clone(!) the sandbox! This takes 1-3s.
+const sandbox2 = await sandbox.fork();
+
+// Sandbox 2 will have the same processes running as sandbox 1
+const portInfo2 = await sandbox2.ports.waitForPort(3000);
+console.log(portInfo2.getPreviewUrl());
+
+// Finally, we can hibernate the sandbox. This will snapshot the sandbox and stop it.
+// Next time you start the sandbox, it will continue where it left off, as we created a memory snapshot.
+// The sandboxes will also automatically resume if a network request comes in for the
+// servers they have started.
+await sandbox.hibernate();
+await sandbox2.hibernate();
+
+// Open the sandbox again
+const resumedSandbox = await sdk.sandbox.open(sandbox.id);
+```
diff --git a/packages/projects-docs/pages/sdk/persistence.mdx b/packages/projects-docs/pages/sdk/persistence.mdx
new file mode 100644
index 00000000..e980f483
--- /dev/null
+++ b/packages/projects-docs/pages/sdk/persistence.mdx
@@ -0,0 +1,34 @@
+---
+title: Persistence
+description: Learn how the persistence of sandboxes works.
+---
+
+import { Callout } from 'nextra-theme-docs'
+
+# Persistence
+
+Sandboxes have three states of persistence:
+
+- **Memory**: the sandbox has a memory snapshot and will be restored from memory when started. This takes 1-2 seconds.
+- **Disk**: the sandbox has a disk snapshot, but needs to boot from scratch. This takes 5-20 seconds.
+- **Archived**: the sandbox has no disk, and will be recreated from our archive storage. This takes 20-60 seconds.
+
+Generally, a sandbox will have a memory snapshot for 7 days, a disk snapshot for 2 weeks, and an archive for undetermined time (so far in the last 4 years, we've never deleted an archive).
+
+## Memory
+
+Whenever a sandbox is hibernated, we keep a memory snapshot of the underlying Firecracker VM. Then, when you start that sandbox, or if any network request is made to the sandbox, we'll restore the memory snapshot and continue from where you left off (this takes 0.5-2 seconds).
+
+Memory snapshots are kept for a week (can be longer depending on plan, and disk pressure), after which they'll be deleted. If the sandbox was used in the meantime (either the sandbox was resumed, or the sandbox was forked), the memory snapshot will be kept around and the timer will reset.
+
+## Disk
+
+Sandboxes have two layers of disk persistence:
+
+- `/persisted`: contains our archive of the sandbox. If you start a sandbox after a year of inactivity, the `/persisted` directory will still be there. Because of this, it's smaller than the `/project/sandbox` directory.
+
+
+We keep a `.git` directory in `/persisted` to track the filesystem of the sandbox, which we regularly commit to.
+
+
+- `/project/sandbox`: this is the working directory of the sandbox. All files saved in this directory will be persisted between reboots. If the sandbox is not started for more than two weeks (or longer, depending on plan and disk pressure), we'll commit all files of `/project/sandbox` to `/persisted` and delete the disk. If the persisting of those files fails, we won't delete the disk to ensure the user's data is not lost.
diff --git a/packages/projects-docs/pages/sdk/ports.mdx b/packages/projects-docs/pages/sdk/ports.mdx
new file mode 100644
index 00000000..bddc3afd
--- /dev/null
+++ b/packages/projects-docs/pages/sdk/ports.mdx
@@ -0,0 +1,130 @@
+---
+title: Ports
+description: Learn how you can interact with ports in your sandbox.
+---
+
+import { Callout } from 'nextra-theme-docs'
+
+# Ports
+
+The Ports API allows you to monitor and interact with HTTP ports in your sandbox. This is particularly useful when working with development servers or any other services that listen on specific ports.
+
+Whenever a port is opened within a sandbox, we'll automatically expose it under `https://-.csb.app`.
+
+
+If the sandbox is private, we'll ask the user to sign in to open the preview. We're currently working on an API to allow creating signed URLs for private sandboxes, or selecting which ports are exposed and which are closed.
+
+
+Also, we'll automatically resume a sandbox whenever a port is accessed while the sandbox is hibernated.
+
+## API
+
+The Ports API is available under `sandbox.ports`. It provides methods for monitoring port activity and getting preview URLs for web services.
+
+### Monitoring Ports
+
+You can listen for ports being opened and closed in your sandbox:
+
+```ts
+const sandbox = await sdk.sandbox.create();
+
+// Listen for ports being opened
+const listener1 = sandbox.ports.onDidPortOpen((portInfo) => {
+ console.log(`Port ${portInfo.port} opened`);
+ console.log(`Preview URL: ${portInfo.getPreviewUrl()}`);
+});
+
+// Listen for ports being closed
+const listener2 = sandbox.ports.onDidPortClose((port) => {
+ console.log(`Port ${port} closed`);
+});
+
+// Remove listeners when done
+listener1.dispose();
+listener2.dispose();
+```
+
+### Getting Port Information
+
+You can get information about currently opened ports:
+
+```ts
+const sandbox = await sdk.sandbox.create();
+
+// Get all opened ports
+const openPorts = sandbox.ports.getOpenedPorts();
+for (const port of openPorts) {
+ console.log(`Port ${port.port} is open at ${port.hostname}`);
+}
+
+// Get preview URL for a specific port
+const previewUrl = sandbox.ports.getPreviewUrl(3000);
+if (previewUrl) {
+ console.log(`Preview available at: ${previewUrl}`);
+}
+```
+
+### Waiting for Ports
+
+When starting services, you often need to wait for a port to become available:
+
+```ts
+const sandbox = await sdk.sandbox.create();
+
+// Start a development server
+sandbox.shells.run("npm run dev");
+
+// Wait for the dev server port to open
+const portInfo = await sandbox.ports.waitForPort(3000);
+console.log(`Dev server is ready at: ${portInfo.getPreviewUrl()}`);
+```
+
+## Examples
+
+### Starting a Web Server
+
+Here's a complete example of starting a web server and getting its preview URL:
+
+```ts
+const sandbox = await sdk.sandbox.create();
+
+// Start the server
+sandbox.shells.run("npx serve -y .");
+
+// Wait for the server to be ready
+const portInfo = await sandbox.ports.waitForPort(3000);
+
+// Get the preview URL with custom protocol
+const httpUrl = portInfo.getPreviewUrl("http://");
+const httpsUrl = portInfo.getPreviewUrl(); // defaults to https://
+
+console.log(`Server is running at:
+- HTTP: ${httpUrl}
+- HTTPS: ${httpsUrl}`);
+```
+
+### Monitoring Multiple Ports
+
+When working with multiple services, you might want to monitor several ports:
+
+```ts
+const sandbox = await sdk.sandbox.create();
+
+// Start monitoring before launching services
+sandbox.ports.onDidPortOpen((portInfo) => {
+ switch (portInfo.port) {
+ case 3000:
+ console.log("Frontend server ready");
+ break;
+ case 3001:
+ console.log("API server ready");
+ break;
+ case 5432:
+ console.log("Database ready");
+ break;
+ }
+});
+
+// Start your services
+sandbox.shells.run("npm run start:all");
+```
diff --git a/packages/projects-docs/pages/sdk/pricing.mdx b/packages/projects-docs/pages/sdk/pricing.mdx
new file mode 100644
index 00000000..1e388f1f
--- /dev/null
+++ b/packages/projects-docs/pages/sdk/pricing.mdx
@@ -0,0 +1,61 @@
+---
+title: Pricing
+description: Learn how CodeSandbox SDK is priced, find your ideal plan, and estimate your bill.
+---
+
+import { Callout } from 'nextra-theme-docs'
+
+# Pricing
+
+CodeSandbox SDK is priced according to the [CodeSandbox plans](https://codesandbox.io/pricing). The SDK follows two main pricing components:
+
+- **VM credits**: Credits serve as the unit of measurement for VM runtime. One credit equates to a specific amount of resources used per hour, depending on the specs of the VM you are using. VM credits follow a pay-as-you-go approach and are priced at $0.018 per credit. Learn more about credits [here](/learn/credit-usage/credits).
+
+- **VM concurrency**: This defines the maximum number of VMs you can run simultaneously with the SDK. As explored below, each CodeSandbox plan has a different VM concurrency limit.
+
+We use minutes as the smallest unit of measurement for VM credits. E.g.: if a VM runs for 3 minutes and 25 seconds, we bill the equivalent of 4 minutes of VM runtime.
+
+## VM credit prices by VM size
+
+Below is a summary of how many VM credits are used per hour of runtime in each of our available VM sizes. Note that, by default, we recommend using the Pico VM size, as it should provide enough resources for most workflows that require basic code interpretation.
+
+| VM size | Credits / hour | Cost / hour | CPU | RAM |
+| ------- | -------------- | ----------- | -------- | ------ |
+| Pico | 7 credits | $0.126 | 2 cores | 1 GB |
+| Nano | 10 credits | $0.18 | 2 cores | 4 GB |
+| Micro | 20 credits | $0.36 | 4 cores | 8 GB |
+| Small | 40 credits | $0.72 | 8 cores | 16 GB |
+| Medium | 80 credits | $1.44 | 16 cores | 32 GB |
+| Large | 160 credits | $2.88 | 32 cores | 64 GB |
+| XLarge | 320 credits | $5.76 | 64 cores | 128 GB |
+
+## Concurrent VMs
+
+To pick the most suitable plan for your use case, consider how many concurrent VMs you require and pick the corresponding plan:
+
+- Free plan: 5 concurrent VMs
+- Pro plan: 20 concurrent VMs
+- Builder plan: 100 concurrent VMs
+- Enterprise plan: custom concurrent VMs
+
+In case you expect a a high volume of VM runtime, our Enterprise plan also provides special discounts (up to 50% off) on VM credits.
+
+## Estimating your bill
+
+To estimate your bill, you must consider:
+
+- The base price of your CodeSandbox plan.
+- The number of included VM credits on that plan.
+- How many VM credits you expect to require.
+
+As an example, let's say you are planning to run 80 concurrent VMs on average, each running 3 hours per day, every day, on the Pico VM size. Here's the breakdown:
+
+- You will need a Builder plan (which allows up to 100 concurrent VMs).
+- You will use a total of 50,400 VM credits per month (80 VMs x 3 hours/day x 30 days x 7 credits/hour).
+- Your Builder plan includes 1100 free VM credits each month, so you will purchase 49,300 VM credits (50,400 - 1100).
+
+Based on this, your expected bill for that month is:
+
+- Base price of Builder plan: $170
+- Total price of VM credits: $887.40 (49,300 VM credits x $0.018/credit)
+- Total bill: $1057.40
diff --git a/packages/projects-docs/pages/sdk/sandboxes.mdx b/packages/projects-docs/pages/sdk/sandboxes.mdx
new file mode 100644
index 00000000..a766dc31
--- /dev/null
+++ b/packages/projects-docs/pages/sdk/sandboxes.mdx
@@ -0,0 +1,112 @@
+---
+title: Sandboxes
+description: Learn how to create sandboxes with the CodeSandbox SDK.
+---
+
+import { Callout } from 'nextra-theme-docs'
+
+# Sandboxes
+
+Sandboxes are the main building block of the CodeSandbox SDK. They represent a single project that you can run, fork, and modify. They are backed by a Firecracker VM. Sandboxes are completely isolated, and persisted, so you can securely run untrusted code in them.
+
+## Creating a Sandbox
+
+You can create a sandbox by calling `sandbox.create()`:
+
+```ts
+import { CodeSandbox } from '@codesandbox/sdk'
+const sdk = new CodeSandbox();
+
+const sandbox = await sdk.sandbox.create();
+```
+
+If no argument is provided to `sandbox.create()`, we'll create a sandbox based on our [Universal](https://codesandbox.io/p/devbox/universal-pcz35m) template on CodeSandbox. You can also pass in a template id, either from [our collection of templates](/sdk/snapshot-library) or by creating your own snapshot using our [Snapshot Builder](/sdk/snapshot-builder).
+
+## Opening an Existing Sandbox
+
+You can also open an existing sandbox by calling `sandbox.open()`:
+
+```ts
+const sandbox = await sdk.sandbox.open('sandbox-id');
+```
+
+This will start the sandbox and connect to it.
+
+## Opening a Sandbox from the Browser
+
+It's possible to connect to a sandbox directly from the browser without sharing your API key with the frontend. You can do this by generating a single-use token from the server:
+
+```ts
+import express from 'express';
+import { CodeSandbox } from '@codesandbox/sdk'
+
+const app = express();
+const sdk = new CodeSandbox();
+
+app.get('/api/start-sandbox/:id', async (req, res) => {
+ const startData = await sdk.sandbox.start(req.params.id);
+
+ res.json(startData);
+});
+```
+
+From the browser, you can use this start data to connect to the sandbox:
+
+```ts
+import { connectToSandbox } from '@codesandbox/sdk/browser'
+
+// Fetch the start data from the server
+const startData = await fetch('/api/start-sandbox/some-sandbox-id').then(res => res.json());
+
+const sandbox = await connectToSandbox(startData);
+
+// Now you can do whatever you normally do using the SDK
+await sandbox.fs.writeFile('./index.html', '
Hello World
');
+sandbox.shells.run('npx -y serve .')
+console.log((await sandbox.ports.waitForPort(3000)).getPreviewUrl())
+```
+
+
+Some APIs are not available when connecting from the browser. For example, you can't hibernate, shutdown or fork a sandbox.
+
+
+## Hibernation & Hibernation Timeout
+
+When you're done with a sandbox, you can hibernate it. This will save the memory state of the sandbox, so it will resume from the same state when you start it again.
+
+```ts
+await sandbox.hibernate();
+```
+
+When starting a sandbox, you can also set a hibernation timeout between 1 minute and 24 hours. By default this timeout is 5 minutes for free users, and 30 minutes for paid users.
+
+```ts
+import { CodeSandbox } from '@codesandbox/sdk'
+const sdk = new CodeSandbox();
+
+const sandbox = await sdk.sandbox.create({
+ hibernationTimeoutSeconds: 60 * 60 * 1 // 1 hour
+});
+```
+
+When you set a hibernation timeout, the sandbox will hibernate after the specified period of inactivity (no calls from the SDK). While the SDK remains connected, we recommend either explicitly hibernating the sandbox or disconnecting from it when you're done using it. Since resuming only takes a few seconds, you can be aggressive with hibernation to conserve resources.
+
+## Disconnecting from a Sandbox
+
+Alternatively, you can disconnect from the sandbox. In this case, it will automatically hibernate after the timeout:
+
+```ts
+await sandbox.disconnect();
+```
+
+You can do this if you want a user to still interact with the sandbox, but don't need to keep the SDK connected.
+
+## Shutdown
+
+Finally, you can also shutdown a sandbox. This will shut down the sandbox without creating a memory snapshot. Next time the sandbox is started, it will boot from a clean state (but your files in `/project/sandbox` will be preserved).
+
+```ts
+await sandbox.shutdown();
+```
+
+Generally you should shutdown a sandbox if you want to start from a clean state.
diff --git a/packages/projects-docs/pages/sdk/shells.mdx b/packages/projects-docs/pages/sdk/shells.mdx
new file mode 100644
index 00000000..e097d62f
--- /dev/null
+++ b/packages/projects-docs/pages/sdk/shells.mdx
@@ -0,0 +1,115 @@
+---
+title: Shells
+description: Learn how the CodeSandbox SDK's shells work.
+---
+
+# Shells
+
+The Shell API allows you to create, manage and interact with shell processes in your sandbox. You can create interactive shells, run commands, and execute code in different programming languages.
+
+## API
+
+The Shell API is available under `sandbox.shells`. It provides methods for creating shells, running commands, and managing shell instances.
+
+### Creating Interactive Shells
+
+You can create an interactive shell that allows you to send commands and receive output:
+
+```ts
+const sandbox = await sdk.sandbox.create();
+
+// Create a new shell (bash is default)
+const shell = await sandbox.shells.create('bash');
+
+// Listen to shell output
+shell.onShellOut((output) => {
+ console.log(output);
+});
+
+// Send commands to the shell
+await shell.write("echo 'Hello, world!'");
+
+// Kill the shell when done
+await shell.kill();
+```
+
+### Running Commands
+
+For simple command execution, you can use the `run` method which returns a promise with the command's output:
+
+```ts
+const sandbox = await sdk.sandbox.create();
+
+// Run a single command
+const command = sandbox.shells.run("npm install");
+
+// Listen to real-time output
+command.onOutput((output) => {
+ console.log(output);
+});
+
+// Optionally cancel the command if it's not finished
+if (Math.random() > 0.5) {
+ command.kill();
+}
+
+// Wait for completion and get results
+const result = await command;
+console.log(result.output, result.exitCode);
+```
+
+### Language Interpreters
+
+The Shell API includes built-in support for running code in different programming languages:
+
+```ts
+const sandbox = await sdk.sandbox.create();
+
+// Run JavaScript code
+const jsResult = await sandbox.shells.js.run(`
+ console.log("Hello from Node.js!");
+`);
+
+// Run Python code
+const pythonResult = await sandbox.shells.python.run(`
+ print("Hello from Python!")
+`);
+```
+
+These interpreters are built on top of the `run` method, so you can use the same options and event listeners. Currently, we only support `python` and `js` interpreters, but we're working on adding more. In the meantime you can use the `run` method to run any command.
+
+### Managing Shell Instances
+
+You can list and reconnect to existing shells:
+
+```ts
+const sandbox = await sdk.sandbox.create();
+
+// Get all shells
+const shells = await sandbox.shells.getShells();
+
+// Reconnect to an existing shell
+const shell = await sandbox.shells.open(shellId);
+
+// Check shell status and info
+console.log(shell.status); // "RUNNING" | "FINISHED" | "ERROR" | "KILLED" | "RESTARTING"
+console.log(shell.exitCode);
+console.log(shell.getOutput());
+```
+
+## Examples
+
+### Starting a server and waiting for the port to open
+
+```ts
+const sandbox = await sdk.sandbox.create();
+
+const shell = await sandbox.shells.create();
+
+// Run in background by not awaiting the command
+shell.run("npx serve -y .");
+
+const portInfo = await shell.waitForPort(3000);
+
+console.log(portInfo.getPreviewUrl());
+```
diff --git a/packages/projects-docs/pages/sdk/snapshot-builder.mdx b/packages/projects-docs/pages/sdk/snapshot-builder.mdx
new file mode 100644
index 00000000..cc842b95
--- /dev/null
+++ b/packages/projects-docs/pages/sdk/snapshot-builder.mdx
@@ -0,0 +1,128 @@
+---
+title: Snapshot Builder
+description: Learn how to create your own templates with the CodeSandbox SDK.
+---
+
+import Video from '../../../../shared-components/Video'
+
+# Snapshot Builder
+
+If you’re using CodeSandbox SDK, there’s a big chance that you want to customize the base environment of your sandboxes. You might want to preload a custom Docker image, or prestart a server that should be available as soon as you create a sandbox.
+
+You can use our CLI to create a memory snapshot that has all this data preloaded. This CLI will build a sandbox based on a folder, load the docker image, start the servers and finally create a memory snapshot that can be used when creating new sandboxes.
+
+New sandboxes can be created from this memory snapshot, which means that new sandboxes will “hit the ground running” with the servers running during snapshot creation. Creating a sandbox from a memory snapshot takes 1-3 seconds.
+
+
+
+## Creating a snapshot
+
+Install the CodeSandbox SDK globally to enable the CLI:
+
+```sh
+npm i -g @codesandbox/sdk@latest
+```
+
+Then create a directory with the files you want to have available inside your sandboxes.
+
+Finally, run:
+
+```jsx
+$ CSB_API_KEY=KEY csb build
+abcde1
+```
+
+This will create a fresh sandbox, upload the files of your directory, start necessary servers and finally snapshot the sandbox to return the id you can use. You can then pass this id when creating new sandboxes:
+
+```jsx
+const sdk = new CodeSandbox(process.env.CSB_API_KEY);
+
+const sandbox = await sdk.sandbox.create({ template: 'abcde1' });
+```
+
+### Custom Docker Image
+
+CodeSandbox uses [Dev Containers](https://containers.dev/) for configuring Docker or Docker Compose for an environment. You can configure Docker by creating a `.devcontainer/devcontainer.json` file inside your snapshot folder with these contents:
+
+```json
+{
+ "image": "ubuntu:22.04"
+}
+```
+
+When we boot the sandbox, we’ll make sure that the docker image is pulled (or built) and we’ll make sure that all shells will start within this container. The `/project/sandbox` folder is mounted inside the container.
+
+You can also decide to build the Docker image as part of the snapshot creation process. You can do this by defining this in your `.devcontainer/devcontainer.json`:
+
+```json
+{
+ "build": {
+ "dockerfile": "Dockerfile"
+ }
+}
+```
+
+And creating a `.devcontainer/Dockerfile` with the contents of your Dockerfile.
+
+For more options (like running docker compose, or adding additional features), you can look at the [Dev Container docs](https://containers.dev/implementors/json_reference/).
+
+### Prestarting Servers
+
+If you have a server, agent or dev server that you want to run as part of your snapshot, you can do that by defining a `.codesandbox/tasks.json`. Let’s say you want to run your own dev server, the contents can be this:
+
+```json
+{
+ "tasks": {
+ "dev-server": {
+ "name": "Dev Server",
+ "command": "/bin/dev-server --port 3000",
+ "preview": {
+ "port": 3000
+ },
+ "runAtStart": true
+ }
+ }
+}
+```
+
+During the snapshot creation process, we will start `/bin/dev-server` after the Docker container has been started, and we will wait until port 3000 resolves before creating a memory snapshot. Then, whenever a new sandbox is created from this snapshot, the dev server will already be running.
+
+You can also run more than one task, you can add as many as you’d like. All commands will be run from the project directory.
+
+You can learn more about tasks in our [tasks documentation](/sdk/tasks.mdx).
+
+### Boot/Setup Tasks
+
+You can configure tasks to run after docker build has been done, but before we run the other tasks. These are called setup tasks or boot tasks. Usually you would put things like dependency installation in here. This can also be done in `.codesandbox/tasks.json`:
+
+```json
+{
+ "setupTasks": [
+ "npm install",
+ "npm build"
+ ]
+}
+```
+
+For any preparation you need to do inside the workspace directory (like building a binary from source files, or installing node_modules), a setup task would be better suited than putting it in the docker image. Also, if for some reason a sandbox starts without a memory snapshot, the setup tasks will also run before it starts any tasks.
+
+You can learn more about setup tasks in our [tasks documentation](/sdk/tasks.mdx).
+
+## Examples
+
+At CodeSandbox we’ve built many templates that follow this structure. You can find different examples of templates in this repository: https://github.com/codesandbox/sandbox-templates.
+
+## Strategies & Ideas
+
+- Preloading certain npm modules by preloading them in the cache, making `pnpm install` close to instant
+ - You can do this by creating a shell script that runs `pnpm store add` for all popular packages. For example: `pnpm store add react@18.3.1 react-dom@18.3.1`.
+ - Then, as part of your Docker image or [boot tasks](https://www.notion.so/SDK-Snapshot-Builder-151b878aad1a808abcd8fda5a62e6e41?pvs=21), you can run that script to preload the image with the pnpm packages.
+ - Now, when the user runs `pnpm add react`, it should be close to instant because the packages are already available.
+- Preloading a headless browser
+ - You can create a snapshot that has a headless browser (like Playwright) already snapshotted and running inside a VM.
+ - This browser can open a websocket port, which you can use to control the browser.
+
+## Future
+
+- We're working on a way to create snapshots in multiple clusters, allowing you to run your sandboxes close to the user.
+- We're working on a tagging system that allows you to use a tag (like `my-snapshot:latest`). This way you don't have to update ids whenever you create a new snapshot.
diff --git a/packages/projects-docs/pages/sdk/snapshot-library.mdx b/packages/projects-docs/pages/sdk/snapshot-library.mdx
new file mode 100644
index 00000000..f540744b
--- /dev/null
+++ b/packages/projects-docs/pages/sdk/snapshot-library.mdx
@@ -0,0 +1,33 @@
+---
+title: Snapshot Library
+description: Explore some CodeSandbox SDK snaphots to help you bootstrap your next project.
+---
+
+import { Callout } from 'nextra-theme-docs'
+import { Templates } from './templates-component'
+
+# SDK Snapshots
+
+All sandboxes created by the CodeSandbox SDK are created from a snapshot. Even if you don't pass an argument to `sdk.sandbox.create`, we will fork the "Universal" snasphot to create a new sandbox.
+
+This is because CodeSandbox is built on top of the concept of forking. You create a template that contains all your necessary dependencies, files, or even running servers and you can clone it many times to create new sandboxes.
+
+## Starting from a Snapshot
+
+You can start from a snapshot by passing the template id to the `sdk.sandbox.create` method.
+
+```ts
+const sandbox = await sdk.sandbox.create({
+ template: 'template-id'
+})
+```
+
+## Templates
+
+Below are the official templates on CodeSandbox that you can start experimenting with. You can click on the id on the right to copy the id to your clipboard and use it in your sandbox. Click on the title to open the template in the CodeSandbox editor to inspect it.
+
+
+ Want to create your own snapshot? Check out the [Snapshot Builder](/sdk/snapshot-builder) guide to learn how to create a template from your own files using a CLI.
+
+
+
diff --git a/packages/projects-docs/pages/sdk/specs.mdx b/packages/projects-docs/pages/sdk/specs.mdx
new file mode 100644
index 00000000..213741d7
--- /dev/null
+++ b/packages/projects-docs/pages/sdk/specs.mdx
@@ -0,0 +1,46 @@
+---
+title: VM Specs
+description: You can start sandboxes with custom VM specs, or even change the VM specs of a running sandbox.
+---
+
+import { Callout } from 'nextra-theme-docs'
+
+# VM Specs
+
+Whenever you start a sandbox, you can specify which VM specs to use. This allows you to customize the VM to your needs. We also allow you to change the VM specs of a running sandbox on the fly,
+without reboot. This is useful if you want to scale up or down your sandbox dynamically based on workload needs.
+
+## Starting Sandbox with Specs
+
+You can start a sandbox with a specific VM tier by passing the `vmTier` option to the `sandbox.create` method:
+
+```ts
+import { CodeSandbox, VMTier } from "@codesandbox/sdk";
+
+const sdk = new CodeSandbox();
+const sandbox = await sdk.sandbox.create({ vmTier: VMTier.Small });
+```
+
+You can also approximate the VM size:
+
+```ts
+const sandbox = await sdk.sandbox.create({
+ vmTier: VMTier.fromSpecs({ cpu: 4, memGiB: 8 }),
+});
+```
+
+This will pick the smallest VM tier that can fit the specs you provided.
+
+## Changing VM Specs
+
+You can change the VM specs of a running sandbox by calling the `sandbox.updateTier` method:
+
+```ts
+await sandbox.updateTier(VMTier.Medium);
+```
+
+This will change the VM specs of the sandbox dynamically, without rebooting.
+
+
+ Be careful when scaling the VM specs of a running sandbox down. If you scale down the VM too much, it might not have enough resources to run your tasks and will slow to a crawl.
+
diff --git a/packages/projects-docs/pages/sdk/tasks.mdx b/packages/projects-docs/pages/sdk/tasks.mdx
new file mode 100644
index 00000000..ad7993e3
--- /dev/null
+++ b/packages/projects-docs/pages/sdk/tasks.mdx
@@ -0,0 +1,318 @@
+---
+title: Tasks & Setup
+description: Learn how the CodeSandbox SDK's tasks work.
+---
+
+import { Callout } from 'nextra-theme-docs'
+
+# Tasks
+
+The Tasks API allows you to manage and run predefined commands in your sandbox. Tasks are typically defined in your project's configuration and can include development servers, build processes, tests, or any other command-line operations.
+
+
+We might still change the Task API in the future to make it better suited for the SDK, let us know if you have any feedback or suggestions!
+
+
+## Configuration
+
+Tasks are configured in your project's `.codesandbox/tasks.json` file. This file defines both setup tasks that run when the sandbox starts, and regular tasks that can be run on-demand.
+
+### Setup Tasks
+
+Setup tasks run in order when initializing your sandbox. They're typically used for installation and preparation steps:
+
+```json
+{
+ "setupTasks": [
+ {
+ "name": "Install Dependencies",
+ "command": "pnpm install"
+ },
+ {
+ "name": "Copy Environment File",
+ "command": "cp .env.example .env"
+ },
+ "pnpm run build" // Short form for { "name": "pnpm run build", "command": "pnpm run build" }
+ ]
+}
+```
+
+### Regular Tasks
+
+Regular tasks can be run at any time and support more configuration options:
+
+```json
+{
+ "tasks": {
+ "dev": {
+ "name": "Development Server",
+ "command": "pnpm dev",
+ "runAtStart": true,
+ "preview": {
+ "port": 3000
+ },
+ "restartOn": {
+ "files": ["package.json", "pnpm-lock.yaml"], // Restart when package.json or pnpm-lock.yaml changes
+ "clone": true, // Restart right after this VM was cloned from another VM
+ "resume": false // Restart when sandbox resumes from hibernation
+ }
+ },
+ "build": {
+ "name": "Production Build",
+ "command": "pnpm build",
+ "preview": {
+ "port": 4000
+ }
+ },
+ "test": {
+ "name": "Run Tests",
+ "command": "pnpm test",
+ "restartOn": {
+ "files": ["tests/**/*"]
+ }
+ }
+ }
+}
+```
+
+### Task Options
+
+Each task can have the following options:
+
+- `name`: Display name for the task
+- `command`: The command to execute
+- `runAtStart`: Whether to run the task when the sandbox starts
+- `preview`: Configuration for task preview
+ - `port`: Port number to preview
+- `restartOn`: Configure when the task should restart
+ - `files`: Array of file patterns that trigger restart when changed
+ - `clone`: Restart when this VM was cloned from another VM
+ - `resume`: Restart when sandbox resumes from hibernation
+
+### Example Configuration
+
+Here's a more complete example showing various task configurations:
+
+```json
+{
+ "setupTasks": [
+ {
+ "name": "Install Dependencies",
+ "command": "pnpm install"
+ },
+ {
+ "name": "Copy Environment",
+ "command": "cp .env.example .env.local"
+ }
+ ],
+ "tasks": {
+ "dev": {
+ "name": "Development",
+ "command": "pnpm dev",
+ "runAtStart": true,
+ "preview": {
+ "port": 3000,
+ "prLink": "direct"
+ },
+ "restartOn": {
+ "files": ["package.json", ".env.local"],
+ "branch": false,
+ "resume": false
+ }
+ },
+ "storybook": {
+ "name": "Storybook",
+ "command": "pnpm storybook",
+ "preview": {
+ "port": 6006
+ }
+ },
+ "test:watch": {
+ "name": "Test Watch",
+ "command": "pnpm test:watch",
+ "restartOn": {
+ "files": ["tests/**/*", "src/**/*.test.*"]
+ }
+ },
+ "typecheck": {
+ "name": "Type Check",
+ "command": "pnpm typecheck"
+ },
+ "lint:fix": {
+ "name": "Fix Lint Issues",
+ "command": "pnpm lint --fix"
+ }
+ }
+}
+```
+
+## Setup Tasks
+
+Setup tasks run automatically when a sandbox starts. They typically handle installation of dependencies and initial builds. You can monitor and control setup tasks using the Setup API:
+
+```ts
+const sandbox = await sdk.sandbox.create();
+
+// Listen to setup progress
+sandbox.setup.onSetupProgressUpdate((progress) => {
+ console.log(`Setup progress: ${progress.currentStepIndex + 1}/${progress.steps.length}`);
+ console.log(`Current step: ${progress.steps[progress.currentStepIndex].name}`);
+});
+
+// Get current progress
+const progress = await sandbox.setup.getProgress();
+console.log(`Setup state: ${progress.state}`);
+
+// Wait for setup to finish
+const result = await sandbox.setup.waitForFinish();
+if (result.state === "FINISHED") {
+ console.log("Setup completed successfully");
+}
+```
+
+### Setup Tasks vs Docker Build: When to Use Which?
+
+Setup tasks are used for any preparation work needed in the `/project/sandbox` directory, such as:
+
+- Installing dependencies
+- Building assets
+- Running initial compilations
+
+Docker build, on the other hand, should be used for:
+
+- Setting up the container environment
+- Installing system-level dependencies
+- Configuring global tools
+
+This separation exists because the `/project/sandbox` directory is only available after the container starts.
+
+### Setup Progress
+
+The setup progress includes the following information:
+
+```ts
+type SetupProgress = {
+ state: "IDLE" | "IN_PROGRESS" | "FINISHED" | "STOPPED";
+ steps: {
+ name: string;
+ command: string;
+ shellId: string | null;
+ finishStatus: "SUCCEEDED" | "FAILED" | "SKIPPED" | null;
+ }[];
+ currentStepIndex: number;
+};
+```
+
+## Tasks
+
+The Tasks API is available under `sandbox.tasks`. It provides methods for listing, retrieving, and running tasks in your sandbox.
+
+
+Regular tasks are defined in the `tasks` section of your `tasks.json` file. Each task has a unique ID and can be configured to run automatically when the sandbox starts by setting `runAtStart: true`. They will start after setup has completed.
+
+
+### Listing Tasks
+
+You can get all available tasks in your sandbox:
+
+```ts
+const sandbox = await sdk.sandbox.create();
+
+// Get all tasks
+const tasks = await sandbox.tasks.getTasks();
+for (const task of tasks) {
+ console.log(`Task: ${task.name} (${task.command})`);
+}
+```
+
+### Running Tasks
+
+You can run a task using its ID:
+
+```ts
+const sandbox = await sdk.sandbox.create();
+
+// Run a specific task
+const task = await sandbox.tasks.runTask("dev");
+console.log(`Started task: ${task.name}`);
+
+// If the task opens a port, you can access it
+if (task.ports.length > 0) {
+ const port = task.ports[0];
+ console.log(`Preview available at: ${port.getPreviewUrl()}`);
+}
+```
+
+### Getting Task Information
+
+You can get information about a specific task:
+
+```ts
+const sandbox = await sdk.sandbox.create();
+
+// Get a specific task
+const task = await sandbox.tasks.getTask("build");
+if (task) {
+ console.log(`Task: ${task.name}`);
+ console.log(`Command: ${task.command}`);
+ console.log(`Runs at start: ${task.runAtStart}`);
+
+ if (task.shellId) {
+ console.log("Task is currently running");
+ }
+}
+```
+
+## Examples
+
+### Starting a Development Server
+
+Here's an example of running a development server task and waiting for it to be ready:
+
+```ts
+const sandbox = await sdk.sandbox.create();
+
+// Get the dev task
+const task = await sandbox.tasks.getTask("dev");
+if (!task) {
+ throw new Error("Dev task not found");
+}
+
+// Run the task
+await sandbox.tasks.runTask(task.id);
+
+// If the task has a preview port configured
+if (task.preview?.port) {
+ // Wait for the port to open
+ const portInfo = await sandbox.ports.waitForPort(task.preview.port);
+ console.log(`Dev server ready at: ${portInfo.getPreviewUrl()}`);
+}
+```
+
+### Running Multiple Tasks
+
+You can run multiple tasks and monitor their ports:
+
+```ts
+const sandbox = await sdk.sandbox.create();
+
+// Get all tasks that should run at start
+const tasks = await sandbox.tasks.getTasks();
+
+// Run all startup tasks
+for (const task of tasks) {
+ console.log(`Starting ${task.name}...`);
+ sandbox.tasks.runTask(task.id);
+}
+
+// Monitor ports for all tasks
+sandbox.ports.onDidPortOpen((portInfo) => {
+ const task = tasks.find(t =>
+ t.preview?.port === portInfo.port
+ );
+
+ if (task) {
+ console.log(`${task.name} is ready at: ${portInfo.getPreviewUrl()}`);
+ }
+});
+```
diff --git a/packages/projects-docs/pages/sdk/templates-component.tsx b/packages/projects-docs/pages/sdk/templates-component.tsx
new file mode 100644
index 00000000..533b394b
--- /dev/null
+++ b/packages/projects-docs/pages/sdk/templates-component.tsx
@@ -0,0 +1,56 @@
+import React, { useEffect, useState } from "react";
+
+const TEMPLATES_URL =
+ "https://raw.githubusercontent.com/codesandbox/sandbox-templates/refs/heads/main/templates.json";
+
+export const Templates = () => {
+ const [templates, setTemplates] = useState([]);
+ const [copiedId, setCopiedId] = useState(null);
+
+ useEffect(() => {
+ const fetchTemplates = async () => {
+ const templates = await fetch(TEMPLATES_URL).then((res) => res.json());
+ setTemplates(templates);
+ };
+ fetchTemplates();
+ }, []);
+ console.log(templates);
+
+ const handleCopyClick = async (id: string) => {
+ await navigator.clipboard.writeText(id);
+ setCopiedId(id);
+ setTimeout(() => setCopiedId(null), 2000);
+ };
+
+ return (
+
+ );
+};
diff --git a/packages/projects-docs/pages/sdk/use-cases.mdx b/packages/projects-docs/pages/sdk/use-cases.mdx
new file mode 100644
index 00000000..9efe8209
--- /dev/null
+++ b/packages/projects-docs/pages/sdk/use-cases.mdx
@@ -0,0 +1,44 @@
+---
+title: Use Cases
+description: Learn the main use cases for CodeSandbox SDK and get inspired to build the next big thing.
+---
+
+# Use Cases
+
+Overall, CodeSandbox SDK is a good fit with any project that requires any of the following:
+
+- Running multiple development environments at scale.
+- Acess to an isolated code interpreter.
+- Access to a sandboxed environment.
+
+There are hundreds of use cases that can benefit from these three features. Below are some of the most interesting ones we've come across recently.
+
+## Code interpretation
+
+Because CodeSandbox SDK allows programmatically spinning up sandboxes (VMs) to execute code in, it provides an ideal environment to interpret code, both for simple and complex tasks.
+
+Because these sandboxes exist in total isolation, you can run untrusted code without worrying about it affecting your system.
+
+Many of the CodeSandbox SDK early adopters, such as Blackbox AI, are leveraging this to bring code interpretation capabilities to their generative AI applications. We highly recommend following the [guide by Together AI](https://docs.together.ai/docs/code-execution) to get CodeSandbox SDK running seamlessly with any of the leading open-source LLMs.
+
+## AI Agents
+
+Agentic workflows are a fast-emerging use case that can benefit immensely from CodeSandbox SDK.
+
+You can give each agents a sandbox to resolve user prompts, or create autonomous agents running on sandboxes. This ensures they are securely isolated from your system but still can interact with each other as required.
+
+You can run multiple agents in parallel without them interfering with each other. Using the forking mechanism, you can also A/B test different agents.
+
+## Development environments
+
+With the SDK, you can programmatically provision a sandbox for anyone who needs an environment to code in. This way, you can run multiple development environments in parallel without them interfering with each other.
+
+With this, you can essentially create your own CodeSandbox for your team/company/school!
+
+## CI/CD
+
+CodeSandbox SDK is a worthy successor to CodeSandbox CI.
+
+With the SDK, you can set up your own CI/CD implementation to run tests inside a sandbox and hibernate the sandbox when the tests are done. This way, you can quickly start the sandbox again when you need to run the tests again or evaluate the results.
+
+You can also use the SDK to create 1 sandbox that runs your CI/CD preparation, and then clone it multiple times to run your tests in parallel.
diff --git a/packages/projects-docs/public/snapshot-builder.mp4 b/packages/projects-docs/public/snapshot-builder.mp4
new file mode 100644
index 00000000..7f43fc3b
Binary files /dev/null and b/packages/projects-docs/public/snapshot-builder.mp4 differ
diff --git a/packages/projects-docs/styles.css b/packages/projects-docs/styles.css
index 397e545c..f04fe135 100644
--- a/packages/projects-docs/styles.css
+++ b/packages/projects-docs/styles.css
@@ -453,3 +453,92 @@ html[class~="dark"] article pre {
background-color: var(--neutral-dark-medium) !important;
border: none;
}
+
+/* Templates List
+ ------------------------ */
+.templates-list {
+ width: 100%;
+ margin-top: 2rem;
+}
+
+html[class~="dark"] .templates-list {
+ --template-border: var(--neutral-dark-opacity);
+ --template-title: var(--neutral-light-high);
+ --template-id-bg: var(--neutral-dark-high);
+ --template-id-text: var(--neutral-light-base);
+ --template-description: var(--neutral-light-base);
+}
+
+html[class~="light"] .templates-list {
+ --template-border: var(--neutral-light-opacity);
+ --template-title: var(--neutral-dark-base);
+ --template-id-bg: var(--neutral-light-high);
+ --template-id-text: var(--neutral-dark-base);
+ --template-description: var(--neutral-light-base);
+}
+
+.templates-list .template-item {
+ display: flex;
+ align-items: flex-start;
+ padding: 1rem;
+ border-bottom: 1px solid var(--template-border);
+}
+
+.templates-list .template-icon {
+ width: 32px;
+ height: 32px;
+ margin-right: 1rem;
+ border-radius: 6px;
+}
+
+html[class~="light"] .templates-list .template-icon {
+ background-color: var(--neutral-light-base);
+ padding: 4px;
+ border: 1px solid var(--neutral-light-base);
+}
+
+html[class~="dark"] .templates-list .template-icon {
+ background-color: transparent;
+ padding: 0;
+}
+
+.templates-list .template-content {
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+}
+
+.templates-list .template-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 0.5rem;
+}
+
+.templates-list .template-title {
+ font-weight: 500;
+ color: var(--template-title);
+ text-decoration: none;
+}
+
+.templates-list .template-title:hover {
+ text-decoration: underline;
+}
+
+.templates-list .template-id {
+ padding: 0.25rem 0.5rem;
+ font-size: 0.875rem;
+ background-color: var(--template-id-bg);
+ border: none;
+ border-radius: 4px;
+ color: var(--template-id-text);
+ cursor: pointer;
+ min-width: 80px;
+ text-align: center;
+}
+
+.templates-list .template-description {
+ font-size: 0.875rem;
+ color: var(--template-description);
+ line-height: 1.25rem;
+}
diff --git a/packages/projects-docs/tsconfig.json b/packages/projects-docs/tsconfig.json
new file mode 100644
index 00000000..65348e83
--- /dev/null
+++ b/packages/projects-docs/tsconfig.json
@@ -0,0 +1,28 @@
+{
+ "compilerOptions": {
+ "lib": [
+ "dom",
+ "dom.iterable",
+ "esnext"
+ ],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "strict": false,
+ "noEmit": true,
+ "incremental": true,
+ "esModuleInterop": true,
+ "module": "esnext",
+ "moduleResolution": "node",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "jsx": "preserve"
+ },
+ "include": [
+ "next-env.d.ts",
+ "**/*.ts",
+ "**/*.tsx"
+ ],
+ "exclude": [
+ "node_modules"
+ ]
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index b1003356..8806cd1d 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -51,12 +51,18 @@ importers:
autoprefixer:
specifier: ^10.4.16
version: 10.4.16(postcss@8.4.31)
+ markdown-table:
+ specifier: ^3.0.4
+ version: 3.0.4
postcss:
specifier: ^8.4.31
version: 8.4.31
tailwindcss:
specifier: ^3.3.5
version: 3.3.5
+ typescript:
+ specifier: 5.7.2
+ version: 5.7.2
packages:
@@ -2913,9 +2919,8 @@ packages:
engines: {node: '>=0.10.0'}
dev: false
- /markdown-table@3.0.3:
- resolution: {integrity: sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==}
- dev: false
+ /markdown-table@3.0.4:
+ resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==}
/match-sorter@6.3.1:
resolution: {integrity: sha512-mxybbo3pPNuA+ZuCUhm5bwNkXrJTbsk5VWbR5wiwz/GC6LIiegBGn2w3O08UG/jdbYLinw51fSQ5xNU1U3MgBw==}
@@ -3005,7 +3010,7 @@ packages:
resolution: {integrity: sha512-jjcpmNnQvrmN5Vx7y7lEc2iIOEytYv7rTvu+MeyAsSHTASGCCRA79Igg2uKssgOs1i1po8s3plW0sTu1wkkLGg==}
dependencies:
'@types/mdast': 3.0.14
- markdown-table: 3.0.3
+ markdown-table: 3.0.4
mdast-util-from-markdown: 1.3.1
mdast-util-to-markdown: 1.5.0
transitivePeerDependencies:
@@ -5111,6 +5116,12 @@ packages:
resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==}
dev: false
+ /typescript@5.7.2:
+ resolution: {integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==}
+ engines: {node: '>=14.17'}
+ hasBin: true
+ dev: true
+
/undici-types@5.26.5:
resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
dev: false
diff --git a/shared-components/Video.js b/shared-components/Video.js
index 86347350..f4f6c191 100644
--- a/shared-components/Video.js
+++ b/shared-components/Video.js
@@ -2,7 +2,7 @@ import { useRef, useCallback, useEffect } from "react";
import { useInView } from "react-intersection-observer";
import "intersection-observer";
-export default ({ src, caption, ratio }) => {
+export default ({ src, caption, ratio, autoPlay = true, playsInline = true, controls = false }) => {
const [inViewRef, inView] = useInView({
threshold: 1,
});
@@ -46,8 +46,9 @@ export default ({ src, caption, ratio }) => {
// style={{ position: "absolute", top: 0, left: 0 }}
loop
muted
- autoPlay
- playsInline
+ controls={controls}
+ autoPlay={autoPlay}
+ playsInline={playsInline}
ref={setRefs}
>
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 00000000..7c3485a0
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,5 @@
+{
+ "compilerOptions": {
+ "jsx": "react"
+ }
+}
\ No newline at end of file