Provenance, tamper evidence and agent scopes
Since 03/10/2026, mem7 records which governed call wrote each memory, seals every entry in a hash chain, and can restrict what each agent reads, from identities that flux7-mesh vouches for.
What the mesh sends
When mem7 sits behind flux7-mesh as a streamable-http upstream, the mesh adds
a _meta to each tools/call:
| Key | Content | Sent |
|---|---|---|
traceparent |
W3C trace context of the governed call | always |
art.flux7/agent |
the agent the mesh authenticated | with forward_identity: true on the upstream |
Provenance
mem7 records the trace id on every write and every deletion: in the markdown
workspace (trace: in the entry's envelope), which stays the source of truth,
and in the index, rebuilt with it by mem7 rescan. memory_recall and
memory_search print it, and memory_context returns it as trace_id. Hence a memory
points back to the decision that produced it in the mesh's traces.
Hash chain (tamper evidence)
Every entry mem7 writes to the workspace (store, deletion, deletion by tags) carries the seal of the entry before it (prev:) and its own (hash:), computed over its parsed fields. Edit an entry, drop one or reorder them, and mem7 verify names the first place the chain no longer holds:
$ MEM7_CHAIN_KEY=... mem7 verify
211 entries: 78 sealed, 133 written before the chain
seals: HMAC-SHA256 with MEM7_CHAIN_KEY
chain holds
With MEM7_CHAIN_KEY the seal is an HMAC-SHA256: editing the workspace without the key leaves a break no one can reseal. Without it, a plain SHA-256 catches accidents and careless edits but does not catch a forger. The key changes only through mem7 rekey (below). Changed in the environment alone, it breaks the chain at the next entry. Entries written before the chain existed are counted but not checked, because the chain starts at the first sealed entry. The workspace stays plain markdown that you can read and edit by hand. However, such an edit now shows in the chain.
Rotating the key
$ systemctl stop mem7
$ MEM7_CHAIN_KEY=<current> MEM7_NEW_CHAIN_KEY=<new> mem7 rekey --agent <who>
chain handed to key 2f40cf03a69776de (427 entries sealed, 1 rotation(s))
rekey checks that the chain holds, then appends a rekey entry sealed with the new key over the last seal of the old one. Set MEM7_CHAIN_KEY to the new key, add the old one to MEM7_CHAIN_KEYS_RETIRED, and start the daemon. A holder of the retired key can then neither reseal the entries before the rotation (the rekey entry would no longer follow them) nor append after it, and verify requires the chain to end under the current key. Keys are named by an id derived from them and are never written. Stop the daemon first, because it keeps the chain head in memory. rekey also moves a keyless (SHA-256) chain to a key. Available since v0.9.0.
Identity
Anyone can write a _meta. mem7 therefore honours art.flux7/agent only on
a request that carried its bearer token (MEM7_TOKEN), which only the mesh
and trusted infrastructure hold. The vouched identity replaces the agent
argument the caller declared. Without a token, the trace id is still recorded
but no request can speak for an agent.
Scopes
A scopes file (MEM7_SCOPES or --scopes, JSON) restricts identified agents:
| Caller | Reads | Writes and forgets |
|---|---|---|
| identified agent | its own memories, plus the owners listed under read (glob patterns) |
its own keys only; no forget by tags; no memory_get (raw workspace) |
| administrator | everything | everything |
| token, no agent (supervisor, console, the mesh's decision writer) | everything | everything |
Without a scopes file, identities still sign the writes and reads stay open.
Wiring
# flux7-mesh
memory:
url: http://localhost:9070
token: "${MEM7_TOKEN}"
mcp_servers:
- name: memory
transport: streamable-http
url: http://localhost:9070/mcp
forward_identity: true
headers:
Authorization: "Bearer ${MEM7_TOKEN}"
Every direct client then needs the token: the supervisor reads MEM7_TOKEN
from its environment when memory.token is empty, and the console reads it from
its environment file. contrib/systemd/enable-token.sh in flux7-memory wires
the token and the scopes into the systemd units of a single machine.
Tool pinning
The change adds an agent property to memory_forget. A mesh with tool
pinning on holds the tool until the new definition is accepted on the
console's Tools page: the protection against a silently changed tool works
as intended.