Files
yuan-lab-llm--clawmanager/docs/hermes-runtime-agent-development.md
T
wehub-resource-sync 6d978fe483
Build / Frontend Build (push) Waiting to run
Build / Backend Build (push) Waiting to run
Build / Docker Build (push) Blocked by required conditions
Build / Kubernetes Deploy Smoke Test (push) Blocked by required conditions
chore: import upstream snapshot with attribution
2026-07-13 12:35:24 +08:00

30 KiB

Hermes Runtime Image and Agent Development Guide

This guide is for Hermes image and agent developers. It explains how to build a ClawManager-managed Hermes runtime image on top of Webtop, and how the embedded Hermes agent should integrate with ClawManager Agent Control Plane so Hermes can behave like OpenClaw: report live runtime status, report health and system metrics, sync skill inventory, upload skill packages, and poll runtime commands.

Mode note: this document describes the Hermes Pro Webtop/instance-agent path. For Hermes Lite, implement Runtime Pod Agent V2 instead. See Hermes Lite / Pro Agent 开发说明.

Goals

A Hermes image must satisfy two layers of requirements:

  • Desktop access layer: keep the Webtop/KasmVNC runtime model. ClawManager accesses the desktop through the instance Service on port 3001.
  • Runtime agent layer: run a long-lived Hermes agent inside the image. The agent registers with ClawManager, sends heartbeats, reports state, syncs skills, and executes platform-issued commands.

Current Hermes runtime defaults in ClawManager:

  • Port: 3001
  • PVC mount path: /config
  • Persistent directory: /config/.hermes
  • Default title: Hermes Runtime
  • Proxy path: ClawManager rewrites SUBFOLDER to /api/v1/instances/{instance_id}/proxy/ when the instance is created.

Do not change the port, PVC mount path, or persistent directory in the image. ClawManager mounts the instance PVC at /config so Webtop desktop files such as /config/Desktop and Hermes runtime files under /config/.hermes persist together.

Image Build Requirements

Use a LinuxServer Webtop image as the base image, for example:

FROM lscr.io/linuxserver/webtop:ubuntu-xfce

USER root

# 1. Install Hermes runtime dependencies.
# Keep this as an example. The Hermes project should own the real install steps.
# RUN apt-get update && apt-get install -y ... && rm -rf /var/lib/apt/lists/*

# 2. Install Hermes itself.
# COPY hermes /opt/hermes

# 3. Install the ClawManager Hermes agent.
COPY hermes-agent /usr/local/bin/hermes-agent
RUN chmod +x /usr/local/bin/hermes-agent

# 4. Register an s6 longrun service so the agent starts with the Webtop container.
COPY root/ /

ENV TITLE="Hermes Runtime"
ENV SUBFOLDER="/"

EXPOSE 3001

Webtop uses s6 overlay for process supervision. The Hermes agent can run as a longrun service:

root/
  etc/
    s6-overlay/
      s6-rc.d/
        hermes-agent/
          type
          run
        user/
          contents.d/
            hermes-agent

type:

longrun

run:

#!/usr/bin/with-contenv bash
set -euo pipefail

if [ "${CLAWMANAGER_AGENT_ENABLED:-false}" != "true" ]; then
  echo "ClawManager Hermes agent disabled"
  sleep infinity
fi

exec /usr/local/bin/hermes-agent

The Hermes agent must not bind to 3001. Port 3001 belongs to the Webtop desktop entrypoint. The agent only needs outbound HTTP access to ClawManager.

Environment Variables Injected by ClawManager

The Hermes image must read configuration from environment variables. Do not hardcode ClawManager URLs, instance IDs, tokens, or persistent paths into the image.

Base Webtop variables:

Variable Description
TITLE Desktop title. Hermes defaults to Hermes Runtime.
SUBFOLDER Reverse proxy subpath. ClawManager rewrites it at runtime.
HTTP_PROXY / HTTPS_PROXY Injected when platform egress proxy is enabled.
NO_PROXY Platform-internal services and localhost are added automatically.

