Skip to content

feat(scripts): add local-patch-recovery infrastructure for source-tree customizations - #36794

Closed
VIPKaiser wants to merge 1 commit into
NousResearch:mainfrom
VIPKaiser:feat/local-patch-recovery-hooks
Closed

VIPKaiser wants to merge 1 commit into
NousResearch:mainfrom
VIPKaiser:feat/local-patch-recovery-hooks

Conversation

@VIPKaiser

Copy link
Copy Markdown

Problem

If a user applies a local source-tree patch to /usr/local/lib/hermes-agent/ (e.g. to fix a bug, optimize a workflow, or work around an unmerged PR), the first hermes update will silently revert that patch with no warning. hermes update runs git pull --ff-only on the managed checkout, and uncommitted modifications to tracked files are overwritten.

This is invisible until something breaks. There is no built-in way to:

  • Detect that a local patch has been reverted
  • Re-apply it automatically
  • Audit which local patches were ever applied to a given install

Solution

A small, opt-in toolkit that ships as ordinary files under scripts/:

  1. **scripts/local-patch-recovery-hook.sh** — a git post-merge hook template. When installed into .git/hooks/post-merge, it runs after every successful git pull / git merge (including the git-based path of hermes update). It detects when a tracked local patch has been reverted by checking a canary function in the source, then re-applies the fix using:

    • git cherry-pick --3way of the commit SHA listed in ~/.hermes/patches/manifest.txt (preferred — survives context line drift from rebases)
    • git apply --3way on a .patch file in ~/.hermes/patches/ as a legacy fallback
  2. **scripts/hermes-preupdate.sh** — a read-only preflight check you run before any hermes update. Snapshots the current git state and local patches to ~/.hermes/state-snapshots/<timestamp>-pre-update/, verifies the hook is installed, verifies the canary is currently applied, and reminds you to run a backup if the last one is older than 14 days.

  3. **scripts/install-local-patch-hooks.sh** — one-shot installer. Copies the hook + scripts to ~/.hermes/bin/, installs the git hook, creates the manifest placeholder, and supports --check / --uninstall.

  4. **scripts/local-patches-README.md** — the README that gets installed to ~/.hermes/patches/README.md explaining the format and recovery procedure.

Use case: PR #36779

PR #36779 is a fix for the minimax-oauth auxiliary routing bug — the kind of patch a user might apply locally while waiting for the PR to merge. Once it does merge, the local patch becomes redundant; until then, the user needs it to survive updates. This toolkit is the mechanism that makes that work without operator action.

Design choices

  • Opt-in: nothing is installed until the user runs the install script. The default Hermes install is unaffected.
  • Read-only on source: the hook only writes to ~/.hermes/ and the local .git/hooks/ directory. The source checkout is never modified by the install script itself.
  • Idempotent: install-local-patch-hooks.sh can be run multiple times safely. --check is intended for cron / monitoring.
  • Two-stage recovery: commit-hash cherry-pick (preferred) handles context-line drift; raw git apply is a fallback for legacy patches without a recorded SHA.
  • No new dependencies: pure bash + git. No new Python imports, no new pip packages, no changes to pyproject.toml.

Verification

The author has installed this on a production server and tested the full failure recovery:

  1. git checkout main -- agent/auxiliary_client.py (simulating an upstream revert) → canary count drops to 0
  2. .git/hooks/post-merge fires automatically
  3. git apply --3way re-applies the patch from ~/.hermes/patches/ → canary count back to 2
  4. Warning printed to operator's terminal with PR link and recovery instructions
  5. hermes-preupdate.sh --check confirms: hook installed, patch applied, canary present

Files

  • scripts/local-patch-recovery-hook.sh (new, 7.3 KB)
  • scripts/hermes-preupdate.sh (new, 6.0 KB)
  • scripts/install-local-patch-hooks.sh (new, 4.9 KB)
  • scripts/local-patches-README.md (new, 3.0 KB)

Total: +21 KB across 4 new files. No existing files modified.

…e customizations

Adds a complete local-patch-recovery toolkit for users who maintain
source-tree customizations to /usr/local/lib/hermes-agent/ (e.g. local
bug fixes, performance patches, or workarounds for unmerged PRs).

The kit:

1. scripts/local-patch-recovery-hook.sh — a git post-merge hook
   template. When installed into .git/hooks/post-merge, it runs after
   every successful git pull / git merge (including the git-based path
   of `hermes update`). It detects when a tracked local patch has been
   reverted by checking a canary function in the source, then
   re-applies the fix using:
     a) git cherry-pick --3way of the commit SHA listed in
        ~/.hermes/patches/manifest.txt (preferred — survives context
        line drift from rebases)
     b) git apply --3way on a .patch file in ~/.hermes/patches/ as a
        legacy fallback

2. scripts/hermes-preupdate.sh — a read-only preflight check you run
   before any `hermes update`. Snapshots the current git state and
   local patches to ~/.hermes/state-snapshots/<timestamp>-pre-update/,
   verifies the hook is installed, verifies the canary is currently
   applied, and reminds you to run a backup if the last one is older
   than 14 days.

3. scripts/install-local-patch-hooks.sh — one-shot installer. Copies
   the hook + scripts to ~/.hermes/bin/, installs the git hook, creates
   the manifest placeholder, and supports --check / --uninstall.

4. scripts/local-patches-README.md — the README that gets installed to
   ~/.hermes/patches/README.md explaining the format and recovery
   procedure.

Use case: today, any local source patch is silently reverted by the
first `hermes update`. This makes that visible and recoverable
without operator action. Triggered by PR NousResearch#36779 which is the first
known local patch on this server; future local patches can be added
by appending a line to ~/.hermes/patches/manifest.txt.

The hook is opt-in: nothing is installed until the user runs the
install script. The default Hermes install is unaffected.
@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have labels Jun 1, 2026

@mxnstrexgl mxnstrexgl left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Automated PR Review

Security Scan

  • ✓ No hardcoded secrets, injection sinks, unsafe deserialization, or dependency red flags found by this automated scan.

Code Quality

  • ✓ No blocking code-quality issues found by this automated scan.
  • ℹ️ No test file changes detected; verify existing coverage exercises this behavior.

Summary

Status: APPROVE — security findings: 0, quality suggestions: 0.

Automated review; raw diff content intentionally omitted.

@teknium1

Copy link
Copy Markdown
Collaborator

Thanks for the recovery tooling work. This is an automated hermes-sweeper review; current main already provides the underlying protection this PR targets.

  • hermes_cli/main.py:6454-6497 detects local changes and saves both tracked and untracked files with git stash push --include-untracked before an update.
  • hermes_cli/main.py:9870-9894 restores that stash after a successful update by default; hermes_cli/main.py:6574-6604 retains it for manual recovery if restoration conflicts.
  • The behavior is covered in tests/hermes_cli/test_update_autostash.py:59-81 and documented at website/docs/reference/cli-commands.md:1563.

Because local source-tree patches are no longer silently overwritten by hermes update, the recovery-hook infrastructure is redundant on current main.

@teknium1 teknium1 closed this Jul 13, 2026
@teknium1 teknium1 added the sweeper:implemented-on-main Sweeper: behavior already present on current main label Jul 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P3 Low — cosmetic, nice to have sweeper:implemented-on-main Sweeper: behavior already present on current main type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants