Skip to content
Open
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 docs/README_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ OpenSandbox 提供了丰富的示例来演示不同场景下的沙箱使用方
- **[google-adk](../examples/google-adk/README.md)** - 使用 Google ADK 通过 OpenSandbox 工具读写文件并执行命令。
- **[nullclaw](../examples/nullclaw/README.md)** - 在沙箱中启动 Nullclaw Gateway。
- **[openclaw](../examples/openclaw/README_zh.md)** - 在沙箱中启动 OpenClaw Gateway。
- **[zeroclaw](../examples/zeroclaw/README.md)** - 在沙箱中启动 ZeroClaw Gateway。

#### 🌐 浏览器与桌面环境

Expand Down
1 change: 1 addition & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Examples for common OpenSandbox use cases. Each subdirectory contains runnable c
- <img src="https://google.github.io/adk-docs/assets/agent-development-kit.png" alt="Google ADK" width="16" height="16" style="display:inline-block;width:16px;height:16px;vertical-align:middle;margin-right:4px;" /> [**google-adk**](google-adk): Google ADK agent calling OpenSandbox tools
- 🦞 [**nullclaw**](nullclaw): Launch a Nullclaw Gateway inside a sandbox
- 🦞 [**openclaw**](openclaw): Run an OpenClaw Gateway inside a sandbox
- 🦞 [**zeroclaw**](zeroclaw): Run a ZeroClaw Gateway inside a sandbox
- 🖥️ [**desktop**](desktop): Launch VNC desktop (Xvfb + x11vnc) for VNC client connections
- <img src="https://playwright.dev/img/playwright-logo.svg" alt="Playwright" width="16" height="16" style="display:inline-block;width:16px;height:16px;vertical-align:middle;margin-right:4px;" /> [**playwright**](playwright): Launch headless browser (Playwright + Chromium) to scrape web content
- <img src="https://code.visualstudio.com/assets/favicon.ico" alt="VS Code" width="16" height="16" style="display:inline-block;width:16px;height:16px;vertical-align:middle;margin-right:4px;" /> [**vscode**](vscode): Launch code-server (VS Code Web) to provide browser access
Expand Down
26 changes: 26 additions & 0 deletions examples/zeroclaw/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Copyright 2026 Alibaba Group Holding Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

FROM ghcr.io/zeroclaw-labs/zeroclaw:latest AS zeroclaw

FROM debian:trixie-slim