Agent Control Plane variables:

Variable Description
CLAWMANAGER_AGENT_ENABLED Start the Hermes agent when set to true.
CLAWMANAGER_AGENT_BASE_URL ClawManager API base URL, without the /api/v1/agent suffix.
CLAWMANAGER_AGENT_BOOTSTRAP_TOKEN One-time bootstrap token used for initial registration.
CLAWMANAGER_AGENT_INSTANCE_ID Current ClawManager instance ID.
CLAWMANAGER_AGENT_PROTOCOL_VERSION Current protocol version, v1.
CLAWMANAGER_AGENT_PERSISTENT_DIR Persistent directory. Hermes uses /config/.hermes.
CLAWMANAGER_AGENT_DISK_LIMIT_BYTES Instance disk quota in bytes.

Runtime resource bootstrap variables:

Variable Description
CLAWMANAGER_HERMES_CHANNELS_JSON Channel configuration injected at instance creation time.
CLAWMANAGER_HERMES_SKILLS_JSON Skill configuration injected at instance creation time.
CLAWMANAGER_HERMES_BOOTSTRAP_MANIFEST_JSON Manifest for the current bootstrap payload.
CLAWMANAGER_RUNTIME_CHANNELS_JSON Generic runtime alias for channel configuration.
CLAWMANAGER_RUNTIME_SKILLS_JSON Generic runtime alias for skill configuration.
CLAWMANAGER_RUNTIME_BOOTSTRAP_MANIFEST_JSON Generic runtime alias for the bootstrap manifest.

For compatibility with the existing OpenClaw resource center, ClawManager also keeps the original CLAWMANAGER_OPENCLAW_* variables. Hermes agents should prefer CLAWMANAGER_HERMES_*, then fall back to CLAWMANAGER_RUNTIME_*, and finally to CLAWMANAGER_OPENCLAW_*.

Platform-side note: some Agent Control Plane payload fields still use historical OpenClaw names. Until those fields are renamed into generic runtime fields, Hermes agents should reuse compatible fields such as openclaw_status, openclaw_pid, and openclaw_version to describe Hermes runtime state.

Channel and Skill Bootstrap Consumption

Hermes agents must handle two kinds of injection:

  • Runtime bootstrap injection: channels, configuration skills, session templates, agents, scheduled tasks, and related resources selected at instance creation time are injected through environment variables.
  • Platform skill installation: reusable platform skills selected at instance creation time are first attached to the instance. ClawManager then sends an install_skill command. The agent must download and install the skill package.

Read Order

At startup, read bootstrap payloads in this priority order. Use the first non-empty value:

Resource Preferred variable Fallback variables
Manifest CLAWMANAGER_HERMES_BOOTSTRAP_MANIFEST_JSON CLAWMANAGER_RUNTIME_BOOTSTRAP_MANIFEST_JSON, CLAWMANAGER_OPENCLAW_BOOTSTRAP_MANIFEST_JSON
Channels CLAWMANAGER_HERMES_CHANNELS_JSON CLAWMANAGER_RUNTIME_CHANNELS_JSON, CLAWMANAGER_OPENCLAW_CHANNELS_JSON
Config Skills CLAWMANAGER_HERMES_SKILLS_JSON CLAWMANAGER_RUNTIME_SKILLS_JSON, CLAWMANAGER_OPENCLAW_SKILLS_JSON
Session Templates CLAWMANAGER_HERMES_SESSION_TEMPLATES_JSON CLAWMANAGER_RUNTIME_SESSION_TEMPLATES_JSON, CLAWMANAGER_OPENCLAW_SESSION_TEMPLATES_JSON
Agents CLAWMANAGER_HERMES_AGENTS_JSON CLAWMANAGER_RUNTIME_AGENTS_JSON, CLAWMANAGER_OPENCLAW_AGENTS_JSON
Scheduled Tasks CLAWMANAGER_HERMES_SCHEDULED_TASKS_JSON CLAWMANAGER_RUNTIME_SCHEDULED_TASKS_JSON, CLAWMANAGER_OPENCLAW_SCHEDULED_TASKS_JSON

