Repository navigation
Releases: churnast/hermes-memory-shield
Release list
Memory Shield v1.1.2
Fixed
- A call that refers to a memory alias so often that following it would add more than 16,384 characters is now judged as a direct edit of the owner's profile, which the default policy refuses. In 1.1.1 the substitution stopped silently, so
F=~/.hermes/memories/USER.md, thenecho $F700 times, thenecho pwned > $F(5.6 KB) passed, and so did the Python form withopen(p, 'r')700 times beforeopen(p, 'w'); 1.1.0 refused both. - The check for a call longer than 16,384 characters ignores case, quotes and backslashes: it looks for the word
memories,USER.mdorMEMORY.mdafter dropping",'and\, somem"ori"es/US"ER".md,mem\ories/US\ER.mdandMEMORIES/user.mdpadded past the cap are refused again, as in 1.1.0. Such a call is charged to the agent's notes only whenMEMORY.mdis the only word found. - A shell call that mixes memory aliases with
xargs rmreads its words once after the last command instead of once per new alias: an alternation of the two under 16 KB took 0.66 to 1.16 s on a Mac and now takes about 12 to 20 ms. - The pattern for
open(path, mode)no longer retries a long run of spaces at every split:open(afollowed by 16,370 spaces took about 280 ms, andopen(followed by 2,000 spaces about 2.9 s (16,370 did not finish in 20 s), in bothexecute_codeandterminal. Both now take about 3 ms. The verdicts are the same. - Timing tests now cover payloads just under the cap, where the scanner actually runs, as well as past it, and new tests cover the alias budget in shell and Python and the case, quote and backslash forms past the cap.
Changed
- The README says what the check past the cap looks for (the word
memories,USER.mdorMEMORY.md, any case, quotes ignored), gives the cap as 16,384 characters, and says that a snapshot, the audit log or a restored memory file that did not exist before is created with mode 0600, while an existing one keeps its permissions.
Memory Shield v1.1.1
Fixed
- The
pre_tool_callhook now has a bound on its time and memory use forterminalandexecute_codecalls, after a review of the plugin for the Hermes catalog. A call is read up to 16 KB; a longer one is judged without being read: it is refused when it mentionsUSER.md,MEMORY.mdor the memories folder (with a hint to split it up or keep the memory files out of it) and let through when it mentions none of them. Before, a one-line call of.hermes.unlink(repeated 2000 times (30 KB) kept the hook busy for about two minutes, because the memory path was looked for once per.unlink(or.write_text(in a statement; it is now looked for once per statement. - Shell variables and Python names assigned a memory path are substituted in one pass, a name whose value refers to another such name is not kept, and the substitution stops once it has added more than 16 KB to the call. Before, about thirty chained lines like
a1 = '.hermes/memories' + a2 + a2doubled the text at every step until memory ran out. - The two regular expressions that looked for the memories folder behind the Hermes home no longer rescan the rest of the line for every mention of the home.
- Snapshots, the audit log and a restored memory file are written through a temporary file with a unique name in the same folder (
tempfile.mkstemp) instead of a fixed.tmpneighbour, so two writers can never share one; a file that already exists keeps its permissions.
Memory Shield v1.1.0
Added
- A new level for the owner's profile,
owner_edits, now the default: the agent may add facts wherever it may write and may replace one only when the owner asks in a direct chat, the CLI or a chat intrusted_chats(and, oncetrusted_usersis set, only for a person listed there); nobody may delete one, and a replace with empty or placeholder text still counts as a delete. In a group, a scheduled job or the background review it behaves likeappend_only.append_onlystays available for owners who want nothing changed by the agent at all. - Hermes' unattended self-improvement review, the fork that tidies memory and skills after a conversation with nobody watching, may not add to, change or delete the owner's profile unless
user_profileisoff. The plugin reads Hermes' own marker for that fork (tools.skill_provenance.is_unattended_review), which reachespre_tool_callhooks under the defaultplugins.isolation: in_process; a review the owner starts with/refineis attended and keeps the direct-chat rules. The agent's own notes keep their level there, where Hermes itself holds deletions for approval.
Changed
trusted_usersnow applies to direct chats too: once it is set, a direct chat with someone not listed is judged like a shared chat (read-only by default,group_chatsdecides), andmode: approveblocks there instead of asking. A session without a user id, such as the CLI, still counts as the owner. Withtrusted_usersempty nothing changes./memory-shieldand/memory-shield whoamisay so.- The policy hints name the new rules: a replace outside the owner's direct chat says that facts about the owner are changed only when the owner asks in a direct chat; a refused delete of a fact about the owner says that facts are never deleted and that placeholder text counts as deleting.
Fixed
- Shell and Python side-door detection no longer refuses commands that only read a memory file or write somewhere else. Before, any command that mentioned a memory file together with any writing word was refused, so
cat ~/.hermes/memories/USER.md > /tmp/copy.md,cp ~/.hermes/memories/USER.md /tmp/xandgrep ... USER.md > elsewherewere blocked. Now the plugin reads the call command by command and counts only a write whose target isUSER.md,MEMORY.mdor the memory folder: a redirection,tee,cp,install,rsync,lnordd of=into it,sed -iorperl -ion it,rm,mv,truncate,shredorfind -deleteof it, and in Pythonopen(..., "w"/"a"/"x"/"+"),write_text,write_bytes,unlink,os.remove,shutil.move,shutil.rmtreeandshutil.copywith it as the destination. Simple shell variables,cdinto the memory folder and Python names assigned a memory path in the same call are followed, and quoted strings are read as shell text once, forpython -c,subprocessandos.system.
Memory Shield v1.0.1
Fixed
/memory-shield logfollows the same rule as/memory-shield restore: it answers only in a direct chat, the CLI or a chat intrusted_chats, and whentrusted_usersis set, only the people listed there; a session without a user id, such as the CLI, counts as the owner. Before, anyone who could message the agent directly could read up to 50 events from every chat, with excerpts from the owner's own chats (for a deletion, words from the memory entry itself), even withtrusted_usersset. Someone not listed there gets a refusal that says where the command works and who may run it, andrestorenow gives the same one./memory-shield snapshotsis unchanged: it shows times, stores and sizes, no memory text.
Memory Shield v1.0.0
The first stable release. What the plugin does as of this release is listed under Added and the two fixes since 0.1.4 under Fixed; the README, its banner, a catalog card and a short demo video are new.
Added
- A policy for Hermes' built-in
memorytool through onepre_tool_callhook, per store: the owner's profile (USER.md, settinguser_profile) is append-only, and the agent's own notes (MEMORY.md, settingagent_notes) can be added to and updated but not deleted. Levelsoff,no_delete,append_onlyandread_only; a batch is checked operation by operation. - Shared chats (groups, channels, forum topics, guild threads, webhook runs) are read-only (
group_chats), except for the people intrusted_users(ids asplatform:id) and the owner-only chats intrusted_chats, which are judged like a direct chat.scheduled_jobsadds an extra limit in cron runs; it is off by default. - Modes:
blockrefuses with a hint the model can act on,approveasks through Hermes' approval prompt in direct chats (with a key for that exact call) and blocks elsewhere,observeallows the call and logs it. - Replacing an entry with empty or placeholder text ("n/a", "[deleted]", and placeholder words in Russian, Spanish, Portuguese, German and French) counts as removing it.
- Direct edits of
USER.mdandMEMORY.mdthroughwrite_file,patch,terminalandexecute_code, and shell commands that wipe or move the whole memory folder, are judged as an add, a replace and a remove at once. - A snapshot of the memory file right before an edit or deletion goes through: 20 per file by default, at most 200,
snapshots: 0turns them off./memory-shield snapshotslists them, and/memory-shield restore <n>puts one back in a direct chat or a chat intrusted_chats, after saving the current file. - An audit log of refused and flagged writes (the last 500, each with a 160-character excerpt;
audit_log: falseturns it off), shown by/memory-shield log [n]in a direct chat, the CLI or a chat intrusted_chats./memory-shieldshows the policy and how many events and snapshots are kept;/memory-shield whoamishows the user id and, in a shared chat, the chat key. - A card for the Hermes plugin catalog,
docs/card.png(1200x600): in a group, a stranger asks the agent to forget everything about its owner, the agent's notes stay, and the shield sits on the chat.docs/banner.pngstays the README banner. - The README shows a short demo (
docs/demo.webp, also asdocs/demo.mp4, 20 seconds), re-drawn from a local test run with fictional people, in two scenes: in the group "Friends", Sam asks the agent to remember "Alex owes me $100" and it refuses; in a direct chat, the owner, Alex, asks it to forget everything, and it refuses and offers a dated note. Under What you get, five screenshots fromdocs/screenshots.
Changed
- The README follows the layout of Telegram Stickers: badges in one style, a one-line introduction to Hermes Agent, a Quick start (install and restart,
/memory-shieldto check,trusted_usersfor groups), What you get, the commands, Configuration, the comparison withmemory.write_approval, Privacy and safety, Known limitations and Troubleshooting as a list. Known limitations is new: groups where the gateway does not pass the message author to plugins (trusted_chatscovers an owner-only one), memory provider plugins, best-effort file and shell detection, facts about the owner that only the owner can fix by default, andapprovedepending on Hermes' approvals. Privacy and safety now also say who can run which subcommand and that the plugin holds the memory store's lock file while it reads or writes a memory file. - The README banner is redrawn as a mini chat, like the Telegram Stickers banner: in a group, Sam tries to plant a claim about the owner, Alex, then to wipe what the agent knows, and the agent's notes stay. It drops its pills and uses larger text so it reads in small link previews.
Fixed
/memory-shield loganswers only in a direct chat, the CLI or a chat intrusted_chats, like/memory-shield restore, and in any other chat says where to run it. Before, it worked in any chat, so whoever could run the agent's slash commands in a group could read up to 50 events from every chat, with excerpts from the owner's direct chats (for a deletion, words from the memory entry itself)./memory-shield snapshotsstill works in any chat: it shows times, stores and sizes, no memory text.- A level set to
offwithhermes config setor as an unquotedoffinconfig.yamlis stored as YAMLfalse; the plugin now reads that asoffinstead of silently keeping the default. This applies touser_profile,agent_notes,group_chatsandscheduled_jobs.
Memory Shield v0.1.4
The scheduled_jobs setting now appears in the Hermes Desktop settings form (it was missing from the plugin settings list), the trusted_users hint asks for platform:id ids, and the README explains how to update, switch off and remove the plugin.
hermes plugins update memory-shieldMemory Shield v0.1.3
New trusted_chats setting: a chat that only you and the agent are in (for example a private Telegram group with topics) is judged like a direct chat. In Telegram groups that Hermes observes (observe_unmentioned_group_messages), the sender is not passed to plugins, so trusted_users cannot match there and every memory write from such a group was blocked, even yours. /memory-shield whoami now shows the chat key to add. Also fixed: platform:id entries whose id contains colons (Matrix) now match.
hermes plugins update memory-shieldMemory Shield v0.1.2
Placeholder words in Russian and a few other languages ("удалено", "нет", "неактуально", "gelöscht") now count as deleting an entry, like "deleted" and "n/a" already did.
hermes plugins update memory-shieldMemory Shield v0.1.1
Shell commands that wipe or move the whole memory folder without naming a file (rm -rf ~/.hermes/memories, find ... -delete, shutil.rmtree) are now caught like direct edits of USER.md and MEMORY.md.
hermes plugins update memory-shieldMemory Shield v0.1.0
First public release.
Install
hermes plugins install churnast/hermes-memory-shield --enableAdded
- Policy for the built-in
memorytool through apre_tool_callhook: owner profile append-only, agent notes without deletion, shared chats read-only; levelsoff,no_delete,append_only,read_only. - Modes
block(refuse with a hint the model can act on),approve(Hermes' approval prompt, direct chats only) andobserve(log only). - Replacing an entry with empty or placeholder text counts as removing it.
- Direct edits of
USER.mdandMEMORY.mdthroughwrite_file,patch,terminalandexecute_codeare judged like the memory tool. trusted_userswho may write memory from shared chats, and ascheduled_jobslevel for cron runs.- Snapshots of the memory file before every allowed edit or deletion, with
/memory-shield restore. - Audit log of refused and flagged writes, shown by
/memory-shield log;/memory-shield whoami.
Requires Hermes Agent 0.21.5 or newer. Settings, commands and the privacy section are in the README.