Home Blog About
11 min read

From OpenClaw to Hermes: How I Retired an Agent Home Without Losing the Archive

How to retire an OpenClaw home after moving to Hermes without losing archive access, breaking cron jobs, or leaving stale git hook paths behind.

TechnologyAIAgentic AIOpenClawHermesmigrationDevOpsautomation

I did not want a dramatic migration.

No greenfield rebuild. No “we’ll clean it up later” folder rename that quietly becomes permanent. No week of broken cron jobs because one absolute path survived somewhere in a forgotten shell script.

I wanted the boring outcome: the old OpenClaw home retired, the new Hermes home live, the archive still readable, and the automation layer still doing its job the next morning.

That sounds straightforward until you remember what an agent home actually accumulates over time. It isn’t just prompts and a couple of Markdown files. It is scheduled jobs, helper scripts, repo-local git hooks, backup routines, path assumptions, and a long tail of tiny operational habits that only show themselves when something disappears.

This post is the migration pattern I ended up using to move from OpenClaw to Hermes without losing continuity.

If you are planning an OpenClaw to Hermes migration, the short version is simple: archive the old home somewhere clearly historical, remove legacy paths from live execution surfaces, and verify cron plus repo hooks before you declare the move done.

If you’ve read my earlier posts on portable agent migrations, persistent memory and DR, or memory architecture evolution, this is the next chapter: not portability in theory, but retirement in production.

OpenClaw to Hermes retirement checklist

If you want the compressed version first, this is the sequence I would recommend:

  1. inventory every live .openclaw reference across cron, hooks, wrappers, and helper scripts
  2. move the old home into a clearly archived location with timestamped snapshots
  3. rewrite enabled jobs so runnable helpers live under ~/.hermes/
  4. replace hardcoded hook binaries with dynamic discovery plus safe no-op behavior
  5. keep the archive readable, but make sure new workflows stop writing or executing there
  6. verify the failure surfaces that matter in practice: cron, commits, pushes, and backup reads

The real problem was not copying files

Copying data was the easy part.

The hard part was removing what I think of as accidental authority.

A legacy agent home can keep influencing the system long after you decide it is “old.” The path still looks canonical. Old scripts still point at it. Git hooks still assume binaries live under it. Cron prompts still mention it because they were written months ago and nobody touched them since. If that path remains executable, the old home is not really archived. It is still part of the live system, whether you intended that or not.

That is where migrations go sideways. You think you have one active home and one archive. In reality you have two partially live homes competing for attention.

The goal, then, was not just “move OpenClaw into Hermes.” The goal was:

  1. preserve the old material as an archive
  2. remove the old path from live execution
  3. verify the new live surfaces actually run

That order matters.

What I wanted at the end

I wrote the target state down before touching anything:

  • Hermes is the only live agent home
  • the old OpenClaw workspace remains accessible as historical reference
  • enabled automation does not execute from legacy paths
  • repo-local git hooks do not depend on binaries inside the retired home
  • old references that remain are clearly archival, disabled, or harmless metadata

That sounds obvious. It is still worth stating explicitly, because migrations fail when “keep history” and “stop using the old thing” get blurred together.

Step 1: separate archive references from live execution

The first useful move was inventory, not editing.