If a variable is missing or empty, treat it as an empty config. Do not fail agent startup for missing optional bootstrap payloads. If a variable exists but contains invalid JSON, log a clear error and report health.bootstrap_config or health.config_loader as error in the next state report.

Recommended local bootstrap state:

/config/.hermes/hermes-agent/bootstrap/
  manifest.json
  channels.json
  skills.json
  applied-state.json

Do not print channel tokens, secrets, webhooks, bootstrap tokens, session tokens, or AI Gateway API keys in logs.

Channel Injection

CLAWMANAGER_HERMES_CHANNELS_JSON is a JSON object keyed by resource key. Example:

{
  "feishu": {
    "enabled": true,
    "domain": "feishu",
    "defaultAccount": "main",
    "accounts": {
      "main": {
        "appId": "cli_xxx",
        "appSecret": "secret",
        "enabled": true
      }
    },
    "requireMention": true
  },
  "telegram": {
    "enabled": true,
    "botToken": "123456:xxx",
    "dmPolicy": "open",
    "allowFrom": ["*"]
  }
}

Hermes agent behavior:

  1. Use the top-level key as the runtime channel ID, for example feishu, telegram, slack, or dingtalk-connector. Resource-specific Feishu/Lark keys such as feishu-ops must be folded into the feishu.accounts map before injection.
  2. Skip channels with enabled=false, but keep their config on disk so future updates can re-enable them.
  3. Convert channel config into Hermes-native notification or messaging configuration. A reasonable default path is /config/.hermes/channels.json, unless Hermes has a native config location.
  4. Preserve unknown fields so future ClawManager extensions are not lost.
  5. If Hermes does not support a channel type yet, mark that channel as unsupported in health.channels and keep registration and heartbeats running.

Config Skill Injection

CLAWMANAGER_HERMES_SKILLS_JSON is a list of configuration resources. It is not a zip package. It is used to inject resource-center configuration skills into the runtime at instance creation time. Example:

{
  "schemaVersion": 1,
  "items": [
    {
      "id": 5,
      "type": "skill",
      "key": "support-bot",
      "name": "Support Bot",
      "version": 1,
      "tags": ["skill"],
      "content": {
        "schemaVersion": 1,
        "kind": "skill",
        "format": "skill/custom@v1",
        "dependsOn": [],
        "config": {
          "prompt": "help"
        }
      }
    }
  ]
}

Hermes agent behavior:

  1. Iterate over items and use key as the stable skill identifier.
  2. Read content.config and translate it into executable Hermes skill configuration.
  3. If Hermes stores skills as directories, write the generated config to /config/.hermes/skills/{key}/skill.json. Keep the raw content as well for debugging.
  4. Calculate content_md5 for the written skill directory and include it in the next skills/inventory report.
  5. For skills generated from bootstrap config, inventory source should be injected_by_clawmanager or bootstrap_config. If source is injected_by_clawmanager and skill_id uses a platform external ID, use the format skill-{id}, for example skill-5.

Config skills and platform skill package installation are separate paths:

  • CLAWMANAGER_HERMES_SKILLS_JSON: read and apply during startup. Do not wait for a command.
  • install_skill command: download and install a platform-uploaded zip skill package at runtime.

Bootstrap Manifest

CLAWMANAGER_HERMES_BOOTSTRAP_MANIFEST_JSON describes the payloads injected for the current bootstrap. Example:

{
  "schemaVersion": 1,
  "mode": "manual",
  "resources": [
    { "id": 5, "type": "skill", "key": "support-bot", "name": "Support Bot", "version": 1 }
  ],
  "payloads": [
    { "env": "CLAWMANAGER_HERMES_CHANNELS_JSON", "count": 1 },
    { "env": "CLAWMANAGER_HERMES_SKILLS_JSON", "count": 1 }
  ]
}

