This repository is a blueprint-sdk blueprint for orchestrating OpenClaw
instances on the Tangle network. It follows the standard blueprint-sdk
patterns: Rust workspace, sol!-defined ABI types, TangleLayer-wrapped job
handlers, and a BlueprintRunner entry point.
This repository is the product-layer blueprint. It is not the
infrastructure substrate. Runtime isolation, VM orchestration, and low-level
network/security enforcement are delegated to the sandbox runtime (see
ai-agent-sandbox-blueprint for the runtime reference).
Within product-layer scope, this repo can execute lifecycle through a Docker
backend; Firecracker/microVM substrate remains delegated.
Shared ingress access primitives reused from ai-agent-sandbox-blueprint:
- Canonical env keys for UI auth (
SANDBOX_UI_AUTH_MODE,SANDBOX_UI_BEARER_TOKEN) - Per-instance bearer token generation
- Canonical+alias env binding helpers
Library crate containing all business logic:
lib.rs— ABI type definitions (sol!macro), job ID constants, and theRouterthat maps job IDs to handlers viaTangleLayer.jobs/lifecycle.rs— Handler implementations forcreate,start,stop, anddeleteoperations. Each handler receivesCaller,CallId, andTangleArg<T>extractors and returnsTangleResult<T>. Handlers call the runtime adapter boundary instead of touching storage directly.runtime_adapter.rs— Runtime adapter contract (InstanceRuntimeAdapter) and implementations (LocalStateRuntimeAdapter,DockerRuntimeAdapter).query.rs— reusable read-only query helpers (instance/template views).auth.rs— challenge/session auth service for operator API access control.operator_api.rs— axum router and handlers for/(built-in control-plane UI),/health,/templates,/instances, auth/session endpoints, and setup trigger endpoint.state.rs— File-backed persistent store forInstanceRecordobjects. Usesonce_cell::OnceCell+Mutex<BTreeMap>with JSON persistence.error.rs— Domain error type (InstanceError) with conversions toStringfor on-chain error reporting.
Binary crate with the runner entry point:
main.rs— LoadsBlueprintEnvironment, connects to Tangle, createsTangleProducer/TangleConsumer, and startsBlueprintRunnerwith the library'srouter().
TEE variant wrappers over the instance blueprint:
openclaw-tee-sandbox-blueprint-libre-exports the base library and exposestee_router()which forcesOPENCLAW_EXECUTION_TARGET=tee.openclaw-tee-sandbox-blueprint-binruns the shared lifecycle router with TEE execution target preconfigured.
All state mutations go through on-chain jobs. Each job:
- Is triggered by a
JobSubmittedevent on-chain. - Receives ABI-encoded input via
TangleArg. - Validates caller ownership.
- Persists the state change.
- Returns ABI-encoded output via
TangleResult.
| ID | Handler | Transition |
|---|---|---|
| 0 | create_instance |
— → Stopped |
| 1 | start_instance |
Stopped → Running |
| 2 | stop_instance |
Running → Stopped |
| 3 | delete_instance |
Stopped/Running → Deleted |
Read-only operations are not jobs. They are served via the operator HTTP API (axum):
GET /— static control-plane UI shellGET /instances— list instances (scoped by bearer claims)GET /instances/{id}— instance detailGET /instances/{id}/access— fetch per-instance UI bearer token (scoped session only)POST /instances/{id}/setup/start— trigger variant setup bootstrap (scoped session only)GET /instances/{id}/tee/public-key— fetch TEE-bound public key (scoped session only, TEE-only instances)POST /instances/{id}/tee/sealed-secrets— forward encrypted secrets blob (scoped session only, TEE-only instances)GET /instances/{id}/tee/attestation— fetch current TEE attestation (scoped session only, TEE-only instances)POST /instances/{id}/sshandDELETE /instances/{id}/ssh— SSH key managementPOST /instances/{id}/terminals— create terminal sessionGET /instances/{id}/terminals/{terminalId}/stream— terminal SSE streamPOST /instances/{id}/terminals/{terminalId}/execute— terminal command execDELETE /instances/{id}/terminals/{terminalId}— close terminal sessionGET/POST/PATCH/DELETE /instances/{id}/session/sessions[...]— chat session CRUDGET /instances/{id}/session/events?sessionId=...— chat SSE streamGET /templates— list template packsGET /health— liveness check
Auth/session endpoints:
POST /auth/challenge— create wallet challengePOST /auth/session/wallet— verify wallet signature and issue sessionPOST /auth/session/token— access-token login and session issuance
Operator API startup defaults:
- disabled by default (
OPENCLAW_OPERATOR_HTTP_ENABLED=trueto enable) - default bind when enabled:
127.0.0.1:8787
Instance records are stored in a JSON file at:
$OPENCLAW_INSTANCE_STATE_DIR/instances.json(preferred)- fallback:
$OPENCLAW_STATE_DIR/instances.json(compatibility path) - default:
/tmp/openclaw-sandbox-blueprint/instances.json
The store uses once_cell::OnceCell for lazy initialization and
std::sync::Mutex for thread safety. All writes persist to disk immediately.
Template packs live in config/templates/ and define SOUL/USER/TOOLS presets
for different use cases. Each pack contains:
template.json— metadata (id, name, mode, description)SOUL.md— agent identity and guardrailsUSER.md— target audience and goalsTOOLS.md— tool access matrix
The adapter boundary is implemented:
InstanceRuntimeAdapteris the lifecycle contract consumed by product jobs.LocalStateRuntimeAdapteris the default adapter (file-backed local state).DockerRuntimeAdapterexecutes real container lifecycle via Docker CLI whenOPENCLAW_RUNTIME_BACKEND=dockerand image env vars are configured.- Runtime adapter also exposes container command execution and SSH key updates so operator APIs can provide terminal/chat/SSH surfaces without mock backends.
- Canonical UI auth env key across variants is
SANDBOX_UI_BEARER_TOKEN(SANDBOX_UI_AUTH_MODE=bearer), with compatibility aliases still injected for existing images. - Runtime maps UI ports to loopback host addresses only (
127.0.0.1), so public exposure must happen through an authenticated tunnel/reverse proxy layer. init_instance_runtime_adapter(...)allows replacing the default with a sandbox-runtime-backed adapter.
This keeps lifecycle handlers stable while runtime backend implementations evolve.
Create requests accept optional config_json profile settings:
claw_variant:openclaw|nanoclaw|ironclawui.expose_public_url: bool (defaulttrue)ui.subdomain: optional preferred subdomainui.auth_mode:wallet_signature|access_tokenaccess_tokensessions validate againstOPENCLAW_UI_ACCESS_TOKEN(operator-side env)
Persisted instance records include:
claw_variant(typed enum)execution_target(standard|tee)ui_access.public_urlui_access.tunnel_status(pending|active|disabled)ui_access.auth_modeui_access.owner_only(defaulttrue)
When OPENCLAW_UI_BASE_DOMAIN is set, lifecycle create computes
https://<subdomain>.<base_domain> as the instance public URL.
Canonical variant-source references live in docs/VARIANT-REFERENCE.md.