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
1 change: 1 addition & 0 deletions apps/docs/content/homepage.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export const containers = [
{ name: "Alpine", link: "/alpine/overview", icon: <Icons.alpine/> },
{ name: "Docker", link: "/docker/overview", icon: <Icons.docker/> },
{ name: "Swarm", link: "/swarm/overview", icon: <Icons.servers-connected/> },
{ name: "Box Workspace", link: "/zbox/overview", icon: <Icons.zerops-box/> },
]

export const databases = [
Expand Down
4 changes: 4 additions & 0 deletions apps/docs/content/references/import-yaml/type-list.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ Versions listed on the same line are aliases of the same underlying version.
<td className="w-fit">Swarm</td>
<td className="w-fit"><UnorderedCodeList data={data.swarm.import} /></td>
</tr>
<tr>
<td className="w-fit">Box Workspace (beta)</td>
<td className="w-fit"><UnorderedCodeList data={data.zbox.import} /></td>
</tr>
</tbody>
</table>

Expand Down
118 changes: 118 additions & 0 deletions apps/docs/content/zbox/overview.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
---
title: Zerops Box
description: Zerops Box is a managed service that gives you a persistent workspace VM for running AI agent sandboxes as Firecracker microVMs, managed with the zbox CLI.
---

import data from '@site/static/data.json';
import UnorderedCodeList from '@site/src/components/UnorderedCodeList';

:::beta
Zerops Box is in beta, and we're still shaping it. Its behavior, API and CLI may change as we go, and it doesn't come with an SLA yet. We'd love to hear your feedback, and more documentation is on the way.
:::

Zerops Box runs **sandboxes for AI agents** on Zerops. One Zerops Box service is one **workspace**: a persistent Ubuntu virtual machine. Inside the workspace, each sandbox is a Firecracker microVM that you create, park, wake, fork and snapshot with the [`zbox` CLI](#install-the-zbox-cli). Each workspace also serves a web console.

The service type is called **Box Workspace**, after its unit: one service is one workspace. It is a managed service, like a database. There is nothing to deploy: it has no `zerops.yaml`, no build and no deploy pipeline.

## Install the zbox CLI

Workspaces and sandboxes are managed with the `zbox` CLI ([zbox-cli repository](https://github.com/zeropsio/zbox-cli)). It runs on Linux, macOS and Windows, on amd64 and arm64.

On Linux and macOS:

```bash
curl -fsSL https://box.zerops.io/install.sh | sh
```

The script downloads the latest release, verifies its SHA-256 checksum and installs `zbox` to `/usr/local/bin` if it's writable, otherwise to `~/.local/bin`. If that directory isn't on your `PATH`, the script tells you how to add it.

On Windows, in PowerShell:

```powershell
irm https://box.zerops.io/install.ps1 | iex
```

The binary is installed to `%LOCALAPPDATA%\Programs\zbox` and added to your user `PATH`. Open a new terminal for the change to apply.

Both scripts accept two environment variables: `ZBOX_VERSION` installs a specific release (for example `v0.24`) instead of the latest one, and `ZBOX_INSTALL_DIR` sets the install directory. Pre-releases (tags with a hyphen, like `v0.24-rc1`) are only installed when `ZBOX_VERSION` names them. Run `zbox --version` to check the installed version.

You can also download a binary from the [releases page](https://github.com/zeropsio/zbox-cli/releases) by hand, or install from source with Go 1.25 or newer:

```bash
go install github.com/zeropsio/zbox-cli/cmd/zbox@latest
```

Log in to your Zerops account. `zbox login` opens a consent page in the Zerops GUI where you confirm the code the CLI printed. If you don't have an account yet, `zbox register` opens the same page to create one first.

```bash
zbox login
# or log in with a personal access token created in the Zerops GUI
zbox login --token <personal-access-token>
```

## Create a workspace

The quickest way is `zbox setup`. It creates a Box Workspace service, by default named `zbox` in a new project named `zbox-<timestamp>`, and waits until the default sandbox image is pulled as the first base.

```bash
zbox setup
# use an existing project and a custom service name
zbox setup --project-id <project-id> --name mybox
# set the VM size; the defaults are 2 CPU cores, 4 GiB RAM and 10 GiB disk
zbox setup --cpu 4 --ram 8 --disk 20
```

Check the login, the workspace, its capacity and what is in use with:

```bash
zbox workspace status
```

You can also create a workspace in the GUI: choose **Add new service** in your project and pick **Box Workspace** from the service catalog. Or describe it in a `zerops-import.yaml`:

```yaml title="zerops-import.yaml"
services:
- hostname: box
type: zbox@1
```

Import it with the [zCLI](/references/cli), or paste the YAML in the GUI (**Import services** in the left menu of your project):

```bash
zcli project service-import zerops-import.yaml
```

Supported versions:

<UnorderedCodeList data={data.zbox.import} />

## Work with sandboxes

Create a sandbox, run commands in it and open its ports:

```bash
# new sandbox "app" with port 3000
zbox new app -p 3000
zbox exec app -- echo hello
zbox shell app
# open the port URL in the browser with a one-time ticket valid for 60 seconds
zbox open app 3000
# keep disk and memory state but free the RAM; zbox wake app resumes it
zbox park app
zbox remove app
```

Without `--base`, the only ready base is used. Ports are written as `port[/protocol][/access]`. By default, opening a port needs a one-time ticket.

To start sandboxes without a cold boot, create a warm template. Sandboxes created from it resume from memory:

```bash
zbox template create --name dev --base <base-name-or-digest> --cpus 2 --memory 4g --warm
zbox new app --template dev -p 3000/public
```

Commands have short aliases, like `ls` for `list`, `rm` for `remove`, `ws` for `workspace` and `create` for `new`. Every command accepts `--json` for scripting and `-q` to print only IDs.

## Scaling

A workspace is a single VM, so it scales **vertically only**: CPU cores, RAM and disk. There is no horizontal scaling and no minimum or maximum container count. Disk space can be increased but never decreased. See [Resource management](/features/scaling#part-1-resource-management) for how vertical scaling works on Zerops.
4 changes: 4 additions & 0 deletions apps/docs/docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,10 @@ const config = {
require('./src/plugins/remark-mdx-table-component'),
],
rehypePlugins: [require('./src/plugins/rehype-wrap-tables')],
admonitions: {
keywords: ['beta'],
extendDefaults: true,
},
showLastUpdateTime: false,
showLastUpdateAuthor: false,
// breadcrumbs: false,
Expand Down
36 changes: 36 additions & 0 deletions apps/docs/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@
* - To add a coming soon link (with a badge), add in customProps sidebar_is_soon: true
*/

const betaBadge = {
variant: 'orange',
children: 'BETA',
};

/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */
module.exports = {
homepage: [
Expand Down Expand Up @@ -382,6 +387,16 @@ module.exports = {
},
className: 'homepage-sidebar-item service-sidebar-item',
},
{
type: 'ref',
id: 'zbox/overview',
label: 'Box Workspace',
customProps: {
sidebar_icon: 'zerops-box',
sidebar_badge: betaBadge,
},
className: 'homepage-sidebar-item service-sidebar-item',
},
],
},
{
Expand Down Expand Up @@ -2370,6 +2385,27 @@ module.exports = {
],
},
],
zbox: [
{
type: 'ref',
id: 'homepage',
label: 'Back to home',
customProps: {
sidebar_is_back_link: true,
sidebar_icon: 'back-arrow',
},
},
{
type: 'doc',
id: 'zbox/overview',
label: 'Zerops Box',
customProps: {
sidebar_is_title: true,
sidebar_icon: 'zerops-box',
sidebar_badge: betaBadge,
},
},
],
mariadb: [
{
type: 'ref',
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/src/css/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
}

.sidebar-title .menu__link,
.sidebar-title span {
.sidebar-title span:not(.badge) {
@apply !text-compact-medium-plus text-medusa-fg-base;
}

Expand Down
19 changes: 19 additions & 0 deletions apps/docs/src/theme/Admonition/Icon/Beta.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react';
import type { IconProps } from '@medusajs/icons/dist/types';
import { ExclamationCircleSolid } from '@medusajs/icons';
import clsx from 'clsx';

export default function AdmonitionIconBeta({
className,
...props
}: IconProps): JSX.Element {
return (
<ExclamationCircleSolid
{...props}
className={clsx(
'inline-block mr-0.125 text-medusa-tag-orange-icon',
className
)}
/>
);
}
3 changes: 3 additions & 0 deletions apps/docs/src/theme/Admonition/Layout/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ function AdmonitionContainer({
: 'bg-medusa-tag-neutral-bg border-medusa-tag-neutral-border'),
(type === 'danger' || type === 'warning' || type === 'caution') &&
'bg-medusa-tag-red-bg border-medusa-tag-red-border',
type === 'beta' &&
'bg-medusa-tag-orange-bg border-medusa-tag-orange-border',
'[&_a]:no-underline [&_a]:text-medusa-fg-interactive hover:[&_a]:text-medusa-fg-interactive-hover ',
'mb-2 alert',
className
Expand Down Expand Up @@ -46,6 +48,7 @@ function AdmonitionContent({
: 'text-medusa-tag-neutral-text'),
(type === 'danger' || type === 'warning' || type === 'caution') &&
'text-medusa-tag-red-text',
type === 'beta' && 'text-medusa-tag-orange-text',
'text-medium flex-1 [&>*:last-child]:mb-0',
'[&>p>code]:px-0.5 [&>p>code]:text-code-label'
)}
Expand Down
9 changes: 9 additions & 0 deletions apps/docs/src/theme/Admonition/Type/Beta.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from 'react';
import type { Props } from '@theme/Admonition';
import AdmonitionTypeWarning from '@theme/Admonition/Type/Warning';
import IconBeta from '@theme/Admonition/Icon/Beta';

// Custom :::beta admonition, registered in docusaurus.config.js
export default function AdmonitionTypeBeta(props: Props): JSX.Element {
return <AdmonitionTypeWarning icon={<IconBeta />} title="Beta" {...props} />;
}
9 changes: 9 additions & 0 deletions apps/docs/src/theme/Admonition/Types.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import DefaultAdmonitionTypes from '@theme-original/Admonition/Types';
import AdmonitionTypeBeta from './Type/Beta';

const AdmonitionTypes = {
...DefaultAdmonitionTypes,
beta: AdmonitionTypeBeta,
};

export default AdmonitionTypes;
2 changes: 1 addition & 1 deletion apps/docs/src/theme/DocSidebarItem/Link/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export default function DocSidebarItemLink({
{customProps?.sidebar_badge && (
<Badge
{...customProps.sidebar_badge}
className={`sidebar-soon-badge`}
className={`sidebar-soon-badge ml-0.5 !px-[6px]`}
/>
)}
</Link>
Expand Down
26 changes: 26 additions & 0 deletions apps/docs/src/theme/Icon/ZeropsBox/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { IconProps } from '@medusajs/icons/dist/types';
import React from 'react';

const IconZeropsBox = ({ color = 'currentColor', ...props }: IconProps) => {
return (
<svg
width={props.width || 20}
height={props.height || 20}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}>
<g
stroke={color}
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={1.75}>
<path d="M10 2.25 16.75 6.13v7.74L10 17.75l-6.75-3.88V6.13L10 2.25Z" />
<path d="M3.25 6.13 10 10l6.75-3.87" />
<path d="M10 10v7.75" />
</g>
</svg>
);
};

export default IconZeropsBox;
2 changes: 2 additions & 0 deletions apps/docs/src/theme/Icon/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ import IconPuzzleSolid from './PuzzleSolid';
import IconNextjs from './Nextjs';
import IconFlagMini from './FlagMini';
import IconBeaker from './Beaker';
import IconZeropsBox from './ZeropsBox';
import IconGitHub from './GitHub';
import IconNestjs from './Nestjs';
import IconLaravel from './Laravel';
Expand Down Expand Up @@ -180,6 +181,7 @@ export default {
'back-arrow': ArrowUturnLeft,
'bars-three': BarsThree,
beaker: IconBeaker,
'zerops-box': IconZeropsBox,
bell: BellAlert,
'bell-alert-solid': BellAlertSolid,
bolt: Bolt,
Expand Down
4 changes: 4 additions & 0 deletions apps/docs/static/data.json
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,10 @@
"import": [["swarm@1"], ["swarm-vm@1"]],
"readable": ["1"]
},
"zbox": {
"import": [["zbox@1", "zbox@latest"]],
"readable": ["1"]
},
"docker": {
"base": {
"runtime": [
Expand Down
Loading
Loading