Merge branch 'main' into rewbs/tool-use-charge-to-subscription
This commit is contained in:
242
website/docs/guides/migrate-from-openclaw.md
Normal file
242
website/docs/guides/migrate-from-openclaw.md
Normal file
@@ -0,0 +1,242 @@
|
||||
---
|
||||
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`.
|
||||
@@ -466,7 +466,7 @@ hermes insights [--days N] [--source platform]
|
||||
hermes claw migrate [options]
|
||||
```
|
||||
|
||||
Migrate your OpenClaw setup to Hermes. Reads from `~/.openclaw` (or a custom path) and writes to `~/.hermes`.
|
||||
Migrate your OpenClaw setup to Hermes. Reads from `~/.openclaw` (or a custom path) and writes to `~/.hermes`. Automatically detects legacy directory names (`~/.clawdbot`, `~/.moldbot`) and config filenames (`clawdbot.json`, `moldbot.json`).
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
@@ -481,57 +481,15 @@ Migrate your OpenClaw setup to Hermes. Reads from `~/.openclaw` (or a custom pat
|
||||
|
||||
### What gets migrated
|
||||
|
||||
The migration covers your entire OpenClaw footprint. Items are either **directly imported** into Hermes equivalents or **archived** for manual review when there's no direct mapping.
|
||||
The migration covers 30+ categories across persona, memory, skills, model providers, messaging platforms, agent behavior, session policies, MCP servers, TTS, and more. Items are either **directly imported** into Hermes equivalents or **archived** for manual review.
|
||||
|
||||
#### Directly imported
|
||||
**Directly imported:** SOUL.md, MEMORY.md, USER.md, AGENTS.md, skills (4 source directories), default model, custom providers, MCP servers, messaging platform tokens and allowlists (Telegram, Discord, Slack, WhatsApp, Signal, Matrix, Mattermost), agent defaults (reasoning effort, compression, human delay, timezone, sandbox), session reset policies, approval rules, TTS config, browser settings, tool settings, exec timeout, command allowlist, gateway config, and API keys from 3 sources.
|
||||
|
||||
| Category | OpenClaw source | Hermes destination |
|
||||
|----------|----------------|-------------------|
|
||||
| **Persona** | `SOUL.md` | `~/.hermes/SOUL.md` |
|
||||
| **Workspace instructions** | `AGENTS.md` | `AGENTS.md` in target workspace |
|
||||
| **Long-term memory** | `MEMORY.md` | `~/.hermes/MEMORY.md` (merged with existing entries) |
|
||||
| **User profile** | `USER.md` | `~/.hermes/USER.md` (merged with existing entries) |
|
||||
| **Daily memory files** | `workspace/memory/` | Merged into `~/.hermes/MEMORY.md` |
|
||||
| **Default model** | Config model setting | `config.yaml` model section |
|
||||
| **Custom providers** | Provider definitions (baseUrl, apiType, headers) | `config.yaml` custom\_providers |
|
||||
| **MCP servers** | MCP server definitions | `config.yaml` mcp\_servers |
|
||||
| **User skills** | Workspace skills | `~/.hermes/skills/openclaw-imports/` |
|
||||
| **Shared skills** | `~/.openclaw/skills/` | `~/.hermes/skills/openclaw-imports/` |
|
||||
| **Command allowlist** | Exec approval patterns | `config.yaml` command\_allowlist |
|
||||
| **Messaging settings** | Allowlists, working directory | `config.yaml` messaging section |
|
||||
| **Session policies** | Daily/idle reset policies | `config.yaml` session\_reset |
|
||||
| **Agent defaults** | Compaction, context, thinking settings | `config.yaml` agent section |
|
||||
| **Browser settings** | Browser automation config | `config.yaml` browser section |
|
||||
| **Tool settings** | Exec timeout, sandbox, web search | `config.yaml` tools section |
|
||||
| **Approval rules** | Approval mode and rules | `config.yaml` approvals section |
|
||||
| **TTS config** | TTS provider and voice | `config.yaml` tts section |
|
||||
| **TTS assets** | Workspace TTS files | `~/.hermes/tts/` |
|
||||
| **Gateway config** | Gateway port and auth | `config.yaml` gateway section |
|
||||
| **Telegram settings** | Bot token, allowlist | `~/.hermes/.env` |
|
||||
| **Discord settings** | Bot token, allowlist | `~/.hermes/.env` |
|
||||
| **Slack settings** | Bot/app tokens, allowlist | `~/.hermes/.env` |
|
||||
| **WhatsApp settings** | Allowlist | `~/.hermes/.env` |
|
||||
| **Signal settings** | Account, HTTP URL, allowlist | `~/.hermes/.env` |
|
||||
| **Channel config** | Matrix, Mattermost, IRC, group settings | `config.yaml` + archive |
|
||||
| **Provider API keys** | OPENROUTER\_API\_KEY, OPENAI\_API\_KEY, ANTHROPIC\_API\_KEY, etc. | `~/.hermes/.env` (requires `--migrate-secrets`) |
|
||||
**Archived for manual review:** Cron jobs, plugins, hooks/webhooks, memory backend (QMD), skills registry config, UI/identity, logging, multi-agent setup, channel bindings, IDENTITY.md, TOOLS.md, HEARTBEAT.md, BOOTSTRAP.md.
|
||||
|
||||
#### Archived for manual review
|
||||
**API key resolution** checks three sources in priority order: config values → `~/.openclaw/.env` → `auth-profiles.json`. All token fields handle plain strings, env templates (`${VAR}`), and SecretRef objects.
|
||||
|
||||
These OpenClaw features don't have direct Hermes equivalents. They're saved to an archive directory for you to review and recreate manually.
|
||||
|
||||
| Category | What's archived | How to recreate in Hermes |
|
||||
|----------|----------------|--------------------------|
|
||||
| **Cron / scheduled tasks** | Job definitions | Recreate with `hermes cron create` |
|
||||
| **Plugins** | Plugin configuration, installed extensions | Check the [plugins guide](../user-guide/features/hooks.md) |
|
||||
| **Hooks and webhooks** | Internal hooks, webhooks, Gmail integration | Use `hermes webhook` or gateway hooks |
|
||||
| **Memory backend** | QMD, vector search, citation settings | Configure Honcho via `hermes honcho` |
|
||||
| **Skills registry** | Per-skill enabled/config/env settings | Use `hermes skills config` |
|
||||
| **UI and identity** | Theme, assistant identity, display prefs | Use `/skin` command or `config.yaml` |
|
||||
| **Logging** | Diagnostics configuration | Set in `config.yaml` logging section |
|
||||
|
||||
### Security
|
||||
|
||||
API keys are **not migrated by default**. The `--preset full` preset enables secret migration, but only for an allowlist of known keys: `OPENROUTER_API_KEY`, `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `ELEVENLABS_API_KEY`, `TELEGRAM_BOT_TOKEN`, and `VOICE_TOOLS_OPENAI_KEY`. All other secrets are skipped.
|
||||
For the complete config key mapping, SecretRef handling details, and post-migration checklist, see the **[full migration guide](../guides/migrate-from-openclaw.md)**.
|
||||
|
||||
### Examples
|
||||
|
||||
@@ -547,9 +505,6 @@ hermes claw migrate --preset user-data --overwrite
|
||||
|
||||
# Migrate from a custom OpenClaw path
|
||||
hermes claw migrate --source /home/user/old-openclaw
|
||||
|
||||
# Migrate and place AGENTS.md in a specific project
|
||||
hermes claw migrate --workspace-target /home/user/my-project
|
||||
```
|
||||
|
||||
## Maintenance commands
|
||||
|
||||
@@ -699,66 +699,171 @@ Use this when you want lower latency or cost without fully changing your default
|
||||
|
||||
## Terminal Backend Configuration
|
||||
|
||||
Configure which environment the agent uses for terminal commands:
|
||||
Hermes supports six terminal backends. Each determines where the agent's shell commands actually execute — your local machine, a Docker container, a remote server via SSH, a Modal cloud sandbox, a Daytona workspace, or a Singularity/Apptainer container.
|
||||
|
||||
```yaml
|
||||
terminal:
|
||||
backend: local # or: docker, ssh, singularity, modal, daytona
|
||||
cwd: "." # Working directory ("." = current dir)
|
||||
timeout: 180 # Command timeout in seconds
|
||||
|
||||
# Docker-specific settings
|
||||
docker_image: "nikolaik/python-nodejs:python3.11-nodejs20"
|
||||
docker_mount_cwd_to_workspace: false # SECURITY: off by default. Opt in to mount the launch cwd into /workspace.
|
||||
docker_forward_env: # Optional explicit allowlist for env passthrough
|
||||
- "GITHUB_TOKEN"
|
||||
docker_volumes: # Additional explicit host mounts
|
||||
- "/home/user/projects:/workspace/projects"
|
||||
- "/home/user/data:/data:ro" # :ro for read-only
|
||||
|
||||
# Container resource limits (docker, singularity, modal, daytona)
|
||||
container_cpu: 1 # CPU cores
|
||||
container_memory: 5120 # MB (default 5GB)
|
||||
container_disk: 51200 # MB (default 50GB)
|
||||
container_persistent: true # Persist filesystem across sessions
|
||||
|
||||
# Persistent shell — keep a long-lived bash process across commands
|
||||
persistent_shell: true # Enabled by default for SSH backend
|
||||
backend: local # local | docker | ssh | modal | daytona | singularity
|
||||
cwd: "." # Working directory ("." = current dir for local, "/root" for containers)
|
||||
timeout: 180 # Per-command timeout in seconds
|
||||
```
|
||||
|
||||
For cloud sandboxes such as Modal and Daytona, `container_persistent: true` means Hermes will try to preserve filesystem state across sandbox recreation. It does not promise that the same live sandbox, PID space, or background processes will still be running later.
|
||||
|
||||
### Backend Overview
|
||||
|
||||
| Backend | Where commands run | Isolation | Best for |
|
||||
|---------|-------------------|-----------|----------|
|
||||
| **local** | Your machine directly | None | Development, personal use |
|
||||
| **docker** | Docker container | Full (namespaces, cap-drop) | Safe sandboxing, CI/CD |
|
||||
| **ssh** | Remote server via SSH | Network boundary | Remote dev, powerful hardware |
|
||||
| **modal** | Modal cloud sandbox | Full (cloud VM) | Ephemeral cloud compute, evals |
|
||||
| **daytona** | Daytona workspace | Full (cloud container) | Managed cloud dev environments |
|
||||
| **singularity** | Singularity/Apptainer container | Namespaces (--containall) | HPC clusters, shared machines |
|
||||
|
||||
### Local Backend
|
||||
|
||||
The default. Commands run directly on your machine with no isolation. No special setup required.
|
||||
|
||||
```yaml
|
||||
terminal:
|
||||
backend: local
|
||||
```
|
||||
|
||||
:::warning
|
||||
The agent has the same filesystem access as your user account. Use `hermes tools` to disable tools you don't want, or switch to Docker for sandboxing.
|
||||
:::
|
||||
|
||||
### Docker Backend
|
||||
|
||||
Runs commands inside a Docker container with security hardening (all capabilities dropped, no privilege escalation, PID limits).
|
||||
|
||||
```yaml
|
||||
terminal:
|
||||
backend: docker
|
||||
docker_image: "nikolaik/python-nodejs:python3.11-nodejs20"
|
||||
docker_mount_cwd_to_workspace: false # Mount launch dir into /workspace
|
||||
docker_forward_env: # Env vars to forward into container
|
||||
- "GITHUB_TOKEN"
|
||||
docker_volumes: # Host directory mounts
|
||||
- "/home/user/projects:/workspace/projects"
|
||||
- "/home/user/data:/data:ro" # :ro for read-only
|
||||
|
||||
# Resource limits
|
||||
container_cpu: 1 # CPU cores (0 = unlimited)
|
||||
container_memory: 5120 # MB (0 = unlimited)
|
||||
container_disk: 51200 # MB (requires overlay2 on XFS+pquota)
|
||||
container_persistent: true # Persist /workspace and /root across sessions
|
||||
```
|
||||
|
||||
**Requirements:** Docker Desktop or Docker Engine installed and running. Hermes probes `$PATH` plus common macOS install locations (`/usr/local/bin/docker`, `/opt/homebrew/bin/docker`, Docker Desktop app bundle).
|
||||
|
||||
**Container lifecycle:** Each session starts a long-lived container (`docker run -d ... sleep 2h`). Commands run via `docker exec` with a login shell. On cleanup, the container is stopped and removed.
|
||||
|
||||
**Security hardening:**
|
||||
- `--cap-drop ALL` with only `DAC_OVERRIDE`, `CHOWN`, `FOWNER` added back
|
||||
- `--security-opt no-new-privileges`
|
||||
- `--pids-limit 256`
|
||||
- Size-limited tmpfs for `/tmp` (512MB), `/var/tmp` (256MB), `/run` (64MB)
|
||||
|
||||
**Credential forwarding:** Env vars listed in `docker_forward_env` are resolved from your shell environment first, then `~/.hermes/.env`. Skills can also declare `required_environment_variables` which are merged automatically.
|
||||
|
||||
### SSH Backend
|
||||
|
||||
Runs commands on a remote server over SSH. Uses ControlMaster for connection reuse (5-minute idle keepalive). Persistent shell is enabled by default — state (cwd, env vars) survives across commands.
|
||||
|
||||
```yaml
|
||||
terminal:
|
||||
backend: ssh
|
||||
persistent_shell: true # Keep a long-lived bash session (default: true)
|
||||
```
|
||||
|
||||
**Required environment variables:**
|
||||
|
||||
```bash
|
||||
TERMINAL_SSH_HOST=my-server.example.com
|
||||
TERMINAL_SSH_USER=ubuntu
|
||||
```
|
||||
|
||||
**Optional:**
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `TERMINAL_SSH_PORT` | `22` | SSH port |
|
||||
| `TERMINAL_SSH_KEY` | (system default) | Path to SSH private key |
|
||||
| `TERMINAL_SSH_PERSISTENT` | `true` | Enable persistent shell |
|
||||
|
||||
**How it works:** Connects at init time with `BatchMode=yes` and `StrictHostKeyChecking=accept-new`. Persistent shell keeps a single `bash -l` process alive on the remote host, communicating via temporary files. Commands that need `stdin_data` or `sudo` automatically fall back to one-shot mode.
|
||||
|
||||
### Modal Backend
|
||||
|
||||
Runs commands in a [Modal](https://modal.com) cloud sandbox. Each task gets an isolated VM with configurable CPU, memory, and disk. Filesystem can be snapshot/restored across sessions.
|
||||
|
||||
```yaml
|
||||
terminal:
|
||||
backend: modal
|
||||
container_cpu: 1 # CPU cores
|
||||
container_memory: 5120 # MB (5GB)
|
||||
container_disk: 51200 # MB (50GB)
|
||||
container_persistent: true # Snapshot/restore filesystem
|
||||
```
|
||||
|
||||
**Required:** Either `MODAL_TOKEN_ID` + `MODAL_TOKEN_SECRET` environment variables, or a `~/.modal.toml` config file.
|
||||
|
||||
**Persistence:** When enabled, the sandbox filesystem is snapshotted on cleanup and restored on next session. Snapshots are tracked in `~/.hermes/modal_snapshots.json`. This preserves filesystem state, not live processes, PID space, or background jobs.
|
||||
|
||||
**Credential files:** Automatically mounted from `~/.hermes/` (OAuth tokens, etc.) and synced before each command.
|
||||
|
||||
### Daytona Backend
|
||||
|
||||
Runs commands in a [Daytona](https://daytona.io) managed workspace. Supports stop/resume for persistence.
|
||||
|
||||
```yaml
|
||||
terminal:
|
||||
backend: daytona
|
||||
container_cpu: 1 # CPU cores
|
||||
container_memory: 5120 # MB → converted to GiB
|
||||
container_disk: 10240 # MB → converted to GiB (max 10 GiB)
|
||||
container_persistent: true # Stop/resume instead of delete
|
||||
```
|
||||
|
||||
**Required:** `DAYTONA_API_KEY` environment variable.
|
||||
|
||||
**Persistence:** When enabled, sandboxes are stopped (not deleted) on cleanup and resumed on next session. Sandbox names follow the pattern `hermes-{task_id}`.
|
||||
|
||||
**Disk limit:** Daytona enforces a 10 GiB maximum. Requests above this are capped with a warning.
|
||||
|
||||
### Singularity/Apptainer Backend
|
||||
|
||||
Runs commands in a [Singularity/Apptainer](https://apptainer.org) container. Designed for HPC clusters and shared machines where Docker isn't available.
|
||||
|
||||
```yaml
|
||||
terminal:
|
||||
backend: singularity
|
||||
singularity_image: "docker://nikolaik/python-nodejs:python3.11-nodejs20"
|
||||
container_cpu: 1 # CPU cores
|
||||
container_memory: 5120 # MB
|
||||
container_persistent: true # Writable overlay persists across sessions
|
||||
```
|
||||
|
||||
**Requirements:** `apptainer` or `singularity` binary in `$PATH`.
|
||||
|
||||
**Image handling:** Docker URLs (`docker://...`) are automatically converted to SIF files and cached. Existing `.sif` files are used directly.
|
||||
|
||||
**Scratch directory:** Resolved in order: `TERMINAL_SCRATCH_DIR` → `TERMINAL_SANDBOX_DIR/singularity` → `/scratch/$USER/hermes-agent` (HPC convention) → `~/.hermes/sandboxes/singularity`.
|
||||
|
||||
**Isolation:** Uses `--containall --no-home` for full namespace isolation without mounting the host home directory.
|
||||
|
||||
### Common Terminal Backend Issues
|
||||
|
||||
If terminal commands fail immediately or the terminal tool is reported as disabled, check the following:
|
||||
If terminal commands fail immediately or the terminal tool is reported as disabled:
|
||||
|
||||
- **Local backend**
|
||||
- No special requirements. This is the safest default when you are just getting started.
|
||||
|
||||
- **Docker backend**
|
||||
- Ensure Docker Desktop (or the Docker daemon) is installed and running.
|
||||
- Hermes needs to be able to find the `docker` CLI. It checks your `$PATH` first and also probes common Docker Desktop install locations on macOS. Run:
|
||||
```bash
|
||||
docker version
|
||||
```
|
||||
If this fails, fix your Docker installation or switch back to the local backend:
|
||||
```bash
|
||||
hermes config set terminal.backend local
|
||||
```
|
||||
|
||||
- **SSH backend**
|
||||
- Both `TERMINAL_SSH_HOST` and `TERMINAL_SSH_USER` must be set, for example:
|
||||
```bash
|
||||
export TERMINAL_ENV=ssh
|
||||
export TERMINAL_SSH_HOST=my-server.example.com
|
||||
export TERMINAL_SSH_USER=ubuntu
|
||||
```
|
||||
- If either value is missing, Hermes will log a clear error and refuse to use the SSH backend.
|
||||
|
||||
- **Modal backend**
|
||||
- You need either a `MODAL_TOKEN_ID` environment variable or a `~/.modal.toml` config file.
|
||||
- Modal persistence is resumable filesystem state, not durable process continuity. If you need something to stay continuously up, use a deployment-oriented tool instead of the terminal sandbox.
|
||||
- If neither is present, the backend check fails and Hermes will report that the Modal backend is not available.
|
||||
- **Local** — No special requirements. The safest default when getting started.
|
||||
- **Docker** — Run `docker version` to verify Docker is working. If it fails, fix Docker or `hermes config set terminal.backend local`.
|
||||
- **SSH** — Both `TERMINAL_SSH_HOST` and `TERMINAL_SSH_USER` must be set. Hermes logs a clear error if either is missing.
|
||||
- **Modal** — Needs `MODAL_TOKEN_ID` env var or `~/.modal.toml`. Run `hermes doctor` to check.
|
||||
- **Daytona** — Needs `DAYTONA_API_KEY`. The Daytona SDK handles server URL configuration.
|
||||
- **Singularity** — Needs `apptainer` or `singularity` in `$PATH`. Common on HPC clusters.
|
||||
|
||||
When in doubt, set `terminal.backend` back to `local` and verify that commands run there first.
|
||||
|
||||
@@ -1021,7 +1126,8 @@ auxiliary:
|
||||
model: "" # e.g. "openai/gpt-4o", "google/gemini-2.5-flash"
|
||||
base_url: "" # Custom OpenAI-compatible endpoint (overrides provider)
|
||||
api_key: "" # API key for base_url (falls back to OPENAI_API_KEY)
|
||||
timeout: 30 # seconds — increase for slow local vision models
|
||||
timeout: 30 # seconds — LLM API call; increase for slow local vision models
|
||||
download_timeout: 30 # seconds — image HTTP download; increase for slow connections
|
||||
|
||||
# Web page summarization + browser page text extraction
|
||||
web_extract:
|
||||
@@ -1045,7 +1151,7 @@ auxiliary:
|
||||
```
|
||||
|
||||
:::tip
|
||||
Each auxiliary task has a configurable `timeout` (in seconds). Defaults: vision 30s, web_extract 30s, approval 30s, compression 120s. Increase these if you use slow local models for auxiliary tasks.
|
||||
Each auxiliary task has a configurable `timeout` (in seconds). Defaults: vision 30s, web_extract 30s, approval 30s, compression 120s. Increase these if you use slow local models for auxiliary tasks. Vision also has a separate `download_timeout` (default 30s) for the HTTP image download — increase this for slow connections or self-hosted image servers.
|
||||
:::
|
||||
|
||||
:::info
|
||||
|
||||
@@ -32,8 +32,8 @@ Set it to `false` only if you explicitly want one shared conversation per chat.
|
||||
## Step 1: Create a Feishu / Lark App
|
||||
|
||||
1. Open the Feishu or Lark developer console:
|
||||
- Feishu: <https://open.feishu.cn/>
|
||||
- Lark: <https://open.larksuite.com/>
|
||||
- Feishu: [https://open.feishu.cn/](https://open.feishu.cn/)
|
||||
- Lark: [https://open.larksuite.com/](https://open.larksuite.com/)
|
||||
2. Create a new app.
|
||||
3. In **Credentials & Basic Info**, copy the **App ID** and **App Secret**.
|
||||
4. Enable the **Bot** capability for the app.
|
||||
|
||||
@@ -161,9 +161,35 @@ Configure the TTS provider in your `config.yaml` under the `tts.provider` key.
|
||||
Hermes Agent works in Telegram group chats with a few considerations:
|
||||
|
||||
- **Privacy mode** determines what messages the bot can see (see [Step 3](#step-3-privacy-mode-critical-for-groups))
|
||||
- When privacy mode is on, **@mention the bot** (e.g., `@my_hermes_bot what's the weather?`) or **reply to its messages** to interact
|
||||
- When privacy mode is off (or bot is admin), the bot sees all messages and can participate naturally
|
||||
- `TELEGRAM_ALLOWED_USERS` still applies — only authorized users can trigger the bot, even in groups
|
||||
- You can keep the bot from responding to ordinary group chatter with `telegram.require_mention: true`
|
||||
- With `telegram.require_mention: true`, group messages are accepted when they are:
|
||||
- slash commands
|
||||
- replies to one of the bot's messages
|
||||
- `@botusername` mentions
|
||||
- matches for one of your configured regex wake words in `telegram.mention_patterns`
|
||||
- If `telegram.require_mention` is left unset or false, Hermes keeps the previous open-group behavior and responds to normal group messages it can see
|
||||
|
||||
### Example group trigger configuration
|
||||
|
||||
Add this to `~/.hermes/config.yaml`:
|
||||
|
||||
```yaml
|
||||
telegram:
|
||||
require_mention: true
|
||||
mention_patterns:
|
||||
- "^\\s*chompy\\b"
|
||||
```
|
||||
|
||||
This example allows all the usual direct triggers plus messages that begin with `chompy`, even if they do not use an `@mention`.
|
||||
|
||||
### Notes on `mention_patterns`
|
||||
|
||||
- Patterns use Python regular expressions
|
||||
- Matching is case-insensitive
|
||||
- Patterns are checked against both text messages and media captions
|
||||
- Invalid regex patterns are ignored with a warning in the gateway logs rather than crashing the bot
|
||||
- If you want a pattern to match only at the start of a message, anchor it with `^`
|
||||
|
||||
## Private Chat Topics (Bot API 9.4)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user