New standalone guide at guides/migrate-from-openclaw.md with: - Complete config key mapping tables for every category - Agent behavior mappings (thinkingDefault → reasoning_effort, etc.) - Session reset policy mapping (session.reset vs resetTriggers) - TTS dual-source explanation (messages.tts.providers + talk config) - MCP server field-by-field mapping - Messaging platform table with exact config paths and env vars - API key resolution: 3 sources, priority order, supported targets - SecretRef handling: plain strings, env templates, SecretRef objects - Post-migration checklist (6 steps) - Troubleshooting section - Complete archived items table with recreation guidance CLI commands reference condensed to summary + link to full guide. Added to sidebar under Guides & Tutorials.
243 lines
13 KiB
Markdown
243 lines
13 KiB
Markdown
---
|
||
sidebar_position: 7
|
||
title: "Migrate from OpenClaw"
|
||
description: "Complete guide to migrating your OpenClaw / Clawdbot setup to Hermes Agent — what gets migrated, how config maps, and what to check after."
|
||
---
|
||
|
||
# Migrate from OpenClaw
|
||
|
||
`hermes claw migrate` imports 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.
|
||
|
||
## Quick start
|
||
|
||
```bash
|
||
# Preview what would happen (no files changed)
|
||
hermes claw migrate --dry-run
|
||
|
||
# Run the migration (secrets excluded by default)
|
||
hermes claw migrate
|
||
|
||
# Full migration including API keys
|
||
hermes claw migrate --preset full
|
||
```
|
||
|
||
The migration reads from `~/.openclaw/` by default. If you still have a legacy `~/.clawdbot/` or `~/.moldbot/` directory, it's detected automatically. Same for legacy config filenames (`clawdbot.json`, `moldbot.json`).
|
||
|
||
## Options
|
||
|
||
| Option | Description |
|
||
|--------|-------------|
|
||
| `--dry-run` | Preview what would be migrated without writing anything. |
|
||
| `--preset <name>` | `full` (default, includes secrets) or `user-data` (excludes API keys). |
|
||
| `--overwrite` | Overwrite existing Hermes files on conflicts (default: skip). |
|
||
| `--migrate-secrets` | Include API keys (on by default with `--preset full`). |
|
||
| `--source <path>` | Custom OpenClaw directory. |
|
||
| `--workspace-target <path>` | Where to place `AGENTS.md`. |
|
||
| `--skill-conflict <mode>` | `skip` (default), `overwrite`, or `rename`. |
|
||
| `--yes` | Skip confirmation prompt. |
|
||
|
||
## 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.md` in `--workspace-target` | Requires `--workspace-target` flag |
|
||
| 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. |
|
||
|
||
All workspace files also check `workspace.default/` as a fallback path.
|
||
|
||
### 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/` |
|
||
|
||
Skill conflicts are handled by `--skill-conflict`: `skip` leaves the existing Hermes skill, `overwrite` replaces it, `rename` creates a `-imported` copy.
|
||
|
||
### 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` | Maps `baseUrl`, `apiType` ("openai"→"chat_completions", "anthropic"→"anthropic_messages") |
|
||
| Provider API keys | `models.providers.*.apiKey` | `~/.hermes/.env` | Requires `--migrate-secrets`. See [API key resolution](#api-key-resolution) below. |
|
||
|
||
### 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" → "high", "auto"/"medium" → "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 is `timeoutSec`, not `timeout`) |
|
||
| Docker sandbox | `agents.defaults.sandbox.backend` | `terminal.backend` | "docker" → "docker" |
|
||
| Docker image | `agents.defaults.sandbox.docker.image` | `terminal.docker_image` | Direct copy |
|
||
|
||
### 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 |
|
||
|
||
Note: OpenClaw also has `session.resetTriggers` (a simple string array like `["daily", "idle"]`). If the structured `session.reset` isn't present, the migration falls back to inferring from `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` | |
|
||
|
||
### TTS (text-to-speech)
|
||
|
||
TTS settings are read from **two** OpenClaw config locations with this priority:
|
||
|
||
1. `messages.tts.providers.{provider}.*` (canonical location)
|
||
2. Top-level `talk.providers.{provider}.*` (fallback)
|
||
3. Legacy flat keys `messages.tts.{provider}.*` (oldest format)
|
||
|
||
| 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` |
|
||
| TTS assets | `~/.hermes/tts/` (file copy) |
|
||
|
||
### Messaging platforms
|
||
|
||
| Platform | OpenClaw config path | Hermes `.env` variable | Notes |
|
||
|----------|---------------------|----------------------|-------|
|
||
| Telegram | `channels.telegram.botToken` | `TELEGRAM_BOT_TOKEN` | Token can be string or [SecretRef](#secretref-handling) |
|
||
| Telegram | `credentials/telegram-default-allowFrom.json` | `TELEGRAM_ALLOWED_USERS` | Comma-joined from `allowFrom[]` array |
|
||
| Discord | `channels.discord.token` | `DISCORD_BOT_TOKEN` | |
|
||
| Discord | `channels.discord.allowFrom` | `DISCORD_ALLOWED_USERS` | |
|
||
| Slack | `channels.slack.botToken` | `SLACK_BOT_TOKEN` | |
|
||
| Slack | `channels.slack.appToken` | `SLACK_APP_TOKEN` | |
|
||
| Slack | `channels.slack.allowFrom` | `SLACK_ALLOWED_USERS` | |
|
||
| WhatsApp | `channels.whatsapp.allowFrom` | `WHATSAPP_ALLOWED_USERS` | Auth via Baileys QR pairing (not a token) |
|
||
| Signal | `channels.signal.account` | `SIGNAL_ACCOUNT` | |
|
||
| Signal | `channels.signal.httpUrl` | `SIGNAL_HTTP_URL` | |
|
||
| Signal | `channels.signal.allowFrom` | `SIGNAL_ALLOWED_USERS` | |
|
||
| Matrix | `channels.matrix.botToken` | `MATRIX_ACCESS_TOKEN` | Via deep-channels migration |
|
||
| Mattermost | `channels.mattermost.botToken` | `MATTERMOST_BOT_TOKEN` | Via deep-channels migration |
|
||
|
||
### 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` | `.env` → `MESSAGING_CWD` | |
|
||
|
||
### Archived (no direct Hermes equivalent)
|
||
|
||
These are saved to `~/.hermes/migration/openclaw/<timestamp>/archive/` for manual review:
|
||
|
||
| What | Archive file | How to recreate in Hermes |
|
||
|------|-------------|--------------------------|
|
||
| `IDENTITY.md` | `archive/workspace/IDENTITY.md` | Merge into `SOUL.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 with `hermes cron create` |
|
||
| Plugins | `archive/plugins-config.json` | See [plugins guide](../user-guide/features/hooks.md) |
|
||
| Hooks/webhooks | `archive/hooks-config.json` | Use `hermes webhook` or gateway hooks |
|
||
| Memory backend | `archive/memory-backend-config.json` | Configure via `hermes honcho` |
|
||
| Skills registry | `archive/skills-registry-config.json` | Use `hermes skills config` |
|
||
| UI/identity | `archive/ui-identity-config.json` | Use `/skin` command |
|
||
| Logging | `archive/logging-diagnostics-config.json` | Set in `config.yaml` logging 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 |
|
||
|
||
## API key resolution
|
||
|
||
When `--migrate-secrets` is enabled, API keys are collected from **three sources** in priority order:
|
||
|
||
1. **Config values** — `models.providers.*.apiKey` and TTS provider keys in `openclaw.json`
|
||
2. **Environment file** — `~/.openclaw/.env` (keys like `OPENROUTER_API_KEY`, `ANTHROPIC_API_KEY`, etc.)
|
||
3. **Auth profiles** — `~/.openclaw/agents/main/agent/auth-profiles.json` (per-agent credentials)
|
||
|
||
Config values take priority. The `.env` fills any gaps. Auth profiles fill whatever remains.
|
||
|
||
### 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`
|
||
|
||
Keys not in this allowlist are never copied.
|
||
|
||
## SecretRef handling
|
||
|
||
OpenClaw config values for tokens and API keys can be in three formats:
|
||
|
||
```json
|
||
// 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 with `source: "env"`, it looks up the value in `~/.openclaw/.env`. SecretRef objects with `source: "file"` or `source: "exec"` can't be resolved automatically — those values must be added to Hermes manually after migration.
|
||
|
||
## After migration
|
||
|
||
1. **Check the migration report** — printed on completion with counts of migrated, skipped, and conflicting items.
|
||
|
||
2. **Review archived files** — anything in `~/.hermes/migration/openclaw/<timestamp>/archive/` needs manual attention.
|
||
|
||
3. **Verify API keys** — run `hermes status` to check provider authentication.
|
||
|
||
4. **Test messaging** — if you migrated platform tokens, restart the gateway: `systemctl --user restart hermes-gateway`
|
||
|
||
5. **Check session policies** — verify `hermes config get session_reset` matches your expectations.
|
||
|
||
6. **Re-pair WhatsApp** — WhatsApp uses QR code pairing (Baileys), not token migration. Run `hermes whatsapp` to pair.
|
||
|
||
## Troubleshooting
|
||
|
||
### "OpenClaw directory not found"
|
||
|
||
The migration checks `~/.openclaw/`, then `~/.clawdbot/`, then `~/.moldbot/`. If your installation is elsewhere, use `--source /path/to/your/openclaw`.
|
||
|
||
### "No provider API keys found"
|
||
|
||
Keys might be in your `.env` file instead of `openclaw.json`. The migration checks both — make sure `~/.openclaw/.env` exists and has the keys. If keys use `source: "file"` or `source: "exec"` SecretRefs, they can't be resolved automatically.
|
||
|
||
### Skills not appearing after migration
|
||
|
||
Imported skills land in `~/.hermes/skills/openclaw-imports/`. Start a new session for them to take effect, or run `/skills` to verify they're loaded.
|
||
|
||
### TTS voice not migrated
|
||
|
||
OpenClaw stores TTS settings in two places: `messages.tts.providers.*` and the top-level `talk` config. 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`.
|