fix(backup): hermes import never overwrites volatile gateway runtime state (NS-501/508) - #48243
Merged
Merged
Conversation
…state (NS-501) Importing a backup wrote every file from the zip over the target home wholesale. On a hosted instance this clobbered gateway_state.json with the source machine's last recorded run/desired state — driving the container-boot reconciler (container_boot._read_desired_state, which only auto-starts a gateway whose state is "running") off stale/foreign state and leaving the gateway stuck "starting", disconnected from the Nous portal. Add _IMPORT_SKIP_NAMES (gateway_state.json, gateway.pid, cron.pid, gateway.lock, processes.json) and skip them by basename in run_import, so both the root profile and named profiles preserve the target's own runtime state. This mirrors what container_boot._STALE_RUNTIME_FILES already sweeps on every container boot, and protects against older backups that predate the backup-side exclusions. The import summary reports which files were preserved. This is the second half of NS-501 (filed separately as NS-508): the upload 502 was fixed in #47663; this fixes the import-breaks-the-instance half.
Contributor
🔎 Lint report:
|
| Rule | Count |
|---|---|
invalid-assignment |
1 |
First entries
tests/run_agent/test_credits_notices_toggle.py:76: [invalid-assignment] invalid-assignment: Object of type `None` is not assignable to attribute `_credits_session_start_micros` of type `int`
✅ Fixed issues (2):
| Rule | Count |
|---|---|
unresolved-attribute |
2 |
First entries
run_agent.py:2941: [unresolved-attribute] unresolved-attribute: Object of type `Self@get_credits_spent_micros` has no attribute `_credits_session_start_micros`
tests/run_agent/test_credits_notices_toggle.py:76: [unresolved-attribute] unresolved-attribute: Unresolved attribute `_credits_session_start_micros` on type `AIAgent`
Unchanged: 5760 pre-existing issues carried over.
Diagnostics are surfaced as warnings — this check never fails the build.
xyshanren
pushed a commit
to xyshanren/hermes-agent-cn
that referenced
this pull request
Jun 25, 2026
…state (NS-501) (NousResearch#48243) Importing a backup wrote every file from the zip over the target home wholesale. On a hosted instance this clobbered gateway_state.json with the source machine's last recorded run/desired state — driving the container-boot reconciler (container_boot._read_desired_state, which only auto-starts a gateway whose state is "running") off stale/foreign state and leaving the gateway stuck "starting", disconnected from the Nous portal. Add _IMPORT_SKIP_NAMES (gateway_state.json, gateway.pid, cron.pid, gateway.lock, processes.json) and skip them by basename in run_import, so both the root profile and named profiles preserve the target's own runtime state. This mirrors what container_boot._STALE_RUNTIME_FILES already sweeps on every container boot, and protects against older backups that predate the backup-side exclusions. The import summary reports which files were preserved. This is the second half of NS-501 (filed separately as NS-508): the upload 502 was fixed in NousResearch#47663; this fixes the import-breaks-the-instance half.
waefrebeorn
pushed a commit
to waefrebeorn/slermes
that referenced
this pull request
Jul 2, 2026
…state (NS-501) (NousResearch#48243) Importing a backup wrote every file from the zip over the target home wholesale. On a hosted instance this clobbered gateway_state.json with the source machine's last recorded run/desired state — driving the container-boot reconciler (container_boot._read_desired_state, which only auto-starts a gateway whose state is "running") off stale/foreign state and leaving the gateway stuck "starting", disconnected from the Nous portal. Add _IMPORT_SKIP_NAMES (gateway_state.json, gateway.pid, cron.pid, gateway.lock, processes.json) and skip them by basename in run_import, so both the root profile and named profiles preserve the target's own runtime state. This mirrors what container_boot._STALE_RUNTIME_FILES already sweeps on every container boot, and protects against older backups that predate the backup-side exclusions. The import summary reports which files were preserved. This is the second half of NS-501 (filed separately as NS-508): the upload 502 was fixed in NousResearch#47663; this fixes the import-breaks-the-instance half.
habarmc1223-sudo
pushed a commit
to habarmc1223-sudo/hermes-agent-fluxmem
that referenced
this pull request
Jul 8, 2026
…state (NS-501) (NousResearch#48243) Importing a backup wrote every file from the zip over the target home wholesale. On a hosted instance this clobbered gateway_state.json with the source machine's last recorded run/desired state — driving the container-boot reconciler (container_boot._read_desired_state, which only auto-starts a gateway whose state is "running") off stale/foreign state and leaving the gateway stuck "starting", disconnected from the Nous portal. Add _IMPORT_SKIP_NAMES (gateway_state.json, gateway.pid, cron.pid, gateway.lock, processes.json) and skip them by basename in run_import, so both the root profile and named profiles preserve the target's own runtime state. This mirrors what container_boot._STALE_RUNTIME_FILES already sweeps on every container boot, and protects against older backups that predate the backup-side exclusions. The import summary reports which files were preserved. This is the second half of NS-501 (filed separately as NS-508): the upload 502 was fixed in NousResearch#47663; this fixes the import-breaks-the-instance half.
santhreal
pushed a commit
to santhreal/hermes-agent
that referenced
this pull request
Jul 13, 2026
…state (NS-501) (NousResearch#48243) Importing a backup wrote every file from the zip over the target home wholesale. On a hosted instance this clobbered gateway_state.json with the source machine's last recorded run/desired state — driving the container-boot reconciler (container_boot._read_desired_state, which only auto-starts a gateway whose state is "running") off stale/foreign state and leaving the gateway stuck "starting", disconnected from the Nous portal. Add _IMPORT_SKIP_NAMES (gateway_state.json, gateway.pid, cron.pid, gateway.lock, processes.json) and skip them by basename in run_import, so both the root profile and named profiles preserve the target's own runtime state. This mirrors what container_boot._STALE_RUNTIME_FILES already sweeps on every container boot, and protects against older backups that predate the backup-side exclusions. The import summary reports which files were preserved. This is the second half of NS-501 (filed separately as NS-508): the upload 502 was fixed in NousResearch#47663; this fixes the import-breaks-the-instance half.
Gravezzz
pushed a commit
to Gravezzz/hermes-agent
that referenced
this pull request
Jul 21, 2026
…state (NS-501) (NousResearch#48243) Importing a backup wrote every file from the zip over the target home wholesale. On a hosted instance this clobbered gateway_state.json with the source machine's last recorded run/desired state — driving the container-boot reconciler (container_boot._read_desired_state, which only auto-starts a gateway whose state is "running") off stale/foreign state and leaving the gateway stuck "starting", disconnected from the Nous portal. Add _IMPORT_SKIP_NAMES (gateway_state.json, gateway.pid, cron.pid, gateway.lock, processes.json) and skip them by basename in run_import, so both the root profile and named profiles preserve the target's own runtime state. This mirrors what container_boot._STALE_RUNTIME_FILES already sweeps on every container boot, and protects against older backups that predate the backup-side exclusions. The import summary reports which files were preserved. This is the second half of NS-501 (filed separately as NS-508): the upload 502 was fixed in NousResearch#47663; this fixes the import-breaks-the-instance half.
leewenjie
pushed a commit
to leewenjie/hermes-agent
that referenced
this pull request
Aug 7, 2026
…state (NS-501) (NousResearch#48243) Importing a backup wrote every file from the zip over the target home wholesale. On a hosted instance this clobbered gateway_state.json with the source machine's last recorded run/desired state — driving the container-boot reconciler (container_boot._read_desired_state, which only auto-starts a gateway whose state is "running") off stale/foreign state and leaving the gateway stuck "starting", disconnected from the Nous portal. Add _IMPORT_SKIP_NAMES (gateway_state.json, gateway.pid, cron.pid, gateway.lock, processes.json) and skip them by basename in run_import, so both the root profile and named profiles preserve the target's own runtime state. This mirrors what container_boot._STALE_RUNTIME_FILES already sweeps on every container boot, and protects against older backups that predate the backup-side exclusions. The import summary reports which files were preserved. This is the second half of NS-501 (filed separately as NS-508): the upload 502 was fixed in NousResearch#47663; this fixes the import-breaks-the-instance half.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Infographic
Summary
This is the second half of NS-501 (filed separately as NS-508, "Agent disconnected from Nous portal after import, stuck on 'starting'"). The upload-side
502was fixed in #47663; this fixes the import-breaks-the-instance half.hermes importwrote every file from the backup zip over the target home wholesale — the only thing it refused was a path-traversal. On a hosted instance this clobberedgateway_state.jsonwith the source machine's last recorded run/desired state. The container-boot reconciler (container_boot._read_desired_state) only auto-starts a gateway whose recorded state isrunning; a backup taken from a laptop where the gateway wasstopped(or carrying a stale/foreign value) overwrote the container's own state and left the gateway stuck "starting"/"cooking", disconnected from the Nous portal.Root cause
hermes_cli/backup.py:run_import()extracted each zip member straight onto disk. The volatile runtime files that are namespaced to the machine/container the backup was taken on were restored along with everything else:gateway_state.json— drives the boot reconciler's auto-start decision. The actual NS-508 breaker.gateway.pid/cron.pid/gateway.lock/processes.json— reference PIDs and locks in the source machine's process namespace; a numerically-equal PID in the new environment is a different process.The backup creates these too (they aren't in the backup-side
_EXCLUDED_NAMES), and older backups predate any exclusion, so the correct and complete place to filter is on import.Fix
Add
_IMPORT_SKIP_NAMES = {gateway_state.json, gateway.pid, cron.pid, gateway.lock, processes.json}and skip them by basename inrun_import, so both the root profile and named profiles (profiles/<name>/gateway_state.json) keep the target's own runtime state. The import summary reports which files were preserved. This mirrors exactly whatcontainer_boot._STALE_RUNTIME_FILESalready sweeps on every container boot.No hosted detection, no lifecycle/restart machinery — a single general import-safety rule that also protects a user restoring a backup onto any live machine.
Tests (proven to fail without the fix)
Four new behavioral tests in
tests/hermes_cli/test_backup.py, each confirmed RED onmainand GREEN with the fix:test_preserves_live_gateway_state— livegateway_state.jsonwins over the backup'stest_does_not_seed_gateway_state_when_absent— a foreign state is dropped, never seededtest_preserves_per_profile_gateway_state— basename match covers named profilestest_preserves_runtime_pid_and_process_files— pid/lock/process files preservedFull module: 114 passed. Plus a real end-to-end run of the actual
hermes importCLI against a tempHERMES_HOME: the live root + profilegateway_state.jsonandgateway.pidwere preserved whileconfig.yaml,.env, skills, and profile config were restored normally.Fixes NS-508 (second half of NS-501).