- Guides & Tutorials
- Migrate from OpenClaw
Migrate from OpenClaw
hermes claw migrateimports your OpenClaw (or legacy Clawdbot/Moldbot) setup into Hermes. This guide covers exactly what gets migrated, the config key mappings, and what to verify after migration.
hermes claw migrate
If your OpenClaw setup was multi-provider,hermes setup –portalcollapses it to one OAuth — 300+ models plus the Tool Gateway in a single login. SeeNous Portal.
hermes setup --portal
Quick start
# Preview then migrate (always shows a preview first, then asks to confirm)hermes claw migrate# Preview only, no changeshermes claw migrate --dry-run# Full migration including API keys, skip confirmationhermes claw migrate --preset full --migrate-secrets --yes
The migration always shows a full preview of what will be imported before making any changes. Review the list, then confirm to proceed.
Reads from~/.openclaw/by default. Legacy~/.clawdbot/or~/.moltbot/directories are detected automatically. Same for legacy config filenames (clawdbot.json,moltbot.json).
~/.openclaw/
~/.clawdbot/
~/.moltbot/
clawdbot.json
moltbot.json
Options
| Option | Description |
|---|---|
| –dry-run | Preview only — stop after showing what would be migrated. |
| –preset |
full(all compatible settings) oruser-data(excludes infrastructure config). Neither preset imports secrets by default — pass–migrate-secretsexplicitly. |
| –overwrite | Overwrite existing Hermes files on conflicts (default: refuse to apply when the plan has conflicts). |
| –migrate-secrets | Include API keys. Required even under–preset full— no preset imports secrets silently. |
| –no-backup | Skip the pre-migration zip snapshot of~/.hermes/(by default a single restore-point archive is written before apply, under~/.hermes/backups/pre-migration-*.zip; restorable withhermes import). |
| –source |
Custom OpenClaw directory. |
| –workspace-target |
Where to placeAGENTS.md. |
| –skill-conflict |
skip(default),overwrite, orrename. |
| –yes | Skip the confirmation prompt after preview. |
--dry-run
--preset <name>
full
user-data
--migrate-secrets
--overwrite
--migrate-secrets
--preset full
--no-backup
~/.hermes/
~/.hermes/backups/pre-migration-*.zip
hermes import
--source <path>
--workspace-target <path>
AGENTS.md
--skill-conflict <mode>
skip
overwrite
rename
--yes
What gets migrated
Persona, memory, and instructions
| What | OpenClaw source | Hermes destination | Notes |
|---|---|---|---|
| Persona | workspace/SOUL.md | ~/.hermes/SOUL.md | Direct copy |
| Workspace instructions | workspace/AGENTS.md | AGENTS.mdin–workspace-target | Requires–workspace-targetflag |
| Long-term memory | workspace/MEMORY.md | ~/.hermes/memories/MEMORY.md | Parsed into entries, merged with existing, deduped. Uses§delimiter. |
| User profile | workspace/USER.md | ~/.hermes/memories/USER.md | Same entry-merge logic as memory. |
| Daily memory files | workspace/memory/*.md | ~/.hermes/memories/MEMORY.md | All daily files merged into main memory. |
workspace/SOUL.md
~/.hermes/SOUL.md
workspace/AGENTS.md
AGENTS.md
--workspace-target
--workspace-target
workspace/MEMORY.md
~/.hermes/memories/MEMORY.md
§
workspace/USER.md
~/.hermes/memories/USER.md
workspace/memory/*.md
~/.hermes/memories/MEMORY.md
Workspace files are also checked atworkspace.default/andworkspace-main/as fallback paths (OpenClaw renamedworkspace/toworkspace-main/in recent versions, and usesworkspace-{agentId}for multi-agent setups).
workspace.default/
workspace-main/
workspace/
workspace-main/
workspace-{agentId}
Skills (4 sources)
| Source | OpenClaw location | Hermes destination |
|---|---|---|
| Workspace skills | workspace/skills/ | ~/.hermes/skills/openclaw-imports/ |
| Managed/shared skills | ~/.openclaw/skills/ | ~/.hermes/skills/openclaw-imports/ |
| Personal cross-project | ~/.agents/skills/ | ~/.hermes/skills/openclaw-imports/ |
| Project-level shared | workspace/.agents/skills/ | ~/.hermes/skills/openclaw-imports/ |
workspace/skills/
~/.hermes/skills/openclaw-imports/
~/.openclaw/skills/
~/.hermes/skills/openclaw-imports/
~/.agents/skills/
~/.hermes/skills/openclaw-imports/
workspace/.agents/skills/
~/.hermes/skills/openclaw-imports/
Skill conflicts are handled by–skill-conflict:skipleaves the existing Hermes skill,overwritereplaces it,renamecreates a-importedcopy.
--skill-conflict
skip
overwrite
rename
-imported
Model and provider configuration
| What | OpenClaw config path | Hermes destination | Notes |
|---|---|---|---|
| Default model | agents.defaults.model | config.yaml→model | Can be a string or{primary, fallbacks}object |
| Custom providers | models.providers.* | config.yaml→custom_providers | MapsbaseUrl,apiType/api— handles both short (“openai”, “anthropic”) and hyphenated (“openai-completions”, “anthropic-messages”, “google-generative-ai”) values |
| Provider API keys | models.providers.*.apiKey | ~/.hermes/.env | Requires–migrate-secrets. SeeAPI key resolutionbelow. |
agents.defaults.model
config.yaml
model
{primary, fallbacks}
models.providers.*
config.yaml
custom_providers
baseUrl
apiType
api
models.providers.*.apiKey
~/.hermes/.env
--migrate-secrets
Agent behavior
| What | OpenClaw config path | Hermes config path | Mapping |
|---|---|---|---|
| Max turns | agents.defaults.timeoutSeconds | agent.max_turns | timeoutSeconds / 10, capped at 200 |
| Verbose mode | agents.defaults.verboseDefault | agent.verbose | “off” / “on” / “full” |
| Reasoning effort | agents.defaults.thinkingDefault | agent.reasoning_effort | “always”/”high”/”xhigh” → “high”, “auto”/”medium”/”adaptive” → “medium”, “off”/”low”/”none”/”minimal” → “low” |
| Compression | agents.defaults.compaction.mode | compression.enabled | “off” → false, anything else → true |
| Compression model | agents.defaults.compaction.model | compression.summary_model | Direct string copy |
| Human delay | agents.defaults.humanDelay.mode | human_delay.mode | “natural” / “custom” / “off” |
| Human delay timing | agents.defaults.humanDelay.minMs/.maxMs | human_delay.min_ms/.max_ms | Direct copy |
| Timezone | agents.defaults.userTimezone | timezone | Direct string copy |
| Exec timeout | tools.exec.timeoutSec | terminal.timeout | Direct copy (field istimeoutSec, nottimeout) |
| Docker sandbox | agents.defaults.sandbox.backend | terminal.backend | “docker” → “docker” |
| Docker image | agents.defaults.sandbox.docker.image | terminal.docker_image | Direct copy |
agents.defaults.timeoutSeconds
agent.max_turns
timeoutSeconds / 10
agents.defaults.verboseDefault
agent.verbose
agents.defaults.thinkingDefault
agent.reasoning_effort
agents.defaults.compaction.mode
compression.enabled
agents.defaults.compaction.model
compression.summary_model
agents.defaults.humanDelay.mode
human_delay.mode
agents.defaults.humanDelay.minMs
.maxMs
human_delay.min_ms
.max_ms
agents.defaults.userTimezone
timezone
tools.exec.timeoutSec
terminal.timeout
timeoutSec
timeout
agents.defaults.sandbox.backend
terminal.backend
agents.defaults.sandbox.docker.image
terminal.docker_image
Session reset policies
| OpenClaw config path | Hermes config path | Notes |
|---|---|---|
| session.reset.mode | session_reset.mode | “daily”, “idle”, or both |
| session.reset.atHour | session_reset.at_hour | Hour (0–23) for daily reset |
| session.reset.idleMinutes | session_reset.idle_minutes | Minutes of inactivity |
session.reset.mode
session_reset.mode
session.reset.atHour
session_reset.at_hour
session.reset.idleMinutes
session_reset.idle_minutes
Note: OpenClaw also hassession.resetTriggers(a simple string array like[“daily”, “idle”]). If the structuredsession.resetisn’t present, the migration falls back to inferring fromresetTriggers.
session.resetTriggers
["daily", "idle"]
session.reset
resetTriggers
MCP servers
| OpenClaw field | Hermes field | Notes |
|---|---|---|
| mcp.servers.*.command | mcp_servers.*.command | Stdio transport |
| mcp.servers.*.args | mcp_servers.*.args | |
| mcp.servers.*.env | mcp_servers.*.env | |
| mcp.servers.*.cwd | mcp_servers.*.cwd | |
| mcp.servers.*.url | mcp_servers.*.url | HTTP/SSE transport |
| mcp.servers.*.tools.include | mcp_servers.*.tools.include | Tool filtering |
| mcp.servers.*.tools.exclude | mcp_servers.*.tools.exclude |
mcp.servers.*.command
mcp_servers.*.command
mcp.servers.*.args
mcp_servers.*.args
mcp.servers.*.env
mcp_servers.*.env
mcp.servers.*.cwd
mcp_servers.*.cwd
mcp.servers.*.url
mcp_servers.*.url
mcp.servers.*.tools.include
mcp_servers.*.tools.include
mcp.servers.*.tools.exclude
mcp_servers.*.tools.exclude
TTS (text-to-speech)
TTS settings are read fromtwoOpenClaw config locations with this priority:
- messages.tts.providers.{provider}.*(canonical location)
- Top-leveltalk.providers.{provider}.*(fallback)
- Legacy flat keysmessages.tts.{provider}.*(oldest format)
messages.tts.providers.{provider}.*
talk.providers.{provider}.*
messages.tts.{provider}.*
| What | Hermes destination |
| — | — |
| Provider name | config.yaml→tts.provider |
| ElevenLabs voice ID | config.yaml→tts.elevenlabs.voice_id |
| ElevenLabs model ID | config.yaml→tts.elevenlabs.model_id |
| OpenAI model | config.yaml→tts.openai.model |
| OpenAI voice | config.yaml→tts.openai.voice |
| Edge TTS voice | config.yaml→tts.edge.voice(OpenClaw renamed “edge” to “microsoft” — both are recognized) |
| TTS assets | ~/.hermes/tts/(file copy) |
config.yaml
tts.provider
config.yaml
tts.elevenlabs.voice_id
config.yaml
tts.elevenlabs.model_id
config.yaml
tts.openai.model
config.yaml
tts.openai.voice
config.yaml
tts.edge.voice
~/.hermes/tts/
Messaging platforms
| Platform | OpenClaw config path | Hermes.envvariable | Notes |
|---|---|---|---|
| Telegram | channels.telegram.botTokenor.accounts.default.botToken | TELEGRAM_BOT_TOKEN | Token can be string orSecretRef. Both flat and accounts layout supported. |
| Telegram | credentials/telegram-default-allowFrom.json | TELEGRAM_ALLOWED_USERS | Comma-joined fromallowFrom[]array |
| Discord | channels.discord.tokenor.accounts.default.token | DISCORD_BOT_TOKEN | |
| Discord | channels.discord.allowFromor.accounts.default.allowFrom | DISCORD_ALLOWED_USERS | |
| Slack | channels.slack.botTokenor.accounts.default.botToken | SLACK_BOT_TOKEN | |
| Slack | channels.slack.appTokenor.accounts.default.appToken | SLACK_APP_TOKEN | |
| Slack | channels.slack.allowFromor.accounts.default.allowFrom | SLACK_ALLOWED_USERS | |
| channels.whatsapp.allowFromor.accounts.default.allowFrom | WHATSAPP_ALLOWED_USERS | Auth via Baileys QR pairing — requires re-pairing after migration | |
| Signal | channels.signal.accountor.accounts.default.account | SIGNAL_ACCOUNT | |
| Signal | channels.signal.httpUrlor.accounts.default.httpUrl | SIGNAL_HTTP_URL | |
| Signal | channels.signal.allowFromor.accounts.default.allowFrom | SIGNAL_ALLOWED_USERS | |
| Matrix | channels.matrix.accessTokenor.accounts.default.accessToken | MATRIX_ACCESS_TOKEN | UsesaccessToken(notbotToken) |
| Mattermost | channels.mattermost.botTokenor.accounts.default.botToken | MATTERMOST_BOT_TOKEN |
.env
channels.telegram.botToken
.accounts.default.botToken
TELEGRAM_BOT_TOKEN
credentials/telegram-default-allowFrom.json
TELEGRAM_ALLOWED_USERS
allowFrom[]
channels.discord.token
.accounts.default.token
DISCORD_BOT_TOKEN
channels.discord.allowFrom
.accounts.default.allowFrom
DISCORD_ALLOWED_USERS
channels.slack.botToken
.accounts.default.botToken
SLACK_BOT_TOKEN
channels.slack.appToken
.accounts.default.appToken
SLACK_APP_TOKEN
channels.slack.allowFrom
.accounts.default.allowFrom
SLACK_ALLOWED_USERS
channels.whatsapp.allowFrom
.accounts.default.allowFrom
WHATSAPP_ALLOWED_USERS
channels.signal.account
.accounts.default.account
SIGNAL_ACCOUNT
channels.signal.httpUrl
.accounts.default.httpUrl
SIGNAL_HTTP_URL
channels.signal.allowFrom
.accounts.default.allowFrom
SIGNAL_ALLOWED_USERS
channels.matrix.accessToken
.accounts.default.accessToken
MATRIX_ACCESS_TOKEN
accessToken
botToken
channels.mattermost.botToken
.accounts.default.botToken
MATTERMOST_BOT_TOKEN
Other config
| What | OpenClaw path | Hermes path | Notes |
|---|---|---|---|
| Approval mode | approvals.exec.mode | config.yaml→approvals.mode | “auto”→”off”, “always”→”manual”, “smart”→”smart” |
| Command allowlist | exec-approvals.json | config.yaml→command_allowlist | Patterns merged and deduped |
| Browser CDP URL | browser.cdpUrl | config.yaml→browser.cdp_url | |
| Browser headless | browser.headless | config.yaml→browser.headless | |
| Brave search key | tools.web.search.brave.apiKey | .env→BRAVE_API_KEY | Requires–migrate-secrets |
| Gateway auth token | gateway.auth.token | .env→HERMES_GATEWAY_TOKEN | Requires–migrate-secrets |
| Working directory | agents.defaults.workspace | config.yaml→terminal.cwd | Legacy migrations may still emitMESSAGING_CWDas a compatibility fallback |
approvals.exec.mode
config.yaml
approvals.mode
exec-approvals.json
config.yaml
command_allowlist
browser.cdpUrl
config.yaml
browser.cdp_url
browser.headless
config.yaml
browser.headless
tools.web.search.brave.apiKey
.env
BRAVE_API_KEY
--migrate-secrets
gateway.auth.token
.env
HERMES_GATEWAY_TOKEN
--migrate-secrets
agents.defaults.workspace
config.yaml
terminal.cwd
MESSAGING_CWD
Archived (no direct Hermes equivalent)
These are saved to~/.hermes/migration/openclaw/
~/.hermes/migration/openclaw/<timestamp>/archive/
| What | Archive file | How to recreate in Hermes |
| — | — | — |
| IDENTITY.md | archive/workspace/IDENTITY.md | Merge intoSOUL.md |
| TOOLS.md | archive/workspace/TOOLS.md | Hermes has built-in tool instructions |
| HEARTBEAT.md | archive/workspace/HEARTBEAT.md | Use cron jobs for periodic tasks |
| BOOTSTRAP.md | archive/workspace/BOOTSTRAP.md | Use context files or skills |
| Cron jobs | archive/cron-config.json | Recreate withhermes cron create |
| Plugins | archive/plugins-config.json | Seeplugins guide |
| Hooks/webhooks | archive/hooks-config.json | Usehermes webhookor gateway hooks |
| Memory backend | archive/memory-backend-config.json | Configure viahermes honcho |
| Skills registry | archive/skills-registry-config.json | Usehermes skills config |
| UI/identity | archive/ui-identity-config.json | Use/skincommand |
| Logging | archive/logging-diagnostics-config.json | Set inconfig.yamllogging section |
| Multi-agent list | archive/agents-list.json | Use Hermes profiles |
| Channel bindings | archive/bindings.json | Manual setup per platform |
| Complex channels | archive/channels-deep-config.json | Manual platform config |
IDENTITY.md
archive/workspace/IDENTITY.md
SOUL.md
TOOLS.md
archive/workspace/TOOLS.md
HEARTBEAT.md
archive/workspace/HEARTBEAT.md
BOOTSTRAP.md
archive/workspace/BOOTSTRAP.md
archive/cron-config.json
hermes cron create
archive/plugins-config.json
archive/hooks-config.json
hermes webhook
archive/memory-backend-config.json
hermes honcho
archive/skills-registry-config.json
hermes skills config
archive/ui-identity-config.json
/skin
archive/logging-diagnostics-config.json
config.yaml
archive/agents-list.json
archive/bindings.json
archive/channels-deep-config.json
API key resolution
When–migrate-secretsis enabled, API keys are collected fromfour sourcesin priority order:
--migrate-secrets
- Config values—models.providers.*.apiKeyand TTS provider keys inopenclaw.json
- Environment file—~/.openclaw/.env(keys likeOPENROUTER_API_KEY,ANTHROPIC_API_KEY, etc.)
- Config env sub-object—openclaw.json→”env”or”env”.”vars”(some setups store keys here instead of a separate.envfile)
- Auth profiles—~/.openclaw/agents/main/agent/auth-profiles.json(per-agent credentials)
models.providers.*.apiKey
openclaw.json
~/.openclaw/.env
OPENROUTER_API_KEY
ANTHROPIC_API_KEY
openclaw.json
"env"
"env"."vars"
.env
~/.openclaw/agents/main/agent/auth-profiles.json
Config values take priority. Each subsequent source fills any remaining gaps.
Supported key targets
OPENROUTER_API_KEY,OPENAI_API_KEY,ANTHROPIC_API_KEY,DEEPSEEK_API_KEY,GEMINI_API_KEY,ZAI_API_KEY,MINIMAX_API_KEY,ELEVENLABS_API_KEY,TELEGRAM_BOT_TOKEN,VOICE_TOOLS_OPENAI_KEY
OPENROUTER_API_KEY
OPENAI_API_KEY
ANTHROPIC_API_KEY
DEEPSEEK_API_KEY
GEMINI_API_KEY
ZAI_API_KEY
MINIMAX_API_KEY
ELEVENLABS_API_KEY
TELEGRAM_BOT_TOKEN
VOICE_TOOLS_OPENAI_KEY
Keys not in this allowlist are never copied.
SecretRef handling
OpenClaw config values for tokens and API keys can be in three formats:
// Plain string"channels": { "telegram": { "botToken": "123456:ABC-DEF..." } }// Environment template"channels": { "telegram": { "botToken": "${TELEGRAM_BOT_TOKEN}" } }// SecretRef object"channels": { "telegram": { "botToken": { "source": "env", "id": "TELEGRAM_BOT_TOKEN" } } }
The migration resolves all three formats. For env templates and SecretRef objects withsource: “env”, it looks up the value in~/.openclaw/.envand theopenclaw.jsonenv sub-object. SecretRef objects withsource: “file”orsource: “exec”can’t be resolved automatically — the migration warns about these, and those values must be added to Hermes manually viahermes config set.
source: "env"
~/.openclaw/.env
openclaw.json
source: "file"
source: "exec"
hermes config set
After migration
- Check the migration report— printed on completion with counts of migrated, skipped, and conflicting items.
- Review archived files— anything in~/.hermes/migration/openclaw/
/archive/needs manual attention. - Start a new session— imported skills and memory entries take effect in new sessions, not the current one.
- Verify API keys— runhermes statusto check provider authentication.
- Test messaging— if you migrated platform tokens, restart the gateway:systemctl –user restart hermes-gateway
- Check session policies— runhermes config showand verify thesession_resetvalue matches your expectations.
- Re-pair WhatsApp— WhatsApp uses QR code pairing (Baileys), not token migration. Runhermes whatsappto pair.
- Archive cleanup— after confirming everything works, runhermes claw cleanupto rename leftover OpenClaw directories to.pre-migration/(prevents state confusion).
Check the migration report— printed on completion with counts of migrated, skipped, and conflicting items.
Review archived files— anything in~/.hermes/migration/openclaw/
~/.hermes/migration/openclaw/<timestamp>/archive/
Start a new session— imported skills and memory entries take effect in new sessions, not the current one.
Verify API keys— runhermes statusto check provider authentication.
hermes status
Test messaging— if you migrated platform tokens, restart the gateway:systemctl –user restart hermes-gateway
systemctl --user restart hermes-gateway
Check session policies— runhermes config showand verify thesession_resetvalue matches your expectations.
hermes config show
session_reset
Re-pair WhatsApp— WhatsApp uses QR code pairing (Baileys), not token migration. Runhermes whatsappto pair.
hermes whatsapp
Archive cleanup— after confirming everything works, runhermes claw cleanupto rename leftover OpenClaw directories to.pre-migration/(prevents state confusion).
hermes claw cleanup
.pre-migration/
Troubleshooting
“OpenClaw directory not found”
The migration checks~/.openclaw/, then~/.clawdbot/, then~/.moltbot/. If your installation is elsewhere, use–source /path/to/your/openclaw.
~/.openclaw/
~/.clawdbot/
~/.moltbot/
--source /path/to/your/openclaw
“No provider API keys found”
Keys might be stored in several places depending on your OpenClaw version: inline inopenclaw.jsonundermodels.providers.*.apiKey, in~/.openclaw/.env, in theopenclaw.json”env”sub-object, or inagents/main/agent/auth-profiles.json. The migration checks all four. If keys usesource: “file”orsource: “exec”SecretRefs, they can’t be resolved automatically — add them viahermes config set.
openclaw.json
models.providers.*.apiKey
~/.openclaw/.env
openclaw.json
"env"
agents/main/agent/auth-profiles.json
source: "file"
source: "exec"
hermes config set
Skills not appearing after migration
Imported skills land in~/.hermes/skills/openclaw-imports/. Start a new session for them to take effect, or run/skillsto verify they’re loaded.
~/.hermes/skills/openclaw-imports/
/skills
TTS voice not migrated
OpenClaw stores TTS settings in two places:messages.tts.providers.*and the top-leveltalkconfig. The migration checks both. If your voice ID was set via the OpenClaw UI (stored in a different path), you may need to set it manually:hermes config set tts.elevenlabs.voice_id YOUR_VOICE_ID.
messages.tts.providers.*
talk
hermes config set tts.elevenlabs.voice_id YOUR_VOICE_ID