The agent can use the manifest as an idempotency key. If the manifest hash has not changed, skip reapplying the same bootstrap payload. If it changes, reapply channel and config skill payloads, then send one state report and one full skill inventory report.

Skills Selected During Instance Creation

When a user selects existing platform skills while creating a Hermes instance, ClawManager attaches those skills to the instance and creates install_skill commands. The Hermes agent must implement this command. Otherwise the UI selection only exists in platform records and the skill will not be installed inside the instance.

Example install_skill payload:

{
  "skill_id": "skill-12",
  "skill_version": "skill-version-34",
  "target_name": "weather-tool",
  "content_md5": "d41d8cd98f00b204e9800998ecf8427e"
}

Processing steps:

  1. Download the version package:
GET {CLAWMANAGER_AGENT_BASE_URL}/api/v1/agent/skills/versions/{skill_version}/download
Authorization: Bearer {session_token}
  1. Validate the zip. Reject absolute paths, ../, multiple top-level directories, and any path that would extract outside /config/.hermes/skills.
  2. Extract to /config/.hermes/skills/{target_name}. Prefer extracting into a temp directory and then atomically replacing the target directory.
  3. Recalculate directory content_md5 and compare it with the command payload. Finish the command as failed if it does not match.
  4. Send one skills/inventory report. For the installed skill, set source to injected_by_clawmanager and skill_id to the command payload skill_id.
  5. Finish the command with install_path, skill_id, skill_version, and content_md5 in result.

Agent Lifecycle

Hermes agent startup flow:

  1. Read CLAWMANAGER_AGENT_* environment variables.
  2. Read and apply runtime bootstrap payloads if present.
  3. If no local session token is available, register with the bootstrap token.
  4. Store the returned session token in /config/.hermes/hermes-agent/session.json.
  5. Send heartbeats using the interval returned by the server.
  6. Poll commands using the command poll interval returned by the server. If heartbeat returns has_pending_command=true, poll once immediately.
  7. Periodically send full state reports and skill inventory reports.
  8. If the session token expires or an API returns HTTP 401, register again with the bootstrap token.

Recommended local agent state directory:

/config/.hermes/hermes-agent/
  session.json
  state.json
  logs/
  cache/
  bootstrap/

Registration

Request:

POST {CLAWMANAGER_AGENT_BASE_URL}/api/v1/agent/register
Authorization: Bearer {CLAWMANAGER_AGENT_BOOTSTRAP_TOKEN}
Content-Type: application/json

Body example:

{
  "instance_id": 123,
  "agent_id": "hermes-123-main",
  "agent_version": "0.1.0",
  "protocol_version": "v1",
  "capabilities": [
    "runtime.status",
    "runtime.health",
    "metrics.report",
    "skills.inventory",
    "skills.upload",
    "commands.poll"
  ],
  "host_info": {
    "runtime": "hermes",
    "desktop_base": "webtop",
    "persistent_dir": "/config/.hermes",
    "port": 3001,
    "arch": "amd64"
  }
}

The response field data.session_token is the token for subsequent Agent API calls. Cache it locally, but never write it to logs.

Heartbeat

Request:

POST {CLAWMANAGER_AGENT_BASE_URL}/api/v1/agent/heartbeat
Authorization: Bearer {session_token}
Content-Type: application/json

Body example:

{
  "agent_id": "hermes-123-main",
  "timestamp": "2026-04-27T14:30:00Z",
  "openclaw_status": "running",
  "summary": {
    "runtime": "hermes",
    "hermes_status": "running",
    "hermes_pid": 245,
    "skill_count": 8,
    "active_skill_count": 8,
    "disk_used_bytes": 2147483648,
    "disk_limit_bytes": 10737418240
  }
}