I searched for legacy path references across the usual places:

  • cron job prompts and scripts
  • repo-local .git/hooks/*
  • wrapper scripts under ~/bin
  • helper scripts inside active repos
  • backup and DR workflows
  • documentation that might still be used as an operational runbook

At this stage I was not trying to delete every mention of OpenClaw. That would have been the wrong metric.

Some references should survive. Historical notes are fine. Old plans are fine. Migration records are fine. Archive-only reads are fine.

What matters is whether a reference still participates in live execution.

That gave me a much cleaner split:

  • archive references: allowed to stay
  • execution references: must be rewritten, disabled, or turned into safe no-ops

This distinction saved a lot of wasted work. It also prevented the classic overcorrection where you start scrubbing history and end up destroying useful context.

Step 2: move the archive somewhere that looks like an archive

I did not want the historical OpenClaw state sitting in the same old canonical location.

The archive now lives under Hermes migration storage as timestamped snapshots rather than pretending to be a current working home. That matters more than it sounds. Naming is operational policy. If an old directory still looks like the real one, future scripts and future-you will treat it like the real one.

The timestamped archive approach gave me two things:

  • a durable historical record I can still inspect
  • a clear signal that this material is preserved, not live

This is one of those boring details that pays off later. If you ever need to recover context, check a historical prompt, or inspect an old workflow, you want the archive easy to browse. You just don’t want anything writing to it by accident.

Step 3: fix cron before it surprises you later

Cron jobs were the first major execution surface.

The important distinction here was between jobs carrying legacy metadata and jobs still carrying live executable paths into the retired home. They are not the same thing.

After the migration pass, I verified that:

  • 0 enabled jobs still executed from .openclaw paths
  • 44 job definitions still mentioned .openclaw in execution-related fields, but none of them were enabled

That is the state I actually wanted.

I did not need the file to become aesthetically pure. I needed the active scheduler to stop depending on a retired home.

In practice, the working pattern was simple:

  • move live helper scripts into ~/.hermes/scripts/
  • rewrite enabled job prompts to point at Hermes paths
  • leave non-live historical references alone unless they were confusing enough to become a future footgun

This is the broader lesson: scheduler cleanup is not a search-and-replace exercise. Some jobs need a direct path swap. Some need state moved with them. Some are better left disabled as historical evidence rather than force-migrated badly.

Step 4: the hooks were the nastier problem

The stale git hooks were more annoying than the cron jobs because they fail at exactly the wrong time.

Everything looks fine right until you commit or push. Then some forgotten repo-local hook tries to execute a binary under the old OpenClaw tree and your workflow stops for reasons that feel completely unrelated to the change you were making.

That happened here too.

The fix was not to rip hooks out everywhere. It was to make them degrade safely.

Across my repos, the old hooks were hardcoded to a binary path inside the retired OpenClaw home. I replaced that pattern with a small guard:

#!/bin/sh
ENTIRE_BIN="${ENTIRE_BIN:-$(command -v entire 2>/dev/null || true)}"
[ -x "$ENTIRE_BIN" ] || exit 0
"$ENTIRE_BIN" hooks git commit-msg "$1" || exit 1

That does three useful things:

  1. it prefers a live entire binary if one is installed
  2. it stops depending on an absolute path inside the retired home
  3. it exits cleanly when the binary does not exist

In other words, the hook becomes optional infrastructure instead of a migration landmine.

After the cleanup pass, I verified 79 hook files across 16 repositories were on the safe pattern, and the smoke test passed with 0 failures.

That number mattered less than the behavior. The real win was that commit and push stopped being booby-trapped by old assumptions.

Step 5: preserve archive access without preserving accidental writes

A migration archive is only useful if you can still read it.

That sounds trivial, but there is a bad version of “retire the old directory” where you make the live system safer by making the history harder to access. Then six weeks later you need to answer a question about an old workflow, a recovery script, or a cron design decision, and you have to reverse-engineer it from fragments.

I wanted the opposite trade-off:

  • old state remains readable
  • old state loses authority

That meant keeping the archived workspace available under Hermes migration storage and making sure new workflows read from Hermes by default. Historical material is still there when I need it. It just stopped being where live automation writes or executes from.

If you only take one idea from this post, make it this one: archive should remain searchable, but not runnable by accident.

Step 6: verify from the surfaces that fail in real life

A migration is not done when the files look tidy.

It is done when the failure surfaces have been exercised.

My verification pass focused on the boring places that actually break production use:

Cron verification

I checked that enabled jobs no longer executed from legacy .openclaw paths.

Hook verification

I smoke-tested the repaired hooks across the affected repositories and confirmed clean exits.

Filesystem verification

I checked that Hermes was the live home and that the old canonical .openclaw location was no longer present as a live directory.

That last one matters. An old path can keep influencing the system simply because it still exists in a shape that looks valid.

What changed in my migration philosophy

Before doing this, I thought of agent-home migration mostly as a backup-and-restore problem.

Now I think of it as an execution-surface audit.

Backups matter. Archive layout matters. Memory portability matters. I still believe all of that. But the risky part of a migration is not the copy. The risky part is the long tail of places where the old home still has operational power.

That includes:

  • scheduler prompts
  • shell wrappers
  • repo-local hooks
  • helper binaries
  • DR scripts
  • “temporary” compatibility fixes that never get revisited

If you don’t audit those surfaces, you have not retired the old home. You have just demoted it cosmetically.

The pattern I would reuse next time

If I had to do this again on another agent stack, I would follow the same sequence:

1. Inventory first

Search everything. Separate historical references from live execution.

2. Rename or relocate the archive clearly

Make the old home look archived, not canonical.

3. Rewrite active scheduler surfaces

Move runnable helpers into the new home and verify enabled jobs point there.

4. Neutralize repo-local hooks

Prefer dynamic binary discovery and safe no-op behavior over hardcoded absolute paths.

5. Keep the archive readable

Do not treat archive access and archive execution as the same thing.

6. Verify by running the surfaces that would actually fail

Commits. Pushes. Cron. Backup checks. The boring stuff.

Why this matters beyond OpenClaw and Hermes

The names here are specific. The pattern is not.

Any serious agent setup grows hidden dependencies on its home directory. Once you have memory, scripts, scheduled tasks, and multiple repos in the loop, your “workspace path” stops being a folder and starts being infrastructure.

That is why migrations are harder than they look from the outside. You are not moving text files around. You are changing the root assumption of an automation system.

Hermes is the live home now. OpenClaw is preserved as history. That is exactly the boundary I wanted.

No drama. No mysterious broken commits a week later. No archive loss. Just a cleaner separation between what is still running and what deserves to be remembered.

That is the migration standard I care about now.

Sources

Share: