21 KiB
Migration Guide
OpenSquilla can import state from OpenClaw and Hermes Agent into OpenSquilla native files. The migration commands are designed to be previewed first, then applied explicitly.
Supported migration paths:
- Auto-detect everything found under your home:
opensquilla migrate - OpenClaw -> OpenSquilla:
opensquilla migrate openclaw - Hermes Agent -> OpenSquilla:
opensquilla migrate hermes
opensquilla migrate (with no subcommand) scans ~/.openclaw and
~/.hermes and decides what to do based on what it finds:
- Nothing detected: prints the default paths it checked and exits 0.
- Exactly one detected: runs that migrator. No prompt, no flag needed.
- Both detected, interactive (TTY) shell: opens a multi-select prompt so you can pick one, both, or neither.
- Both detected, non-interactive context (CI, piped,
--json): prints the detected sources and exits 0 without migrating. Re-run with--source openclaw,hermes(or a subset) to opt in explicitly.
When both sources are selected, OpenSquilla runs OpenClaw first and Hermes
second. The second migrator sees whatever the first one wrote, so its
existing per-file dedupe / persona-conflict rules kick in normally. Use
--source openclaw or --source hermes (comma-separated) to narrow the
selection.
If you are running from a source checkout instead of an installed
opensquilla command, prefix the examples with uv run:
uv run opensquilla migrate openclaw --json
uv run opensquilla migrate hermes --json
Before You Start
- Stop any running OpenSquilla gateway if it is using the target home.
- Make a manual backup of your OpenSquilla home if you need whole-home
rollback. The migrators can back up overwritten items, but they do not yet
create a complete pre-migration snapshot of
~/.opensquilla. - Run a dry run first and inspect the report.
- Do not pass
--migrate-secretsuntil you have reviewed what will be copied.
Default locations:
- OpenSquilla home:
~/.opensquilla - OpenClaw source home:
~/.openclaw - Hermes Agent source home:
~/.hermes
On Windows, these are under your user profile, for example
C:\Users\<you>\.opensquilla.
Common Options
Both migration commands support the same main controls:
| Option | Meaning |
|---|---|
--source PATH |
Source OpenClaw or Hermes Agent home. |
--config PATH |
OpenSquilla config path to preview or write. |
--apply |
Apply the migration. Without this, the command is a dry run. |
--migrate-secrets |
Copy recognized secrets such as API keys and channel tokens. Defaults to false. |
--overwrite |
Allow replacing existing targets. Existing overwritten items are backed up where supported. |
--preset user-data |
Migrate only user-facing data such as persona, memory, and skills. |
--preset full |
Migrate user data plus supported config/runtime artifacts. This is the default. |
--include IDS |
Include only selected migration option ids. Comma-separated. |
--exclude IDS |
Exclude selected migration option ids. Comma-separated. |
--skill-conflict MODE |
Handle imported skill name conflicts: skip, overwrite, or rename. |
--json |
Print a machine-readable report. Recommended for dry runs. |
OpenClaw -> OpenSquilla
Use this path if your existing agent state is in an OpenClaw home.
Preview first:
opensquilla migrate openclaw --json
Preview a custom OpenClaw home:
opensquilla migrate openclaw --source /path/to/.openclaw --json
Apply without secrets:
opensquilla migrate openclaw --apply
Apply and copy recognized secrets:
opensquilla migrate openclaw --apply --migrate-secrets
Apply and rename imported skill conflicts instead of skipping them:
opensquilla migrate openclaw --apply --skill-conflict rename
What Is Migrated From OpenClaw
OpenSquilla currently maps OpenClaw data into OpenSquilla-native locations:
- Workspace persona files such as
SOUL.md,AGENTS.md, andUSER.md. - Long-term memory and daily memory where supported.
- User skills and shared skills, imported under
~/.opensquilla/skills/openclaw-imports/. - TTS assets, while unsupported TTS configuration is archived for review.
- Command allowlists.
- Model config, including string, object, and alias/catalog forms.
- Provider keys from
.envor provider config when--migrate-secretsis set. - MCP server definitions where OpenSquilla has native fields.
- Telegram, Discord, and Slack channel config where OpenSquilla has native channel support.
- Selected agent and tool settings with OpenSquilla-native equivalents.
- Unsupported or unsafe OpenClaw artifacts are archived for manual review.
The OpenClaw migrator also rewrites OpenClaw branding in migrated user-facing workspace text to OpenSquilla branding and archives the original changed text for review.
Mixed-subject prose is kept verbatim. When a workspace file (or a
single MEMORY.md block) already mentions OpenSquilla (any case), the
migrator skips the mechanical rebrand for that file/block and writes it
verbatim. Mechanical replacement of OpenClaw -> OpenSquilla in prose
that already names both runtimes as distinct entities produces factual
errors and self-referential nonsense. The report records
details.rebrand_skipped: "mentions-opensquilla" for the affected file
and, for MEMORY.md, details.rebrand_skipped_block_count so you can
reword the relevant lines by hand.
SOUL.md / USER.md / AGENTS.md Conflict Handling
These persona files are identity definitions (not additive like memory), so when the destination already holds real user-curated content the migrator asks you which version to keep instead of either silently dropping the imported content or clobbering the existing file.
Use --persona-conflict to control the behavior:
| Mode | Behavior |
|---|---|
prompt (default) |
When stdin is a TTY: prompt for each conflicting file with a side-by-side preview and the four choices below. When stdin is not a TTY (CI, pipe, --json): fall back to use-opensquilla and record a note so the choice is visible in the report. |
use-opensquilla |
Keep the destination file untouched. The OpenClaw original is copied to <output_dir>/archive/files/openclaw-orphaned/<filename> for review so nothing is silently lost. status: skipped, details.persona_conflict_resolution: "use-opensquilla". |
use-openclaw |
Back up the destination to <name>.backup.<timestamp> and replace it with the OpenClaw content. status: migrated, details.persona_conflict_resolution: "use-openclaw". |
merge |
Back up the destination and append the OpenClaw content below it under a ## Imported from OpenClaw separator. Useful when the two versions are complementary rather than conflicting. status: migrated, details.persona_conflict_resolution: "merge". |
skip |
Leave both files alone. The OpenClaw original is not archived — use use-opensquilla instead if you want a recoverable copy. status: skipped, details.persona_conflict_resolution: "skip". |
--overwrite short-circuits all of this and replaces the destination
wholesale (still with an item-level backup).
The pristine bootstrap-template case described below is handled before
--persona-conflict and never asks for input: a freshly initialised
OpenSquilla workspace where the template is still untouched is treated as
overwrite-safe.
MEMORY.md Merge Semantics
OpenClaw memory is additive by nature: every imported daily-memory file is
its own ## Imported daily memory: <name> section. The OpenClaw migrator
therefore handles MEMORY.md differently from other workspace files: it
will never silently overwrite existing user-curated memory and it will
never silently drop the imported memory either.
Behaviour matrix (without --overwrite):
| Destination state | What happens |
|---|---|
MEMORY.md does not exist |
Imported memory is written fresh. |
| Pristine OpenSquilla bootstrap template | Template is backed up, imported memory replaces it. details.replaced_bootstrap_template: true. |
| Real user-curated content | Imported blocks that are not already present (after a whitespace-normalised, header-stripped comparison) are appended below the existing content. The pre-existing file is backed up first. details.appended_to_existing: true, new_blocks_appended: N, deduplicated_blocks_vs_existing: M. |
| All imported blocks already present | The file is left untouched. status: skipped, reason: "all openclaw memory blocks already present in destination", details.deduplicated_against_existing: true. No backup created. |
--overwrite is the explicit "replace, do not merge" escape hatch — the
destination is backed up and replaced wholesale regardless of its current
contents.
OpenSquilla Bootstrap-Template Handling
ensure_agent_workspace seeds placeholder SOUL.md / USER.md /
AGENTS.md / MEMORY.md files when an OpenSquilla home is first
initialised. Without special handling those placeholders would block every
workspace-file migration with a silent conflict: target exists —
including the imported daily memory the user is migrating for in the first
place.
The OpenClaw migrator detects a destination that still holds the pristine bootstrap template (byte-identical to the shipped placeholder after a trailing-whitespace normalisation) and treats it as overwrite-safe:
- The pristine template is backed up to
<name>.backup.<timestamp>next to the destination so the placeholder guidance can be recovered on demand. - The imported content replaces the template.
- The migration report marks the item with
details.replaced_bootstrap_template: trueso the special case is visible rather than silent.
A destination file that the user has truly edited (i.e. no longer matches
the canonical template byte-for-byte) still gets the normal
status: conflict treatment — only the pristine placeholder is treated
as overwrite-safe. To accept user edits being overwritten as well, pass
--overwrite.
OpenClaw Limits
Some OpenClaw runtime behavior is not fully mapped yet:
- WhatsApp and Signal settings are detected, but OpenSquilla does not yet create native migrated channel entries for them.
- Some advanced MCP fields such as headers/auth/cwd/include/exclude are not native mapped.
- Some gateway, session, browser, approval, logging, plugin, cron, hook, memory backend, skills registry, and UI settings are archived rather than applied.
- OpenSquilla does not widen channel privileges: ordinary OpenClaw allowlists are not treated as OpenSquilla admin senders.
Review MIGRATION_NOTES.md after an applied migration for partial mappings and
manual follow-up.
Hermes Agent -> OpenSquilla
Use this path if your existing agent state is in a Hermes Agent home.
Preview first:
opensquilla migrate hermes --json
Preview a custom Hermes Agent home:
opensquilla migrate hermes --source /path/to/.hermes --json
Preview a Hermes profile:
opensquilla migrate hermes --profile work --json
Apply without secrets:
opensquilla migrate hermes --apply
Apply and copy recognized secrets:
opensquilla migrate hermes --apply --migrate-secrets
Apply and rename imported skill conflicts instead of skipping them:
opensquilla migrate hermes --apply --skill-conflict rename
What Is Migrated From Hermes Agent
OpenSquilla currently maps the common Hermes Agent home surface:
- Persona and user data files such as
SOUL.md,MEMORY.md, andUSER.md. - Hermes skills, imported under
~/.opensquilla/skills/hermes-imports/. - Hermes model/provider config where there is an OpenSquilla-native equivalent.
- Hermes custom providers with
base_url, mapped to OpenAI-compatible provider config. - Environment values and recognized provider keys when
--migrate-secretsis set. - Search config where supported.
- MCP server definitions where supported.
- Telegram, Discord, and Slack channel tokens when
--migrate-secretsis set. - Selected plugin, cron, and unsupported runtime artifacts are archived for review.
Hermes Agent Limits
The Hermes Agent migrator is newer than the OpenClaw migrator and has a smaller coverage surface. Review the dry-run report carefully before applying.
Current limits:
- Live runtime state, active sessions, process state, and gateway state are not imported.
- Some Hermes runtime config option ids are accepted but currently deferred:
workspace-files,tools-config,browser-config,session-config,gateway-config,approvals-config,logging-config, andmemory-backend. Each appears in the migration report asstatus: deferredwith reasonhandler not implemented yet. Selecting them via--includeis not an error; the migrator just records the gap so it is visible. - Browser, tool, session, gateway, approval, and logging settings may require manual review.
- A full pre-apply snapshot of
~/.opensquillais not created automatically.
Hermes Agent Migration Behavior
The Hermes migrator now mirrors the OpenClaw migrator on a few correctness behaviors that were previously documented but not implemented:
- Item-level backups. When
--overwritereplaces an existing workspace file (SOUL.md,MEMORY.md,USER.md) or skill directory, the prior contents are written to<name>.backup.<timestamp>next to the original before the new content is applied. - Semantic deduplication on merge. Existing destination content is split into paragraph blocks and compared after whitespace normalization. A new source body is appended unless an equivalent block already exists. The previous naive substring check could silently drop short source bodies.
- Memory overflow archival. If the merged
MEMORY.mdwould exceed OpenSquilla's per-file size limit, the overflow is split at a paragraph boundary and archived to~/.opensquilla/migration/hermes/<timestamp>/archive/memory-overflow/MEMORY.overflow.md. A short pointer is left at the end ofMEMORY.md. - Branding rewrite. Hermes branding in imported workspace prose
(
SOUL.md,MEMORY.md,USER.md) is rewritten to OpenSquilla. BareHermesis only rewritten when it is followed by a workspace-context word (e.g.home,workspace,memory,config). Source-reference tokens such asHERMES_HOME,NousResearch, andhermes-agentare preserved so the migration archive still points back at the original source. The unrebranded original is copied to<output_dir>/archive/files/workspace-original/<name>.mdfor review. - Path-token replacement is word-boundary aware. Previously a plain
string replace turned
~/.hermesrcinto~/.opensquillarcand.hermes_backupinto.opensquilla_backup— meaningless paths. The rebrand now only rewrites.hermeswhen it ends a path token (i.e. followed by/, whitespace, quote, or end-of-string). Same rule applied to.openclawon the OpenClaw side, and bare-wordOpenClaw/openclaware now matched with\bso substrings likeOpenClawFlavoredoropenclaw_pidare left alone. - Non-UTF-8 source files no longer crash. Hand-edited source files
with stray bad bytes (CP1252 fragments, leftover binary paste, etc.)
used to abort the entire Hermes migration with
UnicodeDecodeError. The source read now useserrors="replace"(matching OpenClaw); offending bytes become U+FFFD so users can spot them. mcp.enabled = falseis no longer silently flipped. When the destination home already has MCP servers ANDmcp.enabled = false(an explicit "I don't want MCP right now" choice), importing more MCP servers leaves the flag atfalseand surfacesdetails.mcp_enabled_left_disabledplus amanual_stepshint. MCP is still flipped on automatically when the destination had no servers (framework default — flipping is what the user wants).- Mixed-subject prose is kept verbatim. Workspace notes often
describe Hermes AND OpenSquilla as distinct entities ("Hermes Agent
v0.13.0 installed at ~/.local/bin/hermes; OpenSquilla also installed
at ~/.local/bin/opensquilla. Has
migrate hermessubcommand."). A mechanical rebrand collapses the two subjects into one and produces factual errors (path mismatches), tautologies ("OpenSquilla skills loadable by OpenSquilla"), and self-referential commands ("migrate OpenSquilla skills to OpenSquilla"). When the source already mentionsOpenSquilla(any case), the migrator now skips rebrand for that file and writes it verbatim, recordingdetails.rebrand_skipped: "mentions-opensquilla"so you can decide which mentions to reword by hand. The same rule applies per-block during MEMORY.md merging; the count of skipped blocks is reported viadetails.rebrand_skipped_block_count. - Skill compatibility reporting. Each imported skill's
report record now includes
details.compatibility(loadable/needs_review/not_loadable) anddetails.compatibility_issueslisting missing frontmatter, oversize bodies, or invalid YAML. Skills are still copied; the field is informational so you can find ones that may need attention before activating. - Unknown providers are no longer written to
llm.provider. Hermes uses values likeauto(runtime auto-detect) and may ship experimental providers (bedrock,ollama, ...) that have no OpenSquilla equivalent. Writing them verbatim used to crashpersist_configbecause OpenSquilla validatesllm.provideragainst a known set AND requiressquilla_router.tier_profileto agree with it. The migrator now leavesllm.provideruntouched in that case; the model id and base URL are still migrated, and the model-config item carriesdetails.unrecognized_provider,details.llm_provider_left_unchanged, and amanual_stepshint explaining how to set the provider explicitly. - Known providers that clash with an existing
squilla_router.tier_profileare also not written. Even when the Hermes provider is recognized (e.g.anthropic), persisting it would fail if the destination home already pinssquilla_router.tier_profileto a different provider (e.g.openrouter) — OpenSquilla requires the two to match. The migrator now detects the clash, leavesllm.providerunchanged, and recordsdetails.tier_profile_conflict,details.llm_provider_left_unchanged, and amanual_stepshint so you can switch providers explicitly viaopensquilla config setor by clearingsquilla_router.tier_profilefirst. - MCP server entries upsert instead of replacing. Both migrators
used to assign
cfg.mcp.servers = imported, silently destroying any pre-existing OpenSquilla MCP servers the user already had configured. Now the imported servers are upserted by name: same-name entries are replaced (the imported version wins), unrelated entries are preserved. Themcp-serversreport record carriesdetails.added,details.replaced, anddetails.preserved_existing. - Resilient SKILL.md compatibility check. A SKILL.md with empty or
non-dict YAML frontmatter (e.g.
---\n\n---) used to crash the whole migration withAttributeError. The check now records the skill ascompatibility: "not_loadable"and continues. The reportedcompatibilitystring is also kept consistent with theopensquilla_loadableboolean.
Reports
Use --json for dry-run automation:
opensquilla migrate openclaw --json
opensquilla migrate hermes --json
Applied migrations write report files under:
~/.opensquilla/migration/openclaw/<timestamp>/
~/.opensquilla/migration/hermes/<timestamp>/
Typical files:
report.json: structured item-level report.summary.md: human-readable count summary.MIGRATION_NOTES.md: OpenClaw migration notes when semantic conversions or partial mappings are present.archive/: unsupported or review-only artifacts.
Hermes dry runs also write report files. OpenClaw dry runs are best inspected
with --json; apply mode writes the report files.
Validate After Migration
After applying a migration, start the gateway and run a small chat check:
opensquilla gateway start --json
opensquilla chat
Or use a one-shot prompt:
opensquilla agent -m "Briefly summarize your active persona and available memory."
Also check:
~/.opensquilla/workspace/for migrated persona and memory files.~/.opensquilla/skills/openclaw-imports/or~/.opensquilla/skills/hermes-imports/.~/.opensquilla/migration/<source>/<timestamp>/summary.md.~/.opensquilla/migration/<source>/<timestamp>/MIGRATION_NOTES.mdwhen present.
If behavior does not look right, stop the gateway, review the migration report,
and re-run with a narrower --preset, --include, or --exclude selection.
Examples
Migrate only user data from OpenClaw:
opensquilla migrate openclaw --preset user-data --apply
Migrate only Hermes skills and persona files:
opensquilla migrate hermes --include soul,skills --apply
Preview OpenClaw migration while excluding channel settings:
opensquilla migrate openclaw --exclude telegram-settings,discord-settings,slack-settings --json
Apply Hermes migration to a custom config file:
opensquilla migrate hermes --config /path/to/opensquilla.toml --apply