Compatibility requirements:

  • openclaw_status is still the platform compatibility field. Fill it with the Hermes main process status.
  • Recommended status values: starting, running, stopped, error, unknown.
  • Default heartbeat interval is roughly 15 seconds, but use heartbeat_interval_seconds from the registration response.
  • ClawManager considers the agent online when heartbeat is received within 45 seconds, stale between 45 and 120 seconds, and offline after 120 seconds.

Full State Report

Heartbeat is the lightweight online signal. Complete runtime status, system metrics, and health information are reported through state reports.

Request:

POST {CLAWMANAGER_AGENT_BASE_URL}/api/v1/agent/state/report
Authorization: Bearer {session_token}
Content-Type: application/json

Body example:

{
  "agent_id": "hermes-123-main",
  "reported_at": "2026-04-27T14:30:00Z",
  "runtime": {
    "openclaw_status": "running",
    "openclaw_pid": 245,
    "openclaw_version": "hermes-0.4.0"
  },
  "system_info": {
    "runtime": "hermes",
    "os": "ubuntu",
    "desktop_base": "webtop",
    "sampled_at": "2026-04-27T14:30:00Z",
    "cpu": {
      "cores": 2,
      "load": {
        "1m": 0.64,
        "5m": 0.52,
        "15m": 0.40
      }
    },
    "memory": {
      "mem_total_bytes": 4294967296,
      "mem_available_bytes": 2147483648
    },
    "disk": {
      "mount_path": "/config/.hermes",
      "root_total_bytes": 10737418240,
      "root_free_bytes": 8589934592
    },
    "network": {
      "interfaces": [
        {
          "name": "eth0",
          "status": "up",
          "addresses": ["10.42.0.12"],
          "rx_bytes": 123456789,
          "tx_bytes": 98765432
        }
      ]
    }
  },
  "health": {
    "hermes_process": "ok",
    "desktop": "ok",
    "agent": "ok",
    "metrics_collector": "ok",
    "bootstrap_config": "ok",
    "channels": "ok",
    "metrics_sample_interval_seconds": 5,
    "last_skill_scan_at": "2026-04-27T14:29:30Z"
  }
}

Reporting guidance:

  • Heartbeat: send at the server-provided interval.
  • State report: send once immediately after startup, then every 5 to 10 seconds when possible.
  • Send an extra state report after Hermes main process state changes, skill inventory changes, bootstrap config changes, or command completion.

Metrics Reporting Contract

ClawManager does not provide a separate CPU, memory, disk, or network metrics endpoint. Hermes agent must include every sample in the system_info field of the state report. The backend stores this JSON as-is, and the instance detail page reads the fields below to render recent trends.

Required Fields

Path Type Unit Description
system_info.sampled_at string ISO 8601 UTC Agent sampling time.
system_info.cpu.cores number cores CPU cores available to the container.
system_info.cpu.load.1m number load average 1-minute load average.
system_info.cpu.load.5m number load average 5-minute load average.
system_info.cpu.load.15m number load average 15-minute load average.
system_info.memory.mem_total_bytes number bytes Container memory limit or system total memory.
system_info.memory.mem_available_bytes number bytes Currently available memory.
system_info.disk.root_total_bytes number bytes Total capacity of the filesystem containing /config/.hermes.
system_info.disk.root_free_bytes number bytes Free capacity of the filesystem containing /config/.hermes.
system_info.network.interfaces[].name string none Network interface name, for example eth0.
system_info.network.interfaces[].status string none Suggested values: up or down.
system_info.network.interfaces[].rx_bytes number bytes Monotonic received byte counter.
system_info.network.interfaces[].tx_bytes number bytes Monotonic transmitted byte counter.

The frontend calculates CPU percentage as load.1m / cores * 100, capped to 0..100. The agent does not need to report cpu_percent.

