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
SUBFOLDERto/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_skillcommand. 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:
- Use the top-level key as the runtime channel ID, for example
feishu,telegram,slack, ordingtalk-connector. Resource-specific Feishu/Lark keys such asfeishu-opsmust be folded into thefeishu.accountsmap before injection. - Skip channels with
enabled=false, but keep their config on disk so future updates can re-enable them. - 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. - Preserve unknown fields so future ClawManager extensions are not lost.
- If Hermes does not support a channel type yet, mark that channel as unsupported in
health.channelsand 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:
- Iterate over
itemsand usekeyas the stable skill identifier. - Read
content.configand translate it into executable Hermes skill configuration. - If Hermes stores skills as directories, write the generated config to
/config/.hermes/skills/{key}/skill.json. Keep the rawcontentas well for debugging. - Calculate
content_md5for the written skill directory and include it in the nextskills/inventoryreport. - For skills generated from bootstrap config, inventory
sourceshould beinjected_by_clawmanagerorbootstrap_config. Ifsourceisinjected_by_clawmanagerandskill_iduses a platform external ID, use the formatskill-{id}, for exampleskill-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_skillcommand: 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:
- Download the version package:
GET {CLAWMANAGER_AGENT_BASE_URL}/api/v1/agent/skills/versions/{skill_version}/download
Authorization: Bearer {session_token}
- Validate the zip. Reject absolute paths,
../, multiple top-level directories, and any path that would extract outside/config/.hermes/skills. - Extract to
/config/.hermes/skills/{target_name}. Prefer extracting into a temp directory and then atomically replacing the target directory. - Recalculate directory
content_md5and compare it with the command payload. Finish the command asfailedif it does not match. - Send one
skills/inventoryreport. For the installed skill, setsourcetoinjected_by_clawmanagerandskill_idto the command payloadskill_id. - Finish the command with
install_path,skill_id,skill_version, andcontent_md5inresult.
Agent Lifecycle
Hermes agent startup flow:
- Read
CLAWMANAGER_AGENT_*environment variables. - Read and apply runtime bootstrap payloads if present.
- If no local session token is available, register with the bootstrap token.
- Store the returned session token in
/config/.hermes/hermes-agent/session.json. - Send heartbeats using the interval returned by the server.
- Poll commands using the command poll interval returned by the server. If heartbeat returns
has_pending_command=true, poll once immediately. - Periodically send full state reports and skill inventory reports.
- 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_statusis 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_secondsfrom 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/cpuinfoor the language runtime. - Memory: prefer cgroup memory limit and current usage. For cgroup v2, read
/sys/fs/cgroup/memory.maxand/sys/fs/cgroup/memory.current. Computemem_available_bytes = memory.max - memory.current, floored at 0. If no cgroup limit exists, use/proc/meminfoMemTotalandMemAvailable. - Disk: call
statvfson/config/.hermes. Keep the field namesroot_total_bytesandroot_free_bytes, but interpret them as the filesystem containing the Hermes persistent directory. - Network: read
/proc/net/dev. Excludeloby default and keep business interfaces such aseth0.
Reporting Frequency
- Send one state report with complete
system_infoimmediately 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_infoorhealth_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
- Hermes agent sends two consecutive state reports roughly 5 seconds apart.
GET /api/v1/instances/{instance_id}/runtimereturnsdata.runtime.system_info.cpu,memory,disk, andnetwork.- The ClawManager instance detail page starts showing CPU, Memory, Disk, and Network metrics within 10 seconds.
- 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
fullinventory after startup. - Use file watching or periodic scanning for later
incrementalupdates. - When the platform sends
sync_skill_inventoryorrefresh_skill_inventory, run afullscan.
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/, ordist/.
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:
- Call the start endpoint.
- Execute the command.
- Call the finish endpoint with the result.
- 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_infohealth_checksync_skill_inventoryrefresh_skill_inventorycollect_skill_packageinstall_skillupdate_skilluninstall_skillremove_skilldisable_skillquarantine_skillhandle_skill_riskstart_openclawstop_openclawrestart_openclawapply_config_revisionreload_config
Minimum Hermes implementation:
collect_system_infohealth_checksync_skill_inventoryrefresh_skill_inventorycollect_skill_packageinstall_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:
- Validate the zip path boundaries.
- Extract it under
/config/.hermes/skills. - Recalculate
content_md5. - Send
skills/inventory. - 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.
/configis mounted and both/config/Desktopand/config/.hermespersist 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_packagecauses the agent to upload a valid zip package. content_md5in inventory and package upload match the ClawManager specification.- Command execution calls start and finish, including clear
error_messageon 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 forhermesduring instance creation and start. - Allow
hermesinstances 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
.hermesimport and export. - Keep compatibility fields such as
openclaw_status,openclaw_pid, andopenclaw_versionuntil generic runtime fields are introduced. - Add Hermes-specific runtime control commands, or generic
start_runtime,stop_runtime, andrestart_runtime, if runtime process control becomes required.