{"id":47936638,"url":"https://github.com/tangle-network/openclaw-sandbox-blueprint","last_synced_at":"2026-04-04T07:44:32.321Z","repository":{"id":341912852,"uuid":"1171156210","full_name":"tangle-network/openclaw-sandbox-blueprint","owner":"tangle-network","description":"Product-layer OpenClaw hosting blueprint on sandbox runtime","archived":false,"fork":false,"pushed_at":"2026-03-18T10:22:20.000Z","size":2764,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-04T07:44:30.238Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tangle-network.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-02T23:41:44.000Z","updated_at":"2026-03-17T21:45:31.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/tangle-network/openclaw-sandbox-blueprint","commit_stats":null,"previous_names":["tangle-network/openclaw-sandbox-blueprint"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/tangle-network/openclaw-sandbox-blueprint","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tangle-network%2Fopenclaw-sandbox-blueprint","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tangle-network%2Fopenclaw-sandbox-blueprint/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tangle-network%2Fopenclaw-sandbox-blueprint/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tangle-network%2Fopenclaw-sandbox-blueprint/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tangle-network","download_url":"https://codeload.github.com/tangle-network/openclaw-sandbox-blueprint/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tangle-network%2Fopenclaw-sandbox-blueprint/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31392186,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-04T04:26:24.776Z","status":"ssl_error","status_checked_at":"2026-04-04T04:23:34.147Z","response_time":60,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-04T07:44:31.314Z","updated_at":"2026-04-04T07:44:32.301Z","avatar_url":"https://github.com/tangle-network.png","language":"Rust","readme":"![Tangle Network Banner](https://raw.githubusercontent.com/tangle-network/tangle/refs/heads/main/assets/Tangle%20%20Banner.png)\n\n# openclaw-sandbox-blueprint\n\n[![Discord](https://img.shields.io/badge/Discord-Join%20Chat-7289da?logo=discord\u0026logoColor=white)](https://discord.gg/cv8EfJu3Tn)\n[![Twitter](https://img.shields.io/twitter/follow/tangle_network?style=social)](https://twitter.com/tangle_network)\n\nBlueprint-SDK-native Rust implementation for orchestrating OpenClaw\ninstances on the Tangle network.\n\n## Architecture\n\nThis is a **blueprint-sdk blueprint** — a Rust workspace that compiles to a\nTangle-compatible binary. The runner listens for on-chain `JobSubmitted` events,\nexecutes the matching handler, and submits results back to the chain.\n\n### Workspace layout\n\n```\nCargo.toml                         # workspace root\nopenclaw-sandbox-blueprint-lib/    # library: sol! types, jobs, state, router\nopenclaw-sandbox-blueprint-bin/    # binary: runner entry point (main.rs)\nopenclaw-tee-sandbox-blueprint-lib/ # TEE variant library wrapper\nopenclaw-tee-sandbox-blueprint-bin/ # TEE variant runner binary\nconfig/templates/                  # template packs (SOUL/USER/TOOLS presets)\nui/                                # React source UI (blueprint-ui + agent-ui)\ncontrol-plane-ui/                  # embedded operator-served UI build artifacts\ndocs/                              # architecture notes\n```\n\n### Jobs (state-changing, on-chain)\n\n| ID | Name | Description |\n|----|------|-------------|\n| 0 | `create` | Provision a new OpenClaw instance |\n| 1 | `start` | Start a stopped instance |\n| 2 | `stop` | Stop a running instance |\n| 3 | `delete` | Mark an instance as deleted |\n\n### Out-of-box variants\n\nInstances support these built-in `claw_variant` values in `config_json`:\n\n- `openclaw`\n- `nanoclaw`\n- `ironclaw`\n\nEach instance record persists `claw_variant` plus `ui_access` metadata so\noperators can route to the correct runtime profile without changing job ABI.\n\nSee [docs/VARIANT-REFERENCE.md](docs/VARIANT-REFERENCE.md) for verified source\nreferences and naming-collision notes.\n\n### Queries (read-only, operator HTTP API)\n\nRead-only operations are **not** on-chain jobs. They are served via the\noperator HTTP API:\n\n- `GET /` (serves the built-in control-plane UI shell)\n- `GET /assets/*` (serves code-split UI chunks for the control-plane shell)\n- `GET /health`\n- `GET /templates`\n- `GET /instances` (requires bearer auth)\n- `GET /instances/{id}` (requires bearer auth)\n- `GET /instances/{id}/access` (requires scoped bearer auth; returns per-instance UI bearer token)\n- `POST /instances/{id}/setup/start` (requires scoped bearer auth)\n- `GET /instances/{id}/tee/public-key` (requires scoped bearer auth; TEE-only instances)\n- `POST /instances/{id}/tee/sealed-secrets` (requires scoped bearer auth; forwards encrypted secrets, TEE-only instances)\n- `GET /instances/{id}/tee/attestation` (requires scoped bearer auth; fetches current TEE attestation, TEE-only instances)\n- `POST /instances/{id}/ssh` (requires scoped bearer auth; provision SSH public key)\n- `DELETE /instances/{id}/ssh` (requires scoped bearer auth; revoke SSH public key)\n- `POST /instances/{id}/terminals` (requires scoped bearer auth; create terminal session)\n- `GET /instances/{id}/terminals/{terminalId}/stream` (SSE terminal stream; bearer via header or `?token=`)\n- `POST /instances/{id}/terminals/{terminalId}/execute` (requires scoped bearer auth)\n- `DELETE /instances/{id}/terminals/{terminalId}` (requires scoped bearer auth)\n- `GET /instances/{id}/session/sessions` (requires scoped bearer auth; list chat sessions)\n- `POST /instances/{id}/session/sessions` (requires scoped bearer auth; create chat session)\n- `PATCH /instances/{id}/session/sessions/{sessionId}` (requires scoped bearer auth; rename session)\n- `DELETE /instances/{id}/session/sessions/{sessionId}` (requires scoped bearer auth)\n- `GET /instances/{id}/session/sessions/{sessionId}/messages` (requires scoped bearer auth)\n- `POST /instances/{id}/session/sessions/{sessionId}/messages` (requires scoped bearer auth)\n- `POST /instances/{id}/session/sessions/{sessionId}/abort` (requires scoped bearer auth)\n- `GET /instances/{id}/session/events` (SSE chat stream; query `sessionId`, bearer via header or `?token=`)\n\nSession endpoints:\n\n- `POST /auth/challenge` (wallet-signature challenge)\n- `POST /auth/session/wallet` (challenge verify -\u003e bearer token)\n- `POST /auth/session/token` (access-token auth -\u003e bearer token)\n\nOperator API runtime defaults:\n\n- disabled unless `OPENCLAW_OPERATOR_HTTP_ENABLED=true` (or `1`)\n- bind address defaults to `127.0.0.1:8787` via `OPENCLAW_OPERATOR_HTTP_ADDR`\n\n### Template packs\n\nPre-configured SOUL/USER/TOOLS presets in `config/templates/`:\n\n- `discord` — community support and moderation\n- `telegram` — customer outreach and bot workflows\n- `ops` — operational runbook and incident response\n- `custom` — bring your own configuration\n\n## Quickstart\n\n### Build\n\n```bash\ncargo check --all-features\ncargo build --release\ncd ui \u0026\u0026 pnpm install \u0026\u0026 pnpm run build:embedded \u0026\u0026 cd -\n```\n\n### Test\n\n```bash\ncargo test --all\n./scripts/ci/run-docker-integration-tests.sh\n./scripts/ci/run-real-variant-runtime-tests.sh # real OpenClaw + IronClaw + NanoClaw (upstream build)\n```\n\n### Local full stack (Anvil + operators + UI)\n\n```bash\n./scripts/deploy-local.sh\n```\n\nKeplr note: Keplr requires `https://` RPC URLs when adding/switching EVM chains.\nFor local chain `31338`, run:\n\n```bash\nENABLE_HTTPS_RPC_TUNNEL=1 ./scripts/deploy-local.sh\n```\n\nThis starts a Cloudflare quick tunnel (`https://*.trycloudflare.com`) that fronts\nyour local Anvil RPC and writes it into `.env.local` + `ui/.env.local`.\n\n### Run (requires Tangle node + service registration)\n\n```bash\nSERVICE_ID=\u003cid\u003e HTTP_RPC_ENDPOINT=\u003curl\u003e KEYSTORE_URI=\u003curi\u003e \\\n  cargo run --release --bin openclaw-sandbox-blueprint\n```\n\n### Create config schema (variant + secure UI tunnel)\n\n`create_instance` keeps ABI compatibility (`name`, `template_pack_id`,\n`config_json`) and reads optional profile settings from `config_json`:\n\n```json\n{\n  \"claw_variant\": \"openclaw\",\n  \"ui\": {\n    \"expose_public_url\": true,\n    \"subdomain\": \"team-assistant\",\n    \"auth_mode\": \"wallet_signature\"\n  }\n}\n```\n\nSupported values:\n\n- `claw_variant`: `openclaw` | `nanoclaw` | `ironclaw`\n- `ui.auth_mode`: `wallet_signature` | `access_token`\n- `ui.expose_public_url`: defaults to `true`\n- when `ui.auth_mode=access_token`, session login uses operator-side\n  `OPENCLAW_UI_ACCESS_TOKEN` (not `config_json`)\n\nTunnel/public URL behavior:\n\n- If `OPENCLAW_UI_BASE_DOMAIN` is set, URL is generated as\n  `https://\u003csubdomain\u003e.\u003cOPENCLAW_UI_BASE_DOMAIN\u003e` and tunnel status is `active`.\n- If unset, tunnel status is `pending` and URL remains unset until ingress is\n  provisioned by runtime infrastructure.\n- `owner_only` defaults to `true` for secure-by-default routing.\n\nExecution target behavior:\n\n- Default execution target is `standard`.\n- Set `OPENCLAW_EXECUTION_TARGET=tee` to mark new instances as TEE-targeted.\n- The dedicated `openclaw-tee-sandbox-blueprint` binary sets this automatically.\n\n## Dependency on sandbox-runtime contracts\n\nThis blueprint is a **product layer** over sandbox runtime contracts. It does\nnot implement VM/Firecracker orchestration directly. It does implement a real\nDocker execution backend for lifecycle operations. The runtime adapter boundary\nis defined and wired in the lib crate:\n\n- `InstanceRuntimeAdapter` trait = product/runtime integration contract\n- `LocalStateRuntimeAdapter` = in-memory/file projection adapter used for tests\n- `DockerRuntimeAdapter` = lifecycle execution through Docker CLI (`create/start/stop/rm`)\n\nJob handlers call the adapter, not storage internals directly. A future\nsandbox-runtime-backed adapter (for microVM/Firecracker) can be injected\nwithout rewriting job handlers.\n\n## Real execution backend (Docker)\n\nEnable Docker-backed lifecycle execution:\n\n```bash\nexport OPENCLAW_RUNTIME_BACKEND=docker\nexport OPENCLAW_IMAGE_OPENCLAW=ghcr.io/\u003corg\u003e/\u003copenclaw-image\u003e:\u003ctag\u003e\nexport OPENCLAW_IMAGE_IRONCLAW=ghcr.io/\u003corg\u003e/\u003cironclaw-image\u003e:\u003ctag\u003e\nexport OPENCLAW_DOCKER_PULL=true # optional, default true\n```\n\nNanoClaw image options:\n\n- prebuilt image:\n  - `OPENCLAW_IMAGE_NANOCLAW=\u003cimage:tag\u003e`\n- or build on demand during adapter init:\n  - `OPENCLAW_NANOCLAW_BUILD_CONTEXT=/path/to/nanoclaw`\n  - optional `OPENCLAW_NANOCLAW_BUILD_SCRIPT=container/build.sh`\n  - optional `OPENCLAW_NANOCLAW_BUILD_IMAGE_NAME=nanoclaw-agent`\n  - optional `OPENCLAW_NANOCLAW_BUILD_TAG=latest`\n\nBehavior:\n\n- `create` creates a container from the variant-mapped image.\n- UI port mapping defaults:\n  - OpenClaw: `18789`\n  - IronClaw: `18789`\n  - NanoClaw: none by default (terminal-first profile), or explicit env override\n- per-variant UI port override: `OPENCLAW_VARIANT_\u003cOPENCLAW|NANOCLAW|IRONCLAW\u003e_UI_PORT`\n- per-variant startup command override (runs as `sh -lc \u003ccommand\u003e`):\n  - `OPENCLAW_VARIANT_\u003cOPENCLAW|NANOCLAW|IRONCLAW\u003e_CONTAINER_COMMAND`\n- per-variant shell entrypoint override (when image has restrictive `ENTRYPOINT`):\n  - `OPENCLAW_VARIANT_\u003cOPENCLAW|NANOCLAW|IRONCLAW\u003e_FORCE_SHELL_ENTRYPOINT`\n- per-variant host env passthrough allowlist (comma-separated):\n  - `OPENCLAW_VARIANT_\u003cOPENCLAW|NANOCLAW|IRONCLAW\u003e_CONTAINER_ENV_KEYS`\n  - values are read from the runner host env and injected as container env\n- startup stabilization check:\n  - `OPENCLAW_DOCKER_STARTUP_STABILIZE_MS` (default `1000`)\n  - if container exits immediately after `start`, lifecycle now fails fast with recent logs\n- `start` runs `docker start`.\n- `stop` runs `docker stop`.\n- `delete` runs `docker rm -f`.\n- query surfaces include runtime metadata (`backend`, image, container status, local UI URL, setup status, last error).\n- canonical UI auth env is unified across variants: `SANDBOX_UI_BEARER_TOKEN` (`SANDBOX_UI_AUTH_MODE=bearer`).\n- per-instance token retrieval for owner-scoped sessions: `GET /instances/{id}/access`.\n- canonical env naming + token generation come from\n  `sandbox-runtime::ingress_access_control` (re-exported by `openclaw-sandbox-blueprint-lib`).\n- compatibility aliases are still injected for existing images (`CLAW_UI_BEARER_TOKEN`, `OPENCLAW_GATEWAY_TOKEN`, `NANOCLAW_UI_BEARER_TOKEN`, `GATEWAY_AUTH_TOKEN`).\n- setup bootstrap can be triggered with `POST /instances/{id}/setup/start` (scoped session required).\n- default setup commands:\n  - OpenClaw: `openclaw onboard`\n  - NanoClaw: no default setup command (owner drives setup via terminal/chat flow)\n  - IronClaw: `ironclaw onboard`\n- command override per variant: `OPENCLAW_VARIANT_\u003c...\u003e_SETUP_COMMAND`\n- setup env allowlist per variant: `OPENCLAW_VARIANT_\u003c...\u003e_SETUP_ENV_KEYS` (comma-separated)\n- optional chat command per variant:\n  - `OPENCLAW_VARIANT_\u003cOPENCLAW|NANOCLAW|IRONCLAW\u003e_CHAT_COMMAND`\n  - command runs inside the container and receives prompt through env var `OPENCLAW_CHAT_PROMPT`\n\nThis repository does not publish or bundle the variant images. You must provide\nvalid image references for your environment.\n\nReal-image runtime notes:\n\n- official OpenClaw image (`ghcr.io/openclaw/openclaw`) is loopback-bound by default.\n  The runtime applies a host-reachable startup command automatically for this image.\n- official IronClaw worker image requires non-interactive auth env to avoid startup prompts.\n  Provide `NEARAI_API_KEY` or `NEARAI_SESSION_TOKEN` in the runner host env.\n- NanoClaw upstream `container/build.sh` image is a one-shot agent-runner image.\n  The runtime defaults `nanoclaw-agent:*` to a long-lived terminal-first profile\n  (`tail -f /dev/null` with shell entrypoint override) so owners can complete\n  canonical setup (`claude` then `/setup`) through scoped terminal/chat surfaces.\n  You can override this via `OPENCLAW_VARIANT_NANOCLAW_CONTAINER_COMMAND`.\n\nAgent UI compatibility:\n\n- `@tangle-network/agent-ui` terminal/session hooks are compatible when using\n  `apiUrl=http://\u003coperator\u003e/instances/\u003cinstance-id\u003e` with scoped session bearer\n  token.\n\n## Security posture (current)\n\n- Containers are bound to loopback only (`127.0.0.1` port mapping), not exposed directly on public interfaces.\n- Each Docker instance receives a unique bearer token under canonical env key `SANDBOX_UI_BEARER_TOKEN`.\n- Operator API setup execution is restricted to **instance-scoped sessions** (owner flow), not operator-wide tokens.\n- UI token retrieval is restricted to **instance-scoped sessions** (owner flow), not operator-wide tokens.\n- Setup env keys are validated and only injected for the setup execution call; they are not persisted in instance state.\n- UI ingress should still be fronted by authenticated tunnel/reverse proxy before internet exposure.\n\n## State location\n\nInstance state persists at:\n\n- `$OPENCLAW_INSTANCE_STATE_DIR/instances.json` (preferred)\n- fallback: `$OPENCLAW_STATE_DIR/instances.json` (compatibility path)\n- default: `/tmp/openclaw-sandbox-blueprint/instances.json`\n\n## TEE variant\n\nRun the dedicated TEE variant binary:\n\n```bash\nSERVICE_ID=\u003cid\u003e HTTP_RPC_ENDPOINT=\u003curl\u003e KEYSTORE_URI=\u003curi\u003e \\\n  cargo run --release --bin openclaw-tee-sandbox-blueprint\n```\n\n## Engineering workflow\n\n- State-changing operations are jobs only (`create`, `start`, `stop`, `delete`).\n- Read-only operations stay in query surfaces (operator HTTP API).\n- Ship in small, composable PRs with explicit validation evidence.\n- CI runs Rust checks plus synthetic Docker integration tests in\n  `.github/workflows/ci.yml`.\n- Use `scripts/ci/run-real-variant-runtime-tests.sh` before releases to verify\n  official OpenClaw/IronClaw runtime images plus NanoClaw upstream build path.\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for branch, commit, and PR standards.\nSee [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for detailed architecture notes.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftangle-network%2Fopenclaw-sandbox-blueprint","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftangle-network%2Fopenclaw-sandbox-blueprint","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftangle-network%2Fopenclaw-sandbox-blueprint/lists"}