The frontend calculates memory percentage as (mem_total_bytes - mem_available_bytes) / mem_total_bytes * 100, and disk percentage as (root_total_bytes - root_free_bytes) / root_total_bytes * 100.

Network rates are calculated by the frontend from adjacent rx_bytes and tx_bytes samples. Report monotonic counters, not instantaneous rates. If counters reset after a container restart, the frontend will resume calculation from the next valid sample.

Sampling Sources

  • CPU load: read the first three values from /proc/loadavg.
  • CPU cores: prefer cgroup quota. For cgroup v2, read /sys/fs/cgroup/cpu.max. If there is no quota, fall back to /proc/cpuinfo or the language runtime.
  • Memory: prefer cgroup memory limit and current usage. For cgroup v2, read /sys/fs/cgroup/memory.max and /sys/fs/cgroup/memory.current. Compute mem_available_bytes = memory.max - memory.current, floored at 0. If no cgroup limit exists, use /proc/meminfo MemTotal and MemAvailable.
  • Disk: call statvfs on /config/.hermes. Keep the field names root_total_bytes and root_free_bytes, but interpret them as the filesystem containing the Hermes persistent directory.
  • Network: read /proc/net/dev. Exclude lo by default and keep business interfaces such as eth0.

Reporting Frequency

  • Send one state report with complete system_info immediately after successful startup.
  • During normal operation, sample and report every 5 seconds to match the instance detail page polling cadence.
  • If overhead is a concern, 10 seconds is acceptable. Do not sample faster than every 2 seconds.
  • When receiving collect_system_info or health_check, sample immediately, send a state report, then finish the command.

Command Result Guidance

collect_system_info finish result can reuse the same snapshot:

{
  "agent_id": "hermes-123-main",
  "status": "succeeded",
  "finished_at": "2026-04-27T14:31:05Z",
  "result": {
    "sampled_at": "2026-04-27T14:31:05Z",
    "system_info": {
      "cpu": {
        "cores": 2,
        "load": {
          "1m": 0.70,
          "5m": 0.55,
          "15m": 0.42
        }
      },
      "memory": {
        "mem_total_bytes": 4294967296,
        "mem_available_bytes": 2013265920
      },
      "disk": {
        "mount_path": "/config/.hermes",
        "root_total_bytes": 10737418240,
        "root_free_bytes": 8589934592
      },
      "network": {
        "interfaces": [
          {
            "name": "eth0",
            "status": "up",
            "rx_bytes": 124000000,
            "tx_bytes": 99000000
          }
        ]
      }
    }
  },
  "error_message": ""
}

health_check finish result should include health and system_info.sampled_at. If sampling fails, still send available fields in the state report and set health.metrics_collector to error with a short health.metrics_error message.

Metrics Acceptance

  1. Hermes agent sends two consecutive state reports roughly 5 seconds apart.
  2. GET /api/v1/instances/{instance_id}/runtime returns data.runtime.system_info.cpu, memory, disk, and network.
  3. The ClawManager instance detail page starts showing CPU, Memory, Disk, and Network metrics within 10 seconds.
  4. Creating network traffic or disk writes changes the corresponding trend in later samples.

Skill Inventory Sync

Hermes agent must discover skills installed inside the instance and report inventory to ClawManager.

Recommended skill root:

/config/.hermes/skills

Optional environment override:

HERMES_SKILL_DIRS=/config/.hermes/skills

Each skill should be managed as a directory. For every skill, calculate content_md5 and report it:

POST {CLAWMANAGER_AGENT_BASE_URL}/api/v1/agent/skills/inventory
Authorization: Bearer {session_token}
Content-Type: application/json

Body example:

