You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This commit was created on GitHub.com and signed with GitHub’s verified signature.
Upgrade notes
Your store is tightened to 0600, and the memware home to 0700, on the next command that opens
it. This is automatic and needs nothing from you. Check it with ls -la ~/.memware. A
directory you named with MEMWARE_DB or backup.dest is left alone. Windows has no file
modes; see the README's Windows section.
memware stats has a new reason under "beliefs left out of injection": instruction. It
counts beliefs that read as an order to the agent rather than a fact. Each stays in the ledger
and in recall; it is only kept out of injection. memware beliefs --stale lists them. A store
that held such a belief before this release shows a non-zero count the first time.
The Claude Code plugin changes with this release (the SessionEnd fix below). Run claude plugin marketplace update memware and claude plugin update memware@memware;
RELEASING.md has the full deploy steps.
The Claude Code plugin's prompt hook no longer passes -k 6. It reads the new inject.k
setting instead, which defaults to the same 6, so nothing changes unless you set it. The plugin
also ships a garden skill (/memware:garden).
With the relevance filter on, the log trims itself. The first logged prompt after upgrading
strips the prompt and fact text from relevance-log.jsonl lines older than 30 days and deletes
lines older than 180 (relevance.log_text_days, relevance.log_days). Copy the file first if
you want the old text.
Added
inject.k sets how many beliefs the prompt hook injects per prompt (default 6, 1 to 20).
The Claude Code plugin's hook passed -k 6, so the cap could only change by editing an
installed plugin. The hook now omits -k, and memware context reads inject.k when it isn't
given. memware config inject.k refuses anything outside 1 to 20. The Hermes provider keeps
its own prefetch_k.
A garden skill in the Claude Code plugin (/memware:garden) measures and tunes what the
prompt hook injects, then tends the belief ledger. The 0.10.0 calibration was a one-off, and
it only labeled facts memware's own subject rule picked. Nothing checked the facts the relevance
filter adds from lower in the pool, or the candidates it passes over. On one user's 204 prompts
where the filter added a fact, three blind passes labeled 1,781 pairs. The added facts were 35%
relevant, about the same as the picks the filter kept (37%). The picks it dropped were 1%
relevant. With the filter, the block went from 147 relevant facts in 1,224 to 334 in 925.
Facts scored 0.2–0.3 were almost all noise, which is why that ledger's threshold moved to 0.3.
A second cycle measured misses for the first time: of 221 candidates the filter passed over, 8
were relevant.
Measuring:skills/garden/garden.py (standard library only) reports the filter's health
from its logs: fallbacks, latency, cost, block size and cap-bound prompts. It samples blind
labeling batches, including candidates the filter passed over, so misses are measured too.
It turns two labeling passes, plus a third on their disagreements, into verdicts.
Tuning: the log keeps the filter's score for every candidate in the pool, so past
prompts can be replayed under any threshold, k and pool up to the logged size. The report
searches that grid for the least noise that keeps at least 99% of the relevant facts the
current settings inject. It chooses on older prompts and moves only if the newest cycle's
held-out prompts agree, and then only as far as the smallest step that improves. Several
settings can move in one cycle. On synthetic scores it reaches the optimum in five cycles.
Once nothing else moves, it proposes a pool 10 wider for one cycle when the deepest logged
ranks still hold relevant facts. The timeout rises above a 2% timeout rate. The filter goes
back to shadow when it stops beating memware's own picks.
Where it writes: verdicts (pair ids only) and one line of numbers per cycle go to <home>/labels/garden/, so memware nuke removes them and the next cycle labels only new
pairs. It never prints a prompt or a fact. The batches that hold them are owner-only and
deleted after scoring.
Gardening the ledger: the skill proposes a fix for each belief shown at least 5 times
and at least 80% noise, such as a sharper subject, a retraction, or keeping it. It reviews
stale, orphaned and contested beliefs, and every fourth cycle it looks for duplicates,
contradictions and subjects that will misfire. It changes nothing without the user's yes.
python -m memware runs the CLI, the same entry point as the memware script. It used to
fail with No module named memware.__main__. python -m memware.cli still works.
memware runs on native Windows. CI now runs the whole suite on Windows beside Ubuntu and
macOS, on Python 3.11-3.13, and the README has a Windows section (install, where things live,
known limits). On Windows the capture lock uses msvcrt.locking, the derive run lock probes a live process without terminating it, pipes are
read and written as UTF-8, transcript directories match regardless of case, and derive --provider claude-code refuses an npm claude.cmd, because a batch file would pass
transcript text through cmd.exe; it needs the native claude.exe or --provider openai.
Changed
The relevance log keeps prompt text for 30 days, not forever. With the relevance filter in shadow or filter mode, relevance-log.jsonl gained one line per candidate per prompt, each
with the prompt's text, and nothing ever removed one. One user's log reached 15 MB in six days.
Now, at most once a day, the next logged prompt strips prompt and fact from lines older
than relevance.log_text_days (30) and deletes lines older than relevance.log_days (180),
and a line that will not parse. A stripped line keeps its scores and ids, so labeled pairs can
still be replayed. Both settings take 1 to 3650 days. memware nuke removes the trim's stamp
file too.
memware.cli is now a package with one module per command (memware.cli.recall, memware.cli.prune, ...). Behaviour, --help text and the memware = memware.cli:main entry
point are unchanged; tests/test_cli_help.py pins every command's --help byte for byte.
Security
Hardening from a security review; docs/security.md has the threat model.
The store, its write-ahead log, snapshots, a restored store, transcript mirror copies, config.json and the review outbox are created 0600. Directories memware creates are 0700.
An existing store is tightened to 0600 on its next open, and the memware home to 0700 when
the store is in it. A directory you named with MEMWARE_DB or backup.dest is left alone.
The injection gate leaves out a belief that reads as an order to the agent rather than a
fact, whoever wrote it. memware derive no longer files one. Such a belief stays in the
ledger and recall, marked volatile: "instruction", and memware stats counts it. Each
injected line is rendered as one line of plain text.
The MCP tools bound their arguments: at most 16 recall phrasings, k within 1–50, a read_session window within 0–50, and a remembervalid_from that must be a real ISO-8601
time, not in the future.
Keywords longer than 128 characters are left out of search queries.
memware prune redaction now finds a secret in a belief in its decomposed, fullwidth or
percent-encoded form, or with an invisible character inside it. Its six-character minimum
counts visible characters.
Fixed
The relevance log and usage log are created 0600, like the store. Both were opened with a
plain append and created 0644, so other local accounts could read prompt text whenever the
home directory was not 0700. Each write
now creates the file 0600, and a log written before this release is tightened on its next write.
The staleness gate now leaves out three point-in-time readings it called durable: a count of
cards, tickets, issues or PRs (open card count | 305, blocked cards | 3); a "current" PR,
issue, ticket or card that names the one in flight (current pr | PR #18) or a branch in use;
and the state of a checkout, worktree or clone that reads as a working tree (state | dirty and 8 behind, 39 files modified). Targets, limits, configured states and policies stay durable
(max open cards | 50, feature flag | state | enabled by default). memware beliefs --explain
names the rule that fired.
The plugin's SessionEnd sync now receives the hook payload. It was backgrounded with nohup … &, and a POSIX shell points a backgrounded command's stdin at /dev/null, so the sync
read {} and printed "nothing to sync"; the session was indexed only by the next SessionStart
catch-up. The entry now saves the hook's stdin on fd 3 and hands it back to the sync
(exec 3<&0; nohup memware sync … <&3 3<&- … &), which works in sh and in Git Bash alike.