Hermes Operations v1.0.0 MIT
Hermes Config Revert and Restore
Use when reverting a Hermes profile's model to a backup. Later changes are kept. Covers snapshot, block-only restore, verification and reporting.
Features
- Inventory of the snapshot and the live configs before anything changes.
- A "before" snapshot of the live state, taken so the revert itself can be audited and undone.
- Comparison of one named block per profile, parsed as YAML.
- Block-only replacement, written atomically.
- Verification of the restored block and of the fallback chain that must not change.
- A summary that reports the before, now and after state for each profile.
Benefits
- Later changes to other keys survive the rollback.
- A failed revert leaves a recoverable state, because the pre-revert snapshot exists.
- Success is claimed only when the checks pass.
Install
From the tap (or GitHub path)
hermes skills install shagghiesuperstar/hermes-skills/skills/hermes-config-revert-restore --category hermes-operations
Direct URL
hermes skills install https://raw.githubusercontent.com/shagghiesuperstar/hermes-skills/main/skills/hermes-config-revert-restore/SKILL.md --category hermes-operations
Get the skill
Related skills
- Hermes OperationsVerify Before Write: Hermes Config Edit ProcedureUse when a script is about to write a Hermes config file. Covers the verification ladder that proves a write is needed and correct.
- Hermes OperationsHermes Fallback Chain DeploymentUse when rolling out or auditing Hermes fallback chains. The chains span several profiles. Covers the chain rules, credential gaps, verified writes, watching for silent fallbacks and rollback.
Related repos
The skill file
Hermes Config Revert and Restore
Overview
When a primary model was changed without authorization, or a verification run changed models it should not have, the fix is a rollback to the snapshot taken before the change. The obvious method is to copy the whole backup file back over the live one. That also restores every other key, so any legitimate change made after the snapshot, such as an updated fallback chain, is silently lost. This skill restores only the block that changed, checks that the rest of the file is intact, and reports the result with before and after evidence.
When to Use
- An operator-authorized request asks for a rollback to a named backup snapshot.
- A profile's primary model changed without approval and must return to its pre-change value.
- Several profiles changed, and only one block (such as
model:) should be restored in each. - A failure traces back to a config change that should not have happened.
Not for routine edits (use config-verify-before-write), for multi-file changes that belong to one atomic change, or for rollback of files unrelated to Hermes state (use version control or the standard backup tools).
Features
- Inventory of the snapshot and the live configs before anything changes.
- A "before" snapshot of the live state, taken so the revert itself can be audited and undone.
- Comparison of one named block per profile, parsed as YAML.
- Block-only replacement, written atomically.
- Verification of the restored block and of the fallback chain that must not change.
- A summary that reports the before, now and after state for each profile.
Benefits
- Later changes to other keys survive the rollback.
- A failed revert leaves a recoverable state, because the pre-revert snapshot exists.
- Success is claimed only when the checks pass.
Procedure
Confirm the authorization and the snapshot. Stop unless the request names both the backup set and the profiles:
ls -la <backup-dir>/<snapshot-set>/Every profile in scope needs a backup file in that set. If one is missing, stop and report it.
Snapshot the live state before any change. Keep the copy with its timestamps:
mkdir -p <backup-dir>/<revert-set> # Print the default config path with `hermes config path`, then copy that file: cp -p <default-config-path> <backup-dir>/<revert-set>/default-config.yaml # Print each profile's config path with `hermes -p <profile> config path`, then copy that file: cp -p <profile-config-path> <backup-dir>/<revert-set>/<profile>-config.yamlCompare the target block, parsed as YAML, for each profile. Profiles whose block already matches need no action:
import yaml from pathlib import Path def model_block(path: Path): return yaml.safe_load(path.read_text(encoding="utf-8")).get("model") snapshot = Path("<backup-dir>/<snapshot-set>") live_configs = {"<profile-a>": Path("<profile-a-config-path>"), "<profile-b>": Path("<profile-b-config-path>")} for profile in ["<profile-a>", "<profile-b>"]: before = model_block(snapshot / f"{profile}-config.yaml") now = model_block(live_configs[profile]) print(profile, "unchanged" if before == now else "NEEDS REVERT")Before you restore a profile, confirm the difference is a real change to the model and not formatting or comments.
Replace only that block in the live file, leaving every other line alone. Write the result to a temp file in the same directory and rename it over the original, so a crash cannot leave a half-written config:
import os from pathlib import Path def block_span(lines, key): start = next(i for i, l in enumerate(lines) if l.rstrip() == f"{key}:") end = next((i for i in range(start + 1, len(lines)) if lines[i].strip() and lines[i][0] not in " \t#"), len(lines)) return start, end def replace_block(config: Path, new_block: str, key="model"): lines = config.read_text(encoding="utf-8").splitlines(keepends=True) start, end = block_span(lines, key) updated = "".join(lines[:start]) + new_block + "".join(lines[end:]) tmp = config.parent / f"{config.name}.tmp" tmp.write_text(updated, encoding="utf-8") os.replace(tmp, config)Take
new_blockfrom the snapshot file with the same span function, so indentation and newlines match exactly. If the operator's order does not authorize a direct file edit, restore each key through the Hermes CLI instead, and read each value back.Verify the block immediately after each write. A mismatch means the revert has a defect. Halt, and do not check the other profiles until the defect is explained:
assert model_block(live_configs[profile]) == before, f"FATAL: {profile} model block differs after revert"Verify that the fallback chains were not changed by the revert:
for p in <profile-a> <profile-b>; do echo "== $p" hermes -p "$p" fallback list 2>&1 | head -9 doneCompare the output with the chain you expect. If a chain is missing or different, the revert is not clean.
- Report the result per profile: the model before the change, the model now, and the model after the revert. Include the fallback output. End with one line in this form, with real counts:
REVERT host=<host> profiles_checked=<n> primaries_restored=<m> fallback_untouched=yesClaim success only when every check passed and the counts match the request.
Pitfalls
- Never copy a whole backup file over a live config to undo one change. It also restores every other key, including fallback chains and other settings that changed after the snapshot.
- Snapshot the live state before you change it. The snapshot is the "before" for the audit trail and the way back if the revert fails.
- Parse the block; do not grep for it. A grep can match a similar line in another section, such as a per-platform override.
- Verify right after each write. Deferring the check to the end hides which write broke the file.
- A failed block check stops the run. Do not continue to the fallback check or to other profiles with a defect unexplained.
- Write atomically. A temp file and a rename survive a crash. An in-place edit does not.
- Re-check the snapshot before you rely on it. Confirm it is the snapshot the order names, and that its timestamps are the expected ones.
- Do not claim a revert succeeded from the command exit code alone. Read the block back, and read the chains back.
- Authorization covers the named profiles only. Do not widen the revert to other profiles that look similar.
- Log the cause, not only the fix. Record which change was unauthorized and where it came from, so the same path is closed.
Verification
- Each reverted profile's
modelblock parses to the same value as its snapshot. - Each profile's fallback chain prints the same entries as before the revert.
- The pre-revert snapshot directory exists and holds one file per profile in scope.
- The summary line reports the expected profile and restore counts, and
fallback_untouched=yes.