{
  "agent_id": "hermes-123-main",
  "reported_at": "2026-04-27T14:30:00Z",
  "mode": "full",
  "trigger": "startup",
  "skills": [
    {
      "skill_id": "hermes-weather",
      "skill_version": "1.2.0",
      "identifier": "hermes-weather",
      "install_path": "/config/.hermes/skills/hermes-weather",
      "content_md5": "d41d8cd98f00b204e9800998ecf8427e",
      "source": "discovered_in_instance",
      "type": "hermes-skill",
      "size_bytes": 20480,
      "file_count": 12,
      "metadata": {
        "runtime": "hermes",
        "manifest": "skill.json"
      }
    }
  ]
}

mode semantics:

  • full: complete inventory. ClawManager marks instance skills missing from this report as removed.
  • incremental: partial update. Only skills in this report are updated.

Recommended behavior:

  • Send one full inventory after startup.
  • Use file watching or periodic scanning for later incremental updates.
  • When the platform sends sync_skill_inventory or refresh_skill_inventory, run a full scan.

content_md5 Calculation

ClawManager content_md5 is a skill directory content fingerprint, not a zip file MD5. The full algorithm is defined in Skill Content MD5 Calculation Spec.

The most common mistake is top-level directory handling:

  • During inventory, calculate against the contents of /config/.hermes/skills/{skill_name}.
  • During upload, the zip must contain one top-level directory named {skill_name}/.
  • ClawManager strips the zip top-level {skill_name}/ once before validation.
  • Do not strip internal directories such as src/, lib/, or dist/.

For example, if the local file is /config/.hermes/skills/weather/src/main.py, the relative path used for MD5 must be src/main.py, not weather/src/main.py and not main.py.

The agent must use the same directory content and the same algorithm for inventory and collect_skill_package upload. Otherwise ClawManager will return skill package md5 mismatch.

Skill Package Upload

When ClawManager finds a skill blob without object content, it sends a collect_skill_package command. Hermes agent should zip the corresponding skill directory and upload it.

Request:

POST {CLAWMANAGER_AGENT_BASE_URL}/api/v1/agent/skills/upload
Authorization: Bearer {session_token}
Content-Type: multipart/form-data

Form fields:

Field Description
file Zip package. It must contain exactly one top-level skill directory.
agent_id Current agent ID.
skill_id Skill ID from inventory.
skill_version Skill version from inventory.
identifier Skill name or key.
content_md5 Directory fingerprint reported in inventory.
source Usually discovered_in_instance or injected_by_clawmanager.

Zip structure example:

hermes-weather/
  skill.json
  main.py
  README.md

Do not upload multiple top-level directories. Do not put loose files at the zip root. ClawManager rejects both formats.

Command Polling and Execution

Hermes agent polls commands with the session token:

GET {CLAWMANAGER_AGENT_BASE_URL}/api/v1/agent/commands/next
Authorization: Bearer {session_token}

If data.command is null, no command is pending. If a command exists, the agent must:

  1. Call the start endpoint.
  2. Execute the command.
  3. Call the finish endpoint with the result.
  4. Always finish failed commands with status=failed.

Start:

POST {CLAWMANAGER_AGENT_BASE_URL}/api/v1/agent/commands/{id}/start
Authorization: Bearer {session_token}
Content-Type: application/json
{
  "agent_id": "hermes-123-main",
  "started_at": "2026-04-27T14:31:00Z"
}

Finish:

POST {CLAWMANAGER_AGENT_BASE_URL}/api/v1/agent/commands/{id}/finish
Authorization: Bearer {session_token}
Content-Type: application/json
{
  "agent_id": "hermes-123-main",
  "status": "succeeded",
  "finished_at": "2026-04-27T14:31:05Z",
  "result": {
    "message": "skill inventory refreshed",
    "skill_count": 8
  },
  "error_message": ""
}

Current platform command types:

  • collect_system_info
  • health_check
  • sync_skill_inventory
  • refresh_skill_inventory
  • collect_skill_package
  • install_skill
  • update_skill
  • uninstall_skill
  • remove_skill
  • disable_skill
  • quarantine_skill
  • handle_skill_risk
  • start_openclaw
  • stop_openclaw
  • restart_openclaw
  • apply_config_revision
  • reload_config

