OpenClawps

MLOps-inspired CI/CD for OpenClaw agent fleets. Prescriptive, versioned system images provide a managed runtime. Portable data disks carry agent identity, workspace, and state across VM replacements and image upgrades. Deploy a fully equipped, desktop-running claw on Azure in one command. Upgrade it without losing state in another.

github.com/logan-robbins/openclawps
linkedin.com/in/loganrobbins
Prerequisites
CLI Tools
Azure CLI
az login — any subscription
az login
envsubst
Renders cloud-init templates
brew install gettext
sshpass
Deploy-time SSH automation
brew install sshpass
Configuration
Telegram Bot Token
Unique per claw — create via @BotFather
LLM API Key
Any supported provider: xAI, OpenAI, or Anthropic
cp .env.template .env
Full configuration reference in .env.template and README. Each claw gets its own .env — same image, different config, different claw.
Lifecycle Pipeline — deploy.sh [mode]
1
deploy.sh scratchBuild from Source

Stock Ubuntu 24.04, cloud-init full install — xfce4 desktop, Chrome, OpenClaw, Claude Code (~10 min)

cloud-init.yaml
Full graphical desktop on :0 with VNC
MLOps: Train from scratch
2
deploy.sh bake x.y.zCapture Image

Generalize VM into immutable versioned image, push to Azure Compute Gallery

gallery/claw-base/x.y.z
waagent deprovision, secrets stripped
MLOps: Registry push
3
deploy.sh (default)Stamp Out a Claw

Golden image + fresh data disk — fleet-friendly, same image different .env (~2 min)

cloud-init-slim.yaml (secrets only)
Data disk auto-partitioned + seeded
MLOps: Inference deploy
4
deploy.sh upgradeUpgrade in Place

Swap VM to new image version, same data disk — identity, workspace, memory, credentials preserved

Detach data disk, delete VM, recreate from new image, reattach
NIC + public IP reused, migration scripts run automatically
MLOps: Rolling update
Upgrade cycle: bake new image version → upgrade existing instances → data disk preserved across versions
Runtime Topology — Inside a Running Claw
Azure Resource Group
VNet 10.0.0.0/16
Subnet 10.0.0.0/24 + NSG (AllowAll)
Public IP (Standard SKU)Static across stop/start cycles
VM Standard_D2s_v3 Ubuntu 24.04
lightdm
Auto-login azureuser into xfce4-session on :0
x11vnc:5900
Attached to :0, shared + viewonly, password auth
Display :0 — dummy Xorg 1920x1080 — persists across VNC connect/disconnect — DPMS disabled
OpenClaw Gateway (systemd)
Telegram Channel
Bot API polling, DM policy: allowlist or open
Agent "main":18789
Model: xai/grok-4 (200k ctx) | Sandbox: off | Max concurrent: 4 | Elevated: full
Exec: full autonomyChrome (CDP, .deb)Web searchWeb fetch
openclaw.json exec-approvals.json SOUL.md
Claude Code Sidecar
tmux session: claude
claude remote-control --name "$(hostname)" | Working dir: ~/workspace
Started by /opt/claw/start-claude.sh — idempotent, skips if session exists
Storage
OS Disk
From gallery image
Stateless — replaced on upgrade
Data Disk /mnt/claw-dataPERSISTENT
Survives upgrades — detach/reattach preserves agent identity
openclaw/workspace/.envSOUL.mdvnc-password.txtupdate-version.txt.claw-initialized
Symlinked: ~/.openclaw → /mnt/claw-data/openclaw | ~/workspace → /mnt/claw-data/workspace
Inbound :22SSH (password auth)
Inbound :5900VNC (x11vnc, shared + viewonly)
Loopback :18789OpenClaw Gateway (not externally exposed)
api.x.aiOutbound — LLM inference (xAI / Grok-4)
api.telegram.orgOutbound — Bot API polling
*.google.comOutbound — Chrome / CDP browsing
NSGAllowAll (wide open) — ufw disabled
sudoNOPASSWD ALL — full autonomy
Exec sandboxoff — containment at infra boundary, not inside guest
Compute GalleryclawGallery/claw-base/x.y.z
Boot Orchestration — /opt/claw/boot.sh (runs every VM start)
1
Mount disk
LUN 0 discovery, auto-partition if raw, fstab by UUID
2
Seed defaults
First boot: copy /opt/claw/defaults/ to data disk
3
Symlinks
~/.openclaw and ~/workspace point to /mnt/claw-data/
4
Permissions
chown -R azureuser on data mount and home dir
5
VNC sync
Data disk password pushed to /etc/x11vnc.pass
6
Run updates
Numbered scripts in /opt/claw/updates/ (version-gated)
7
Start services
lightdm, x11vnc, openclaw-gateway, claude sidecar
Update Mechanism — run-updates.sh
/opt/claw/updates/
  001-initial.sh    # baseline (no-op)
  002-test-marker.sh # example migration
  NNN-*.sh         # applied in order
Version tracked in /mnt/claw-data/update-version.txt. Each script runs once, version advances on success.
Health Validation — verify.sh (33 checks)
Runs post-deploy via SSH. Catches misconfigs before they become mystery failures:
Disk mountedSymlinks validConfig JSON validServices activePorts listeningBinaries foundEnv vars set
OpenClawps / MLOps Conceptual Mapping
OpenClawps ConceptMLOps EquivalentNotes
deploy.sh scratchTrain from scratchFull environment built from stock Ubuntu
deploy.sh bakeRegistry pushGeneralized VM captured to Compute Gallery
Azure Compute GalleryModel / artifact registryVersioned golden images (claw-base/x.y.z)
deploy.sh (default)Inference deploymentSpin up instance from image + data disk
deploy.sh upgradeRolling updateNew image, same persistent state
Data DiskFeature store / stateAgent identity, workspace, config survive upgrades
boot.shInference server initMount, seed, wire, start — every boot
run-updates.shDrift remediationVersioned migration scripts applied in order
verify.shModel validation33-point post-deploy health checks across all subsystems
SOUL.mdModel cardAgent personality / identity definition
.envSecrets managementNever committed, injected at deploy via envsubst