hermes - 💡(How to fix) Fix [Feature]: Deterministic persistence of self-edits via source-watcher daemon + lint safety gate.

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Root Cause

Default-on or opt-in? Lean opt-in via env var (HERMES_WATCHER_ENABLED=1) so existing users aren’t surprised. GitHub credential scope — full repo write feels too broad, but push-to-feature-branch-with-required-PR-reviews breaks the “restart picks up the new code” recovery model. Worth discussing. Notifications — we use Telegram because we run on Railway with Telegram as the home channel. Upstream probably wants something more generic (or the notify hook left as a no-op the operator wires up themselves). Test infrastructure — does the upstream test suite have patterns for daemons that fork subprocess + git? We’d want to add coverage for the commit/lint/recovery cycles.

RAW_BUFFERClick to expand / collapse

Problem or Use Case

Hermes already supports autonomous skill creation, agent-curated memory, and skills that self-improve during use — all documented selling points. But these self-modifications live on the persistent volume only. The next container restart, image rebuild, volume swap, or local checkout reset wipes them. The bot’s “deepening model of who you are across sessions” survives, but the procedural skills the bot wrote about itself don’t — unless the operator manually git adds them.

For users running Hermes long-term on a server, the closed learning loop has a leak: the bot can teach itself a new skill at 3pm, the operator restarts at 4pm to pick up an unrelated change, and the new skill is gone. The reasoning that produced it is in session history, but the actionable artifact isn’t preserved.

Proposed Solution

A small daemon (scripts/source_watcher.py, ~545 lines) that polls the repo on the persistent volume every 10s. When git status --porcelain shows uncommitted changes, it starts a 180s debounce timer. When the timer expires (or hits a 600s ceiling for files in active flux), it runs git add -A, commits with auto: <ts><files> as the message, and pushes to origin. The Hermes container’s entrypoint symlinks /opt/hermes/{scripts,tools,gateway,skills} to the same git checkout, so a restart picks up the new code from origin/main without a full image rebuild.

Result: the bot can author a new skill in chat, the watcher commits it to GitHub within 3 minutes, and any container restart anywhere recovers the skill without operator intervention.

Mandatory pairing — the safety gate: A self-modifying agent without static checks is a self-bricking agent. We discovered this firsthand when our running Hermes silently auto-committed _resolved_model = getattr(agent, "model", None) referencing a variable that doesn’t exist in scope. Python imports succeeded; the NameError fired only at runtime on the message-handling code path. The bot booted fine, then crashed every Telegram message until manual fix.

The fix is a pre-commit gate inside source_watcher.py that runs ruff check --select F821 --no-fix <staged_python_files> before every commit. F821 (undefined name) catches exactly this class of bug, in <100ms per file. On failure: skip the commit, append context to a blocked log, send a notification, leave the working tree dirty so the bot can fix on its next turn. Notifications are deduplicated by (file_set, ruff_output) hash so a broken file sitting overnight doesn’t flood. Without this gate, the watcher is a “ship your own bug to production” pipeline.

Reference implementation in the personal fork at rousegordon-ops/hermes-agent:

scripts/source_watcher.py — daemon (poll/debounce/commit/push, lint gate, dedup, secret-leak scan, bucket-aware push notifications) docker/entrypoint.sh (lines 120-235) — spawns the watcher, writes git credentials, sets up symlinks The lint gate itself was authored by Hermes in commit 740f66d3 after one round of operator feedback — proof point that the bot can use the tool to make itself safer to use the tool Open design questions:

Default-on or opt-in? Lean opt-in via env var (HERMES_WATCHER_ENABLED=1) so existing users aren’t surprised. GitHub credential scope — full repo write feels too broad, but push-to-feature-branch-with-required-PR-reviews breaks the “restart picks up the new code” recovery model. Worth discussing. Notifications — we use Telegram because we run on Railway with Telegram as the home channel. Upstream probably wants something more generic (or the notify hook left as a no-op the operator wires up themselves). Test infrastructure — does the upstream test suite have patterns for daemons that fork subprocess + git? We’d want to add coverage for the commit/lint/recovery cycles.

Alternatives Considered

Prompt the LLM to commit its own changes. Add a system-prompt rule telling Hermes to git commit after every skill edit. Zero infrastructure. But LLMs are unreliable at procedural rules over long sessions — they forget, skip, batch incorrectly, or write commit messages that don't capture intent. The whole point of a daemon is to take the LLM out of the reliability path for an operation that has to be deterministic.

Manual operator commits per skill change. What we did before this. Doesn’t scale — the bot creates skills frequently, operator has to babysit. Defeats the autonomy story. Image rebuild on every change. Persists changes, but it takes ~10 min per change consumes compute unnecessarily.

No persistence (current upstream). Ships, but the documented “self-improvement” features don’t survive restart in any environment with a fresh container per deploy. Honcho memory survives; procedural artifacts don’t.

A separate “skill snapshot” tool the operator runs manually. Simpler than a watcher but requires discipline. Still misses the “bot fixes its own bug at 3am” use case.

Feature Type

Other

Scope

Large (new module or significant refactor)

Contribution

  • I'd like to implement this myself and submit a PR

Debug Report (optional)

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING