Skip to content

Releases: ericwalisko/memware

memware 0.11.0

Choose a tag to compare

@ericwalisko ericwalisko released this 02 Oct 00:00
6e9473d

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 remember valid_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.

memware 0.8.0

Choose a tag to compare

@ericwalisko ericwalisko released this 24 Sep 17:22
9c2849a

Added

  • An optional relevance filter for prompt-time injection, off by default. The prompt hook and
    the Hermes provider's prefetch pick beliefs by keyword, so a prompt about an incident report
    also got a weekly report's file path. With memware config relevance.mode filter, memware asks
    TypeSafe's System One model (jev-1.13.0, pinned) one yes/no question per candidate, all in one
    request, and injects the candidates at or above relevance.threshold, at most k. shadow makes
    the same call, logs each (prompt, candidate) pair to relevance-log.jsonl for calibration, and
    injects what off does. When it is on, the prompt (up to 2,000 characters) and up to 20
    candidate facts go to api.typesafe.ai, and nothing else does. A task notification, a hook
    inside a subagent and a session memware keeps out of its store are never sent. With the filter
    off, memware reads no key, opens no socket and prints the same bytes as before. It fails open
    on a missing key, a timeout, an HTTP error, a redirect or a malformed reply, with one attempt
    under a 1.5 s deadline. With a full pool of 20 candidates the hook took 553 ms p50 and 753 ms
    p95, against 84 ms and 99 ms off. It uses the standard library only, with no new dependency.
    memware config refuses a bad relevance.* value and says what switching the filter on sends.
    memware nuke removes the log and relevance-usage.jsonl.