Minimum Hermes implementation:

  • collect_system_info
  • health_check
  • sync_skill_inventory
  • refresh_skill_inventory
  • collect_skill_package
  • install_skill

Commands containing openclaw are currently compatibility names. Hermes may ignore start_openclaw, stop_openclaw, and restart_openclaw until Hermes-specific or generic runtime commands are added.

Skill Installation and Version Download

If Hermes supports platform-managed skill installation, command payloads may include a skill version identifier. The agent can download the zip package through:

GET {CLAWMANAGER_AGENT_BASE_URL}/api/v1/agent/skills/versions/{external_version_id}/download
Authorization: Bearer {session_token}

After downloading:

  1. Validate the zip path boundaries.
  2. Extract it under /config/.hermes/skills.
  3. Recalculate content_md5.
  4. Send skills/inventory.
  5. Finish the command with install path, skill ID, version, and content_md5.

Local Development

Use the following variables to run the agent locally:

export CLAWMANAGER_AGENT_ENABLED=true
export CLAWMANAGER_AGENT_BASE_URL=http://127.0.0.1:8080
export CLAWMANAGER_AGENT_BOOTSTRAP_TOKEN=agt_boot_xxx
export CLAWMANAGER_AGENT_INSTANCE_ID=123
export CLAWMANAGER_AGENT_PROTOCOL_VERSION=v1
export CLAWMANAGER_AGENT_PERSISTENT_DIR=/config/.hermes
export CLAWMANAGER_AGENT_DISK_LIMIT_BYTES=10737418240

For local bootstrap testing, also set:

export CLAWMANAGER_HERMES_CHANNELS_JSON='{}'
export CLAWMANAGER_HERMES_SKILLS_JSON='{"schemaVersion":1,"items":[]}'
export CLAWMANAGER_HERMES_BOOTSTRAP_MANIFEST_JSON='{"schemaVersion":1,"mode":"manual","payloads":[]}'

Never commit real tokens, channel secrets, Gateway API keys, or downloaded session tokens into images, repositories, or logs. At most, log a short token prefix and suffix for debugging.

Acceptance Checklist

Before delivering a Hermes image, verify:

  • The Webtop desktop is reachable through the ClawManager instance proxy.
  • /config is mounted and both /config/Desktop and /config/.hermes persist across restarts.
  • The agent registers and starts heartbeat within 30 seconds.
  • The instance detail page shows agent online, runtime running, and an updated last report time.
  • CPU, memory, disk, and network metrics are visible and refresh continuously.
  • Channel bootstrap payloads are applied or clearly reported as unsupported.
  • Config skill bootstrap payloads are applied and included in inventory.
  • Skill inventory syncs after changes under the Hermes skill directory.
  • For discovered skills without stored object content, collect_skill_package causes the agent to upload a valid zip package.
  • content_md5 in inventory and package upload match the ClawManager specification.
  • Command execution calls start and finish, including clear error_message on failure.
  • Network interruption, ClawManager restart, or session expiration causes retry and re-registration.

Platform-Side Companion Checklist

ClawManager must keep the following capabilities for Hermes to work end to end:

  • Inject CLAWMANAGER_AGENT_* variables for hermes during instance creation and start.
  • Allow hermes instances to register with the Agent Control Plane.
  • Inject CLAWMANAGER_LLM_* and OpenAI-compatible variables so Hermes can access models through ClawManager AI Gateway.
  • Inject Hermes and generic runtime bootstrap variables for channels, skills, and related resources.
  • Mount persistent storage at /config, while keeping Hermes runtime state under /config/.hermes.
  • Support .hermes import and export.
  • Keep compatibility fields such as openclaw_status, openclaw_pid, and openclaw_version until generic runtime fields are introduced.
  • Add Hermes-specific runtime control commands, or generic start_runtime, stop_runtime, and restart_runtime, if runtime process control becomes required.