diff --git a/apps/docs/content/homepage.mdx b/apps/docs/content/homepage.mdx
index 9d22d6f83..cc9d1a177 100644
--- a/apps/docs/content/homepage.mdx
+++ b/apps/docs/content/homepage.mdx
@@ -41,6 +41,7 @@ export const containers = [
{ name: "Alpine", link: "/alpine/overview", icon: },
{ name: "Docker", link: "/docker/overview", icon: },
{ name: "Swarm", link: "/swarm/overview", icon: },
+ { name: "Box Workspace", link: "/zbox/overview", icon: },
]
export const databases = [
diff --git a/apps/docs/content/references/import-yaml/type-list.mdx b/apps/docs/content/references/import-yaml/type-list.mdx
index 4639e94be..5f989c77b 100644
--- a/apps/docs/content/references/import-yaml/type-list.mdx
+++ b/apps/docs/content/references/import-yaml/type-list.mdx
@@ -57,6 +57,10 @@ Versions listed on the same line are aliases of the same underlying version.
Swarm
+
+
Box Workspace (beta)
+
+
diff --git a/apps/docs/content/zbox/overview.mdx b/apps/docs/content/zbox/overview.mdx
new file mode 100644
index 000000000..0c0412807
--- /dev/null
+++ b/apps/docs/content/zbox/overview.mdx
@@ -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
+```
+
+## 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-`, 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 --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:
+
+
+
+## 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 --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.
diff --git a/apps/docs/docusaurus.config.js b/apps/docs/docusaurus.config.js
index d660a3dab..e9c93dfe0 100644
--- a/apps/docs/docusaurus.config.js
+++ b/apps/docs/docusaurus.config.js
@@ -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,
diff --git a/apps/docs/sidebars.js b/apps/docs/sidebars.js
index f196c241c..1a6b31cd1 100644
--- a/apps/docs/sidebars.js
+++ b/apps/docs/sidebars.js
@@ -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: [
@@ -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',
+ },
],
},
{
@@ -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',
diff --git a/apps/docs/src/css/custom.css b/apps/docs/src/css/custom.css
index 092b40eb3..d2dd218ff 100644
--- a/apps/docs/src/css/custom.css
+++ b/apps/docs/src/css/custom.css
@@ -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;
}
diff --git a/apps/docs/src/theme/Admonition/Icon/Beta.tsx b/apps/docs/src/theme/Admonition/Icon/Beta.tsx
new file mode 100644
index 000000000..f1ac67faf
--- /dev/null
+++ b/apps/docs/src/theme/Admonition/Icon/Beta.tsx
@@ -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 (
+
+ );
+}
diff --git a/apps/docs/src/theme/Admonition/Layout/index.tsx b/apps/docs/src/theme/Admonition/Layout/index.tsx
index fcd9d5a5c..5bef5db0a 100644
--- a/apps/docs/src/theme/Admonition/Layout/index.tsx
+++ b/apps/docs/src/theme/Admonition/Layout/index.tsx
@@ -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
@@ -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'
)}
diff --git a/apps/docs/src/theme/Admonition/Type/Beta.tsx b/apps/docs/src/theme/Admonition/Type/Beta.tsx
new file mode 100644
index 000000000..c8611c990
--- /dev/null
+++ b/apps/docs/src/theme/Admonition/Type/Beta.tsx
@@ -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 } title="Beta" {...props} />;
+}
diff --git a/apps/docs/src/theme/Admonition/Types.tsx b/apps/docs/src/theme/Admonition/Types.tsx
new file mode 100644
index 000000000..fd6862fa5
--- /dev/null
+++ b/apps/docs/src/theme/Admonition/Types.tsx
@@ -0,0 +1,9 @@
+import DefaultAdmonitionTypes from '@theme-original/Admonition/Types';
+import AdmonitionTypeBeta from './Type/Beta';
+
+const AdmonitionTypes = {
+ ...DefaultAdmonitionTypes,
+ beta: AdmonitionTypeBeta,
+};
+
+export default AdmonitionTypes;
diff --git a/apps/docs/src/theme/DocSidebarItem/Link/index.tsx b/apps/docs/src/theme/DocSidebarItem/Link/index.tsx
index a708d4440..ff151bdc5 100644
--- a/apps/docs/src/theme/DocSidebarItem/Link/index.tsx
+++ b/apps/docs/src/theme/DocSidebarItem/Link/index.tsx
@@ -71,7 +71,7 @@ export default function DocSidebarItemLink({
{customProps?.sidebar_badge && (
)}
diff --git a/apps/docs/src/theme/Icon/ZeropsBox/index.tsx b/apps/docs/src/theme/Icon/ZeropsBox/index.tsx
new file mode 100644
index 000000000..3c2b2e72e
--- /dev/null
+++ b/apps/docs/src/theme/Icon/ZeropsBox/index.tsx
@@ -0,0 +1,26 @@
+import { IconProps } from '@medusajs/icons/dist/types';
+import React from 'react';
+
+const IconZeropsBox = ({ color = 'currentColor', ...props }: IconProps) => {
+ return (
+
+ );
+};
+
+export default IconZeropsBox;
diff --git a/apps/docs/src/theme/Icon/index.tsx b/apps/docs/src/theme/Icon/index.tsx
index 1badcf4bb..b668b0050 100644
--- a/apps/docs/src/theme/Icon/index.tsx
+++ b/apps/docs/src/theme/Icon/index.tsx
@@ -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';
@@ -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,
diff --git a/apps/docs/static/data.json b/apps/docs/static/data.json
index 1ea3e835c..54244f241 100644
--- a/apps/docs/static/data.json
+++ b/apps/docs/static/data.json
@@ -249,6 +249,10 @@
"import": [["swarm@1"], ["swarm-vm@1"]],
"readable": ["1"]
},
+ "zbox": {
+ "import": [["zbox@1", "zbox@latest"]],
+ "readable": ["1"]
+ },
"docker": {
"base": {
"runtime": [
diff --git a/apps/docs/static/llms-full.txt b/apps/docs/static/llms-full.txt
index b0a2c2752..9cc915e59 100644
--- a/apps/docs/static/llms-full.txt
+++ b/apps/docs/static/llms-full.txt
@@ -3301,6 +3301,17 @@ The maximum total that can be automatically charged within a single calendar mon
- After two top-ups ($400), a full $200 would exceed the $500 limit, so the next top-up is reduced to $100, bringing the month's total to exactly $500
- Automatic top-ups then pause until the limit resets at the start of the next calendar month (UTC)
+## When Credit Runs Out
+
+Resource usage is deducted from your credit hourly, while subscriptions such as the project core and a dedicated IPv4 address are charged for a month in advance and renewed on the day they were activated.
+
+If your credit cannot cover a renewal:
+
+- The renewal fails and you are notified in the dashboard.
+- A dedicated IPv4 address is released and the project falls back to the shared IPv4. The subscription is not restored automatically after a top-up; add the address again from the project's routing settings once credit is available, which starts a new paid month.
+
+Enable [automatic top-ups](#automatic-top-ups) to avoid failed renewals.
+
## Billing Information
You are required to enter billing details for all transactions (manual and automatic top-ups), with one exception:
@@ -3426,7 +3437,7 @@ Enhance your deployment with these optional services to meet specific requiremen
Dedicated IPv4
-
$3.00 per 30 days
+
$3.00 per month
Exclusive IPv4 address for your project (instead of shared)
@@ -16413,7 +16424,7 @@ Zerops offers three public access methods: zerops.app subdomains (dev only, 50MB
- Configurable firewall: blacklist or whitelist per port
## Gotchas
-1. **Dedicated IPv4 is non-refundable**: $3/30 days, auto-renews — the fee isn't refunded if removed early, but the address can be reused in another project until the subscription ends
+1. **Dedicated IPv4 is non-refundable**: $3/month, auto-renews — the fee isn't refunded if removed early, but the address can be reused in another project until the subscription ends. If a renewal fails for lack of credit, the address is released and must be added again after a top-up
----------------------------------------
@@ -16445,11 +16456,12 @@ Checks the **new** container at `localhost`. Until it passes, traffic stays on t
deploy:
readinessCheck:
httpGet: { port: 3000, path: /health }
- failureTimeout: 60 # seconds until the container is marked failed
- retryPeriod: 10 # seconds between attempts
+ failureTimeout: "60s" # time until the container is marked failed
+ retryPeriod: "10s" # time between attempts
```
Mechanics: `start` runs → readiness check runs → on fail, wait `retryPeriod` and retry → on success, the container is marked active and receives traffic → if still failing after `failureTimeout`, the container is deleted and the deploy fails (the previous appVersion stays active). Set `failureTimeout`/`retryPeriod` explicitly — there is no fixed schema default to rely on.
+Timeouts and periods are duration strings with a unit, like `"60s"`. A bare number such as `60` fails validation.
## Health check (`run.healthCheck`)
@@ -16459,10 +16471,10 @@ Runs on every container continuously after startup.
run:
healthCheck:
httpGet: { port: 3000, path: /health }
- failureTimeout: 30 # consecutive-failure seconds before restart (reset by a success)
- disconnectTimeout: 30 # seconds before a failing container is pulled from the LB
- recoveryTimeout: 30 # seconds of success before a restarted container takes traffic again
- execPeriod: 10 # seconds between attempts
+ failureTimeout: "30s" # consecutive-failure time before restart (reset by a success)
+ disconnectTimeout: "30s" # time before a failing container is pulled from the LB
+ recoveryTimeout: "30s" # time of success before a restarted container takes traffic again
+ execPeriod: "10s" # time between attempts
```
**Failure sequence**: repeated failures → `disconnectTimeout` removes the container from the load balancer → `failureTimeout` triggers a restart → `recoveryTimeout` gates traffic reconnection once it's healthy again.
@@ -17198,6 +17210,7 @@ export const containers = [
{ name: "Alpine", link: "/alpine/overview", icon: },
{ name: "Docker", link: "/docker/overview", icon: },
{ name: "Swarm", link: "/swarm/overview", icon: },
+ { name: "Box Workspace", link: "/zbox/overview", icon: },
]
export const databases = [
@@ -31697,6 +31710,12 @@ Versions listed on the same line are aliases of the same underlying version.
- `swarm@1`
- `swarm-vm@1`
+
+
+
+
Box Workspace (beta)
+
+- `zbox@1`, `zbox@latest`
@@ -34286,11 +34305,12 @@ Before setting up domain access, you need to configure public IP addresses. Zero
#### IPv4 Configuration
-**Dedicated IPv4 Address ($3/30 days)**
+**Dedicated IPv4 Address ($3/month)**
- Dedicated to your project and shared across all project services
- One IPv4 address per project limit
- Protects against blacklisting risks associated with shared IPs
-- Subscription automatically renews every 30 days *(cannot be purchased with promo credit)*
+- Subscription automatically renews every month on the day it was activated *(cannot be purchased with promo credit)*
+- If the renewal cannot be paid, the address is released and the project falls back to the shared IPv4. Topping up does not restore it; add the address again once credit is available (see [Top-up & Billing](/company/payment#when-credit-runs-out))
- Fee is non-refundable but address can be reused in another project until subscription ends
- **Recommended for production workloads**
@@ -42985,6 +43005,123 @@ For advanced configurations or custom requirements:
- Join our [Discord community](https://discord.gg/zeropsio)
- Contact support via [email](mailto:support@zerops.io)
+----------------------------------------
+
+# Zbox > Overview
+
+
+:::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
+```
+
+## 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-`, 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 --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:
+
+- `zbox@1`, `zbox@latest`
+
+## 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 --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.
+
+
----------------------------------------
# Zcp > Concept > How It Works
@@ -45791,8 +45928,8 @@ deploy:
scheme: https
# Common parameters
- failureTimeout: 60
- retryPeriod: 10
+ failureTimeout: "60s"
+ retryPeriod: "10s"
```
Readiness checks work similarly to [health checks](#healthcheck-) but are specifically for deployment. They verify if a new deployment is ready to receive traffic.
@@ -45805,8 +45942,8 @@ The `httpGet` and `exec` options work the same way as in [health checks](#health
#### Common parameters *[Optional]*
The following parameters can be used with either `httpGet` or `exec` readiness checks:
-- **failureTimeout** - Time in seconds until container is marked as failed.
-- **retryPeriod** - Time interval in seconds between readiness check attempts (equivalent to `execPeriod` in health checks).
+- **failureTimeout** - Time until container is marked as failed. Use a duration string with a unit, for example `"60s"`.
+- **retryPeriod** - Time interval between readiness check attempts, for example `"10s"` (equivalent to `execPeriod` in health checks).
:::tip
Unlike health checks which run continuously, readiness checks only run during deployments to determine when your application is ready to accept traffic.
@@ -46120,10 +46257,10 @@ run:
grep -q "OK" /tmp/status
# Common parameters
- failureTimeout: 60
- disconnectTimeout: 30
- recoveryTimeout: 30
- execPeriod: 10
+ failureTimeout: "60s"
+ disconnectTimeout: "30s"
+ recoveryTimeout: "30s"
+ execPeriod: "10s"
```
Available parameters:
@@ -46143,10 +46280,10 @@ Configures the health check to run a local command.
#### Common parameters *[Optional]*
The following parameters can be used with either `httpGet` or `exec` health checks:
-- **failureTimeout** - Time in seconds until container fails after consecutive health check failures (reset by success).
-- **disconnectTimeout** - Time in seconds until container is disconnected and becomes publicly unavailable.
-- **recoveryTimeout** - Time in seconds until container is connected and becomes publicly available.
-- **execPeriod** - Time interval in seconds between health check attempts.
+- **failureTimeout** - Time until container fails after consecutive health check failures (reset by success). Use a duration string with a unit, for example `"30s"`.
+- **disconnectTimeout** - Time until container is disconnected and becomes publicly unavailable.
+- **recoveryTimeout** - Time until container is connected and becomes publicly available.
+- **execPeriod** - Time interval between health check attempts.
:::tip
Health checks continuously monitor your running application, while readiness checks verify if a new deployment is ready to receive traffic. For readiness checks, see the [readinessCheck section](#readinesscheck-).
diff --git a/apps/docs/static/llms-small.txt b/apps/docs/static/llms-small.txt
index c9b152174..437a22ebe 100644
--- a/apps/docs/static/llms-small.txt
+++ b/apps/docs/static/llms-small.txt
@@ -16104,7 +16104,7 @@ Zerops offers three public access methods: zerops.app subdomains (dev only, 50MB
- Configurable firewall: blacklist or whitelist per port
## Gotchas
-1. **Dedicated IPv4 is non-refundable**: $3/30 days, auto-renews — the fee isn't refunded if removed early, but the address can be reused in another project until the subscription ends
+1. **Dedicated IPv4 is non-refundable**: $3/month, auto-renews — the fee isn't refunded if removed early, but the address can be reused in another project until the subscription ends. If a renewal fails for lack of credit, the address is released and must be added again after a top-up
----------------------------------------
@@ -16136,11 +16136,12 @@ Checks the **new** container at `localhost`. Until it passes, traffic stays on t
deploy:
readinessCheck:
httpGet: { port: 3000, path: /health }
- failureTimeout: 60 # seconds until the container is marked failed
- retryPeriod: 10 # seconds between attempts
+ failureTimeout: "60s" # time until the container is marked failed
+ retryPeriod: "10s" # time between attempts
```
Mechanics: `start` runs → readiness check runs → on fail, wait `retryPeriod` and retry → on success, the container is marked active and receives traffic → if still failing after `failureTimeout`, the container is deleted and the deploy fails (the previous appVersion stays active). Set `failureTimeout`/`retryPeriod` explicitly — there is no fixed schema default to rely on.
+Timeouts and periods are duration strings with a unit, like `"60s"`. A bare number such as `60` fails validation.
## Health check (`run.healthCheck`)
@@ -16150,10 +16151,10 @@ Runs on every container continuously after startup.
run:
healthCheck:
httpGet: { port: 3000, path: /health }
- failureTimeout: 30 # consecutive-failure seconds before restart (reset by a success)
- disconnectTimeout: 30 # seconds before a failing container is pulled from the LB
- recoveryTimeout: 30 # seconds of success before a restarted container takes traffic again
- execPeriod: 10 # seconds between attempts
+ failureTimeout: "30s" # consecutive-failure time before restart (reset by a success)
+ disconnectTimeout: "30s" # time before a failing container is pulled from the LB
+ recoveryTimeout: "30s" # time of success before a restarted container takes traffic again
+ execPeriod: "10s" # time between attempts
```
**Failure sequence**: repeated failures → `disconnectTimeout` removes the container from the load balancer → `failureTimeout` triggers a restart → `recoveryTimeout` gates traffic reconnection once it's healthy again.
@@ -16830,6 +16831,7 @@ export const containers = [
{ name: "Alpine", link: "/alpine/overview", icon: },
{ name: "Docker", link: "/docker/overview", icon: },
{ name: "Swarm", link: "/swarm/overview", icon: },
+ { name: "Box Workspace", link: "/zbox/overview", icon: },
]
export const databases = [
@@ -35988,6 +35990,123 @@ For advanced configurations or custom requirements:
- Join our [Discord community](https://discord.gg/zeropsio)
- Contact support via [email](mailto:support@zerops.io)
+----------------------------------------
+
+# Zbox > Overview
+
+
+:::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
+```
+
+## 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-`, 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 --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:
+
+- `zbox@1`, `zbox@latest`
+
+## 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 --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.
+
+
----------------------------------------
# Zcp > Concept > How It Works
@@ -38794,8 +38913,8 @@ deploy:
scheme: https
# Common parameters
- failureTimeout: 60
- retryPeriod: 10
+ failureTimeout: "60s"
+ retryPeriod: "10s"
```
Readiness checks work similarly to [health checks](#healthcheck-) but are specifically for deployment. They verify if a new deployment is ready to receive traffic.
@@ -38808,8 +38927,8 @@ The `httpGet` and `exec` options work the same way as in [health checks](#health
#### Common parameters *[Optional]*
The following parameters can be used with either `httpGet` or `exec` readiness checks:
-- **failureTimeout** - Time in seconds until container is marked as failed.
-- **retryPeriod** - Time interval in seconds between readiness check attempts (equivalent to `execPeriod` in health checks).
+- **failureTimeout** - Time until container is marked as failed. Use a duration string with a unit, for example `"60s"`.
+- **retryPeriod** - Time interval between readiness check attempts, for example `"10s"` (equivalent to `execPeriod` in health checks).
:::tip
Unlike health checks which run continuously, readiness checks only run during deployments to determine when your application is ready to accept traffic.
@@ -39123,10 +39242,10 @@ run:
grep -q "OK" /tmp/status
# Common parameters
- failureTimeout: 60
- disconnectTimeout: 30
- recoveryTimeout: 30
- execPeriod: 10
+ failureTimeout: "60s"
+ disconnectTimeout: "30s"
+ recoveryTimeout: "30s"
+ execPeriod: "10s"
```
Available parameters:
@@ -39146,10 +39265,10 @@ Configures the health check to run a local command.
#### Common parameters *[Optional]*
The following parameters can be used with either `httpGet` or `exec` health checks:
-- **failureTimeout** - Time in seconds until container fails after consecutive health check failures (reset by success).
-- **disconnectTimeout** - Time in seconds until container is disconnected and becomes publicly unavailable.
-- **recoveryTimeout** - Time in seconds until container is connected and becomes publicly available.
-- **execPeriod** - Time interval in seconds between health check attempts.
+- **failureTimeout** - Time until container fails after consecutive health check failures (reset by success). Use a duration string with a unit, for example `"30s"`.
+- **disconnectTimeout** - Time until container is disconnected and becomes publicly unavailable.
+- **recoveryTimeout** - Time until container is connected and becomes publicly available.
+- **execPeriod** - Time interval between health check attempts.
:::tip
Health checks continuously monitor your running application, while readiness checks verify if a new deployment is ready to receive traffic. For readiness checks, see the [readinessCheck section](#readinesscheck-).
diff --git a/apps/docs/static/llms.txt b/apps/docs/static/llms.txt
index 8b390aea3..6a39c6798 100644
--- a/apps/docs/static/llms.txt
+++ b/apps/docs/static/llms.txt
@@ -4,7 +4,7 @@
## Docs
-- [Full Docs](https://docs.zerops.io/llms-full.txt): The complete documentation as a single file (345 pages, no images).
+- [Full Docs](https://docs.zerops.io/llms-full.txt): The complete documentation as a single file (346 pages, no images).
- [Core Docs](https://docs.zerops.io/llms-small.txt): The same, trimmed to the core platform — excludes API/CLI references, company and help pages.
Every page below is also reachable in its rendered form by dropping the `.md`
@@ -337,6 +337,7 @@ suffix, and any docs.zerops.io URL can be turned into clean markdown by adding i
- [Ubuntu > How To > Upgrade](https://docs.zerops.io/ubuntu/how-to/upgrade.md)
- [Ubuntu > Overview](https://docs.zerops.io/ubuntu/overview.md)
- [Valkey > Overview](https://docs.zerops.io/valkey/overview.md)
+- [Zbox > Overview](https://docs.zerops.io/zbox/overview.md)
- [Zcp > Concept > How It Works](https://docs.zerops.io/zcp/concept/how-it-works.md)
- [Zcp > Glossary](https://docs.zerops.io/zcp/glossary.md)
- [Zcp > Overview](https://docs.zerops.io/zcp/overview.md)