RUN apt-get update \
&& apt-get install -y --no-install-recommends bash ca-certificates \
&& rm -rf /var/lib/apt/lists/*

COPY --from=zeroclaw /usr/local/bin/zeroclaw /usr/local/bin/zeroclaw

ENTRYPOINT ["zeroclaw"]
CMD ["gateway"]
90 changes: 90 additions & 0 deletions examples/zeroclaw/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# ZeroClaw Gateway Example

Launch a [ZeroClaw](https://github.com/zeroclaw-labs/zeroclaw) Gateway inside an OpenSandbox instance and expose its HTTP endpoint. The script polls the gateway health check until it returns HTTP 200, then prints the reachable endpoint.

This example uses a thin wrapper image built from the official ZeroClaw image. The wrapper adds the shell/runtime pieces that OpenSandbox's Docker bootstrap path expects, while still using the upstream `zeroclaw` binary.

## Build the ZeroClaw Sandbox Image

Build the local wrapper image:

```shell
cd examples/zeroclaw
./build.sh
```

By default, this builds `opensandbox/zeroclaw:latest`. You can override the image name with `IMAGE=...` or `TAG=...`.

## Start OpenSandbox server [local]

The wrapper image copies the official ZeroClaw binary from `ghcr.io/zeroclaw-labs/zeroclaw:latest`.

### Notes (Docker runtime requirement)

The server uses `runtime.type = "docker"` by default, so it **must** be able to reach a running Docker daemon.

- **Docker Desktop**: ensure Docker Desktop is running, then verify with `docker version`.
- **Colima (macOS)**: start it first (`colima start`) and export the socket before starting the server:

```shell
export DOCKER_HOST="unix://${HOME}/.colima/default/docker.sock"
```

Pre-pull the upstream ZeroClaw image if you want to warm the cache before building:

```shell
docker pull ghcr.io/zeroclaw-labs/zeroclaw:latest
```

Start the OpenSandbox server (logs will stay in the terminal):

```shell
uv pip install opensandbox-server
opensandbox-server init-config ~/.sandbox.toml --example docker
opensandbox-server
```

If you see errors like `FileNotFoundError: [Errno 2] No such file or directory` from `docker/transport/unixconn.py`, it usually means the Docker unix socket is missing or Docker is not running.

## Create and Access the ZeroClaw Sandbox

This example is hard-coded for a quick start:
- OpenSandbox server: `http://localhost:8080`
- Image: `opensandbox/zeroclaw:latest`
- Gateway port: `42617`
- Timeout: `3600s`
- Command: `zeroclaw gateway --host 0.0.0.0 --port 42617`
- Env: `ZEROCLAW_ALLOW_PUBLIC_BIND=true`

Install dependencies from the project root:

```shell
uv pip install opensandbox requests
```

Run the example:

```shell
uv run python examples/zeroclaw/main.py
```

Or override the image name:

```shell
export ZEROCLAW_SANDBOX_IMAGE=opensandbox/zeroclaw:latest
uv run python examples/zeroclaw/main.py
```

You should see output similar to:

```text
Creating zeroclaw sandbox with image=opensandbox/zeroclaw:latest on OpenSandbox server http://localhost:8080...
[check] sandbox ready after 0.8s
Zeroclaw gateway started. Please refer to 127.0.0.1:56234/proxy/42617
```

The endpoint printed at the end (for example, `127.0.0.1:56234/proxy/42617`) is the ZeroClaw Gateway address exposed from the sandbox. The readiness probe in this example is `GET /health`.

## References
- [ZeroClaw](https://github.com/zeroclaw-labs/zeroclaw)
- [OpenSandbox Python SDK](https://pypi.org/project/opensandbox/)
23 changes: 23 additions & 0 deletions examples/zeroclaw/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/bash
# Copyright 2026 Alibaba Group Holding Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -ex

TAG=${TAG:-latest}
IMAGE=${IMAGE:-opensandbox/zeroclaw:${TAG}}

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"

docker build -t "${IMAGE}" "${SCRIPT_DIR}"
73 changes: 73 additions & 0 deletions examples/zeroclaw/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Copyright 2026 Alibaba Group Holding Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import time
from datetime import timedelta

import requests
from opensandbox import SandboxSync
from opensandbox.config import ConnectionConfigSync


def check_zeroclaw(sbx: SandboxSync) -> bool:
"""
Health check: poll zeroclaw gateway until it returns 200.

Returns:
True when ready
False on timeout or any exception
"""
try:
endpoint = sbx.get_endpoint(42617)
start = time.perf_counter()
url = f"http://{endpoint.endpoint}/health"
for _ in range(150): # max for ~30s
try:
resp = requests.get(url, timeout=1)
if resp.status_code == 200:
elapsed = time.perf_counter() - start
print(f"[check] sandbox ready after {elapsed:.1f}s")
return True
except Exception:
pass
time.sleep(0.2)
return False
except Exception as exc:
print(f"[check] failed: {exc}")
return False


def main() -> None:
server = "http://localhost:8080"
image = os.getenv("ZEROCLAW_SANDBOX_IMAGE", "opensandbox/zeroclaw:latest")
timeout_seconds = 3600 # 1 hour

print(f"Creating zeroclaw sandbox with image={image} on OpenSandbox server {server}...")
sandbox = SandboxSync.create(
image=image,
timeout=timedelta(seconds=timeout_seconds),
metadata={"example": "zeroclaw"},
entrypoint=["zeroclaw", "gateway", "--host", "0.0.0.0", "--port", "42617"],
connection_config=ConnectionConfigSync(domain=server),
health_check=check_zeroclaw,
env={"ZEROCLAW_ALLOW_PUBLIC_BIND": "true"},
)

endpoint = sandbox.get_endpoint(42617)
print(f"Zeroclaw gateway started. Please refer to {endpoint.endpoint}")


if __name__ == "__